Skip to content

Instantly share code, notes, and snippets.

@kenichi-odo
Last active October 4, 2016 05:09
Show Gist options
  • Save kenichi-odo/7435c1eb245ee007aa1aa0626ed56c3c to your computer and use it in GitHub Desktop.
Save kenichi-odo/7435c1eb245ee007aa1aa0626ed56c3c to your computer and use it in GitHub Desktop.
ReactをES2015で書いてVisualforce上で動かす ref: http://qiita.com/kenichi_odo/items/3f19522eaa82eb44115c
cd deploy_salesforce_using_gulp_webpack-2.0
sudo npm i
gulp
// Force.comのログインユーザ名とパスワードの設定
process.env.SF_USERNAME = 'xxx@xxx.xxx';
process.env.SF_PASSWORD = 'xxxxxxxx';
// moduleのロード
import gulp from 'gulp';
import file from 'gulp-file';
import { exec } from 'child_process';
import webpack from 'webpack-stream';
import zip from 'gulp-zip';
import deploy from 'gulp-jsforce-deploy';
import metadata from 'salesforce-metadata-xml-builder';
import os from 'os';
import precss from 'precss';
// ターミナルからgulpを実行した時の処理
gulp.task('default', () => {
// original配下のファイルを監視する
gulp.watch('./original/**/*').on('change', event => {
// Windows or Macのファイル区切り文字
const split_str = os.type().toString().match('Windows') !== null ? '\\' : '/';
// デプロイ時の静的リソース名
// ファイル更新した際の属するフォルダ名(original直下のフォルダ名)を設定
let resource_name = null;
// デプロイ時のパス設定
const paths = [];
let end_flg = false;
for (const path of event.path.split(split_str)) {
if (end_flg) {
paths.push(path);
resource_name = path;
break;
}
if (path === 'original') {
end_flg = true;
}
paths.push(path);
}
// 静的リソースのメタデータ作成
const resource_meta_xml = metadata.StaticResource({
cacheControl: 'Public',
contentType: 'application/zip',
});
// デプロイ用package.xmlの作成
const package_xml = metadata.Package({
types: [
{ name: 'StaticResource', members: [resource_name] },
],
version: '35.0',
});
// ビルドするmain.js
const entry = `${paths.join(split_str)}/main.js`;
// ビルド開始をMacの通知センターに流す
exec(`echo 'display notification "ビルド開始: ${resource_name}" with title "gulp" subtitle "webpack" ' | osascript`);
// webpackのビルド
gulp.src(entry)
.pipe(webpack({
entry,
output: {
filename: 'bundle.js',
libraryTarget: 'umd', // ライブラリとして出力
library: `${resource_name}`, // windowにフォルダ名で書きだして呼び出せるようにする
},
devtool: 'inline-source-map', // ビルドしたjsをデバッグできるようにsource mapをインラインで埋め込み
module: {
loaders: [
{
test: /(\.js)$/,
loaders: ['babel'],
exclude: /node_modules/,
},
{
test: /\.sass$/,
loaders: ['style', 'css', 'postcss?parser=sugarss'],
},
],
},
postcss: [precss],
}))
.on('error', () => {
// webpackのビルドでエラー時、デプロイせずエラーを通知
exec(`echo 'display notification "ビルドエラー: ${resource_name}" with title "gulp" subtitle "webpack" ' | osascript`);
})
.pipe(gulp.dest(`./build/${resource_name}`)) // webpackでビルドしたbundle.jsをbuildフォルダに格納
.on('finish', () => {
// ビルドの終了を通知
exec(`echo \'display notification "ビルド終了: ${resource_name}" with title "gulp" subtitle "webpack" ' | osascript`);
// zip圧縮→デプロイ
gulp.src(`./build/${resource_name}/*`)
.pipe(zip(`${resource_name}.resource`))
.pipe(file(`${resource_name}.resource-meta.xml`, resource_meta_xml))
.pipe(gulp.dest('./src/staticresources'))
.on('finish', () => {
// zip圧縮が完了したらデプロイ開始通知
exec(
`echo 'display notification "デプロイ開始: ${resource_name}.resource" with title "gulp" subtitle "Salesforce" ' | osascript`
);
// デプロイ処理
gulp.src('./src/**', { base: '.' })
.pipe(file('src/package.xml', package_xml))
.pipe(zip('pkg.zip'))
.pipe(deploy({
username: process.env.SF_USERNAME,
password: process.env.SF_PASSWORD,
loginUrl: 'https://test.salesforce.com',
}))
.on('finish', () => {
// デプロイが完了したら通知を流す
exec(
`echo 'display notification "デプロイ完了: ${resource_name}.resource" with title "gulp" subtitle "Salesforce" ' | osascript`
);
});
});
});
});
});
import './style/main.sass';
import $ from 'jquery';
import React from 'react';
import ReactDom from 'react-dom';
import SampleComponent from './react/sample-component';
export class Main {
constructor(name_) {
this._name = name_;
this._$sample_component_div = $('<div />');
$('#contents_area').append(this._$sample_component_div);
}
load() {
const items = [{
id: '001',
name: 'hoge',
}, {
id: '002',
name: 'fuga',
}];
ReactDom.render(<SampleComponent items={ items } />, this._$sample_component_div.get(0));
alert(this._name);
}
}
$red: #f00
.hoge-style
background: $red
{
"devDependencies": {
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.9.0",
"babel-preset-react": "^6.5.0",
"babel-register": "^6.9.0",
},
"babel": {
"presets": [
"es2015",
"react"
],
"compact": false
}
}
import React from 'react';
import Classname from 'classnames';
export default class SampleComponent extends React.Component {
constructor(props_) {
super(props_);
this.state = props_;
}
componentWillReceiveProps(props_) {
this.setState(props_);
}
render() {
if (this.state.items.length === 0) {
return null;
}
return (
<div style={ { display: 'table' } }>
{
this.state.items.map(item_ => {
return (
<div key={ item_.id } style={ { display: 'table-row' } }>
<div className={ Classname({ 'hoge-style': item_.name === 'hoge' }) } style={ { display: 'table-cell' } }>
{ item_.name }
</div>
</div>
);
})
}
</div>
);
}
}
<apex:page
cache="false"
sidebar="false"
showHeader="false"
standardStylesheets="false"
applyBodyTag="false"
applyHtmlTag="false"
docType="html-5.0">
<html>
<body>
<div id="contents_area"></div>
<script src="{!URLFOR($Resource.SampleResource, '/bundle.js')}"></script>
<script>
var _main = new SampleResource.Main('{!$User.UserName}');
_main.load();
</script>
</body>
</html>
</apex:page>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment