From 9c75f0a4e1bd2393608ffaebdf894f30a60e00fb Mon Sep 17 00:00:00 2001 From: Christopher Joe Date: Thu, 29 Sep 2016 13:39:07 +1300 Subject: [PATCH] Rebased with webpack --- .editorconfig | 3 + client/dist/bundle-legacy.js | 3 - client/dist/legacy.js | 14 +++ client/src/legacy/TestReactFormBuilder.js | 100 +++++++++---------- code/TestReactFormBuilder.php | 2 +- gulpfile.js | 70 -------------- package.json | 77 ++++++++------- webpack-dev.config.js | 12 +++ webpack.config.js | 113 ++++++++++++++++++++++ 9 files changed, 236 insertions(+), 158 deletions(-) delete mode 100644 client/dist/bundle-legacy.js create mode 100644 client/dist/legacy.js delete mode 100644 gulpfile.js create mode 100644 webpack-dev.config.js create mode 100644 webpack.config.js diff --git a/.editorconfig b/.editorconfig index 47ae637..52cefc9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,6 +10,9 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true +[{*.js,*.jsx}] +indent_size = 2 + [{*.yml,package.json}] indent_size = 2 diff --git a/client/dist/bundle-legacy.js b/client/dist/bundle-legacy.js deleted file mode 100644 index 50c5e0b..0000000 --- a/client/dist/bundle-legacy.js +++ /dev/null @@ -1,3 +0,0 @@ -!function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o1)for(var i=1;i does not support changing `store` on the fly. It is most likely that you see this error because you updated to Redux 2.x and React Redux 2.x which no longer hot reload reducers automatically. See https://github.com/reactjs/react-redux/releases/tag/v2.0.0 for the migration instructions."))}exports.__esModule=!0,exports["default"]=void 0;var _react=require("react"),_storeShape=require("../utils/storeShape"),_storeShape2=_interopRequireDefault(_storeShape),_warning=require("../utils/warning"),_warning2=_interopRequireDefault(_warning),didWarnAboutReceivingStore=!1,Provider=function(_Component){function Provider(props,context){_classCallCheck(this,Provider);var _this=_possibleConstructorReturn(this,_Component.call(this,props,context));return _this.store=props.store,_this}return _inherits(Provider,_Component),Provider.prototype.getChildContext=function(){return{store:this.store}},Provider.prototype.render=function(){var children=this.props.children;return _react.Children.only(children)},Provider}(_react.Component);exports["default"]=Provider,"production"!==process.env.NODE_ENV&&(Provider.prototype.componentWillReceiveProps=function(nextProps){var store=this.store,nextStore=nextProps.store;store!==nextStore&&warnAboutReceivingStore()}),Provider.propTypes={store:_storeShape2["default"].isRequired,children:_react.PropTypes.element.isRequired},Provider.childContextTypes={store:_storeShape2["default"].isRequired}}).call(this,require("_process"))},{"../utils/storeShape":8,"../utils/warning":9,_process:3,react:"react"}],5:[function(require,module,exports){(function(process){"use strict";function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{"default":obj}}function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(self,call){if(!self)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!call||"object"!=typeof call&&"function"!=typeof call?self:call}function _inherits(subClass,superClass){if("function"!=typeof superClass&&null!==superClass)throw new TypeError("Super expression must either be null or a function, not "+typeof superClass);subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,enumerable:!1,writable:!0,configurable:!0}}),superClass&&(Object.setPrototypeOf?Object.setPrototypeOf(subClass,superClass):subClass.__proto__=superClass)}function getDisplayName(WrappedComponent){return WrappedComponent.displayName||WrappedComponent.name||"Component"}function tryCatch(fn,ctx){try{return fn.apply(ctx)}catch(e){return errorObject.value=e,errorObject}}function connect(mapStateToProps,mapDispatchToProps,mergeProps){var options=arguments.length<=3||void 0===arguments[3]?{}:arguments[3],shouldSubscribe=Boolean(mapStateToProps),mapState=mapStateToProps||defaultMapStateToProps,mapDispatch=void 0;mapDispatch="function"==typeof mapDispatchToProps?mapDispatchToProps:mapDispatchToProps?(0,_wrapActionCreators2["default"])(mapDispatchToProps):defaultMapDispatchToProps;var finalMergeProps=mergeProps||defaultMergeProps,_options$pure=options.pure,pure=void 0===_options$pure||_options$pure,_options$withRef=options.withRef,withRef=void 0!==_options$withRef&&_options$withRef,checkMergedEquals=pure&&finalMergeProps!==defaultMergeProps,version=nextVersion++;return function(WrappedComponent){function checkStateShape(props,methodName){(0,_isPlainObject2["default"])(props)||(0,_warning2["default"])(methodName+"() in "+connectDisplayName+" must return a plain object. "+("Instead received "+props+"."))}function computeMergedProps(stateProps,dispatchProps,parentProps){var mergedProps=finalMergeProps(stateProps,dispatchProps,parentProps);return"production"!==process.env.NODE_ENV&&checkStateShape(mergedProps,"mergeProps"),mergedProps}var connectDisplayName="Connect("+getDisplayName(WrappedComponent)+")",Connect=function(_Component){function Connect(props,context){_classCallCheck(this,Connect);var _this=_possibleConstructorReturn(this,_Component.call(this,props,context));_this.version=version,_this.store=props.store||context.store,(0,_invariant2["default"])(_this.store,'Could not find "store" in either the context or '+('props of "'+connectDisplayName+'". ')+"Either wrap the root component in a , "+('or explicitly pass "store" as a prop to "'+connectDisplayName+'".'));var storeState=_this.store.getState();return _this.state={storeState:storeState},_this.clearCache(),_this}return _inherits(Connect,_Component),Connect.prototype.shouldComponentUpdate=function(){return!pure||this.haveOwnPropsChanged||this.hasStoreStateChanged},Connect.prototype.computeStateProps=function(store,props){if(!this.finalMapStateToProps)return this.configureFinalMapState(store,props);var state=store.getState(),stateProps=this.doStatePropsDependOnOwnProps?this.finalMapStateToProps(state,props):this.finalMapStateToProps(state);return"production"!==process.env.NODE_ENV&&checkStateShape(stateProps,"mapStateToProps"),stateProps},Connect.prototype.configureFinalMapState=function(store,props){var mappedState=mapState(store.getState(),props),isFactory="function"==typeof mappedState;return this.finalMapStateToProps=isFactory?mappedState:mapState,this.doStatePropsDependOnOwnProps=1!==this.finalMapStateToProps.length,isFactory?this.computeStateProps(store,props):("production"!==process.env.NODE_ENV&&checkStateShape(mappedState,"mapStateToProps"),mappedState)},Connect.prototype.computeDispatchProps=function(store,props){if(!this.finalMapDispatchToProps)return this.configureFinalMapDispatch(store,props);var dispatch=store.dispatch,dispatchProps=this.doDispatchPropsDependOnOwnProps?this.finalMapDispatchToProps(dispatch,props):this.finalMapDispatchToProps(dispatch);return"production"!==process.env.NODE_ENV&&checkStateShape(dispatchProps,"mapDispatchToProps"),dispatchProps},Connect.prototype.configureFinalMapDispatch=function(store,props){var mappedDispatch=mapDispatch(store.dispatch,props),isFactory="function"==typeof mappedDispatch;return this.finalMapDispatchToProps=isFactory?mappedDispatch:mapDispatch,this.doDispatchPropsDependOnOwnProps=1!==this.finalMapDispatchToProps.length,isFactory?this.computeDispatchProps(store,props):("production"!==process.env.NODE_ENV&&checkStateShape(mappedDispatch,"mapDispatchToProps"),mappedDispatch)},Connect.prototype.updateStatePropsIfNeeded=function(){var nextStateProps=this.computeStateProps(this.store,this.props);return(!this.stateProps||!(0,_shallowEqual2["default"])(nextStateProps,this.stateProps))&&(this.stateProps=nextStateProps,!0)},Connect.prototype.updateDispatchPropsIfNeeded=function(){var nextDispatchProps=this.computeDispatchProps(this.store,this.props);return(!this.dispatchProps||!(0,_shallowEqual2["default"])(nextDispatchProps,this.dispatchProps))&&(this.dispatchProps=nextDispatchProps,!0)},Connect.prototype.updateMergedPropsIfNeeded=function(){var nextMergedProps=computeMergedProps(this.stateProps,this.dispatchProps,this.props);return!(this.mergedProps&&checkMergedEquals&&(0,_shallowEqual2["default"])(nextMergedProps,this.mergedProps))&&(this.mergedProps=nextMergedProps,!0)},Connect.prototype.isSubscribed=function(){return"function"==typeof this.unsubscribe},Connect.prototype.trySubscribe=function(){shouldSubscribe&&!this.unsubscribe&&(this.unsubscribe=this.store.subscribe(this.handleChange.bind(this)),this.handleChange())},Connect.prototype.tryUnsubscribe=function(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=null)},Connect.prototype.componentDidMount=function(){this.trySubscribe()},Connect.prototype.componentWillReceiveProps=function(nextProps){pure&&(0,_shallowEqual2["default"])(nextProps,this.props)||(this.haveOwnPropsChanged=!0)},Connect.prototype.componentWillUnmount=function(){this.tryUnsubscribe(),this.clearCache()},Connect.prototype.clearCache=function(){this.dispatchProps=null,this.stateProps=null,this.mergedProps=null,this.haveOwnPropsChanged=!0,this.hasStoreStateChanged=!0,this.haveStatePropsBeenPrecalculated=!1,this.statePropsPrecalculationError=null,this.renderedElement=null,this.finalMapDispatchToProps=null,this.finalMapStateToProps=null},Connect.prototype.handleChange=function(){if(this.unsubscribe){var storeState=this.store.getState(),prevStoreState=this.state.storeState;if(!pure||prevStoreState!==storeState){if(pure&&!this.doStatePropsDependOnOwnProps){var haveStatePropsChanged=tryCatch(this.updateStatePropsIfNeeded,this);if(!haveStatePropsChanged)return;haveStatePropsChanged===errorObject&&(this.statePropsPrecalculationError=errorObject.value),this.haveStatePropsBeenPrecalculated=!0}this.hasStoreStateChanged=!0,this.setState({storeState:storeState})}}},Connect.prototype.getWrappedInstance=function(){return(0,_invariant2["default"])(withRef,"To access the wrapped instance, you need to specify { withRef: true } as the fourth argument of the connect() call."),this.refs.wrappedInstance},Connect.prototype.render=function(){var haveOwnPropsChanged=this.haveOwnPropsChanged,hasStoreStateChanged=this.hasStoreStateChanged,haveStatePropsBeenPrecalculated=this.haveStatePropsBeenPrecalculated,statePropsPrecalculationError=this.statePropsPrecalculationError,renderedElement=this.renderedElement;if(this.haveOwnPropsChanged=!1,this.hasStoreStateChanged=!1,this.haveStatePropsBeenPrecalculated=!1,this.statePropsPrecalculationError=null,statePropsPrecalculationError)throw statePropsPrecalculationError;var shouldUpdateStateProps=!0,shouldUpdateDispatchProps=!0;pure&&renderedElement&&(shouldUpdateStateProps=hasStoreStateChanged||haveOwnPropsChanged&&this.doStatePropsDependOnOwnProps,shouldUpdateDispatchProps=haveOwnPropsChanged&&this.doDispatchPropsDependOnOwnProps);var haveStatePropsChanged=!1,haveDispatchPropsChanged=!1;haveStatePropsBeenPrecalculated?haveStatePropsChanged=!0:shouldUpdateStateProps&&(haveStatePropsChanged=this.updateStatePropsIfNeeded()),shouldUpdateDispatchProps&&(haveDispatchPropsChanged=this.updateDispatchPropsIfNeeded());var haveMergedPropsChanged=!0;return haveMergedPropsChanged=!!(haveStatePropsChanged||haveDispatchPropsChanged||haveOwnPropsChanged)&&this.updateMergedPropsIfNeeded(),!haveMergedPropsChanged&&renderedElement?renderedElement:(withRef?this.renderedElement=(0,_react.createElement)(WrappedComponent,_extends({},this.mergedProps,{ref:"wrappedInstance"})):this.renderedElement=(0,_react.createElement)(WrappedComponent,this.mergedProps),this.renderedElement)},Connect}(_react.Component);return Connect.displayName=connectDisplayName,Connect.WrappedComponent=WrappedComponent,Connect.contextTypes={store:_storeShape2["default"]},Connect.propTypes={store:_storeShape2["default"]},"production"!==process.env.NODE_ENV&&(Connect.prototype.componentWillUpdate=function(){this.version!==version&&(this.version=version,this.trySubscribe(),this.clearCache())}),(0,_hoistNonReactStatics2["default"])(Connect,WrappedComponent)}}var _extends=Object.assign||function(target){for(var i=1;i0?"Unexpected "+(unexpectedKeys.length>1?"keys":"key")+" "+('"'+unexpectedKeys.join('", "')+'" found in '+argumentName+". ")+"Expected to find one of the known reducer keys instead: "+('"'+reducerKeys.join('", "')+'". Unexpected keys will be ignored.'):void 0}function assertReducerSanity(reducers){Object.keys(reducers).forEach(function(key){var reducer=reducers[key],initialState=reducer(void 0,{type:_createStore.ActionTypes.INIT});if("undefined"==typeof initialState)throw new Error('Reducer "'+key+'" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.');var type="@@redux/PROBE_UNKNOWN_ACTION_"+Math.random().toString(36).substring(7).split("").join(".");if("undefined"==typeof reducer(void 0,{type:type}))throw new Error('Reducer "'+key+'" returned undefined when probed with a random type. '+("Don't try to handle "+_createStore.ActionTypes.INIT+' or other actions in "redux/*" ')+"namespace. They are considered private. Instead, you must return the current state for any unknown actions, unless it is undefined, in which case you must return the initial state, regardless of the action type. The initial state may not be undefined.")})}function combineReducers(reducers){var sanityError,finalReducers=_pick2["default"](reducers,function(val){return"function"==typeof val});try{assertReducerSanity(finalReducers)}catch(e){sanityError=e}var defaultState=_mapValues2["default"](finalReducers,function(){});return function(state,action){if(void 0===state&&(state=defaultState),sanityError)throw sanityError;var hasChanged=!1,finalState=_mapValues2["default"](finalReducers,function(reducer,key){var previousStateForKey=state[key],nextStateForKey=reducer(previousStateForKey,action);if("undefined"==typeof nextStateForKey){var errorMessage=getUndefinedStateErrorMessage(key,action);throw new Error(errorMessage)}return hasChanged=hasChanged||nextStateForKey!==previousStateForKey,nextStateForKey});if("production"!==process.env.NODE_ENV){var warningMessage=getUnexpectedStateKeyWarningMessage(state,finalState,action);warningMessage&&console.error(warningMessage)}return hasChanged?finalState:state}}exports.__esModule=!0,exports["default"]=combineReducers;var _createStore=require("../createStore"),_isPlainObject=require("./isPlainObject"),_isPlainObject2=_interopRequireDefault(_isPlainObject),_mapValues=require("./mapValues"),_mapValues2=_interopRequireDefault(_mapValues),_pick=require("./pick"),_pick2=_interopRequireDefault(_pick);module.exports=exports["default"]}).call(this,require("_process")); -},{"../createStore":18,"./isPlainObject":24,"./mapValues":25,"./pick":26,_process:3}],23:[function(require,module,exports){"use strict";function compose(){for(var _len=arguments.length,funcs=Array(_len),_key=0;_key<_len;_key++)funcs[_key]=arguments[_key];return function(arg){return funcs.reduceRight(function(composed,f){return f(composed)},arg)}}exports.__esModule=!0,exports["default"]=compose,module.exports=exports["default"]},{}],24:[function(require,module,exports){"use strict";function isPlainObject(obj){if(!obj||"object"!=typeof obj)return!1;var proto="function"==typeof obj.constructor?Object.getPrototypeOf(obj):Object.prototype;if(null===proto)return!0;var constructor=proto.constructor;return"function"==typeof constructor&&constructor instanceof constructor&&fnToString(constructor)===objStringValue}exports.__esModule=!0,exports["default"]=isPlainObject;var fnToString=function(fn){return Function.prototype.toString.call(fn)},objStringValue=fnToString(Object);module.exports=exports["default"]},{}],25:[function(require,module,exports){"use strict";function mapValues(obj,fn){return Object.keys(obj).reduce(function(result,key){return result[key]=fn(obj[key],key),result},{})}exports.__esModule=!0,exports["default"]=mapValues,module.exports=exports["default"]},{}],26:[function(require,module,exports){"use strict";function pick(obj,fn){return Object.keys(obj).reduce(function(result,key){return fn(obj[key])&&(result[key]=obj[key]),result},{})}exports.__esModule=!0,exports["default"]=pick,module.exports=exports["default"]},{}]},{},[1]); -//# sourceMappingURL=bundle-legacy.js.map diff --git a/client/dist/legacy.js b/client/dist/legacy.js new file mode 100644 index 0000000..4af58c3 --- /dev/null +++ b/client/dist/legacy.js @@ -0,0 +1,14 @@ +!function(t){function e(r){if(n[r])return n[r].exports +var o=n[r]={exports:{},id:r,loaded:!1} +return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={} +return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){"use strict" +n(1)},function(t,e,n){"use strict" +function r(t){return t&&t.__esModule?t:{"default":t}}var o=n(2),i=r(o),u=n(3),c=r(u),s=n(4),a=r(s),l=n(5),f=n(6),d=r(f) +i["default"].entwine("ss",function(t){t(".TestReactFormBuilder").entwine({onmatch:function e(){var t=this +setTimeout(function(){return t._renderForm()},100),this[0].style.setProperty("overflow-y","scroll","important")},onunmatch:function n(){this._clearForm(),this.css("overflow-y",!1)},open:function r(){this._renderForm() + +},close:function o(){this._clearForm()},_renderForm:function i(){var t=this,e=window.ss.store,n=e.getState().config.sections.TestReactFormBuilder,r=n.form.TestEditForm.schemaUrl +a["default"].render(c["default"].createElement(l.Provider,{store:e},c["default"].createElement(d["default"],{schemaUrl:r,handleSubmit:function o(){return t._handleSubmit.apply(t,arguments)}})),this[0]) + +},_clearForm:function u(){a["default"].unmountComponentAtNode(this[0])},_handleSubmit:function s(t,e,n){return t.preventDefault(),n()}}),t(".TestReactFormBuilder .nav-link").entwine({onclick:function f(t){ +t.preventDefault()}})})},function(t,e){t.exports=jQuery},function(t,e){t.exports=React},function(t,e){t.exports=ReactDom},function(t,e){t.exports=ReactRedux},function(t,e){t.exports=FormBuilder}]) diff --git a/client/src/legacy/TestReactFormBuilder.js b/client/src/legacy/TestReactFormBuilder.js index bfca34c..9910647 100644 --- a/client/src/legacy/TestReactFormBuilder.js +++ b/client/src/legacy/TestReactFormBuilder.js @@ -1,67 +1,69 @@ import jQuery from 'jQuery'; -import i18n from 'i18n'; import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import FormBuilder from 'components/FormBuilder/FormBuilder'; jQuery.entwine('ss', ($) => { - /** - * Kick off Test React FormBuilder admin section. - * Uses React to rebuild the list of fields from FrameworkTest's TestPages. - */ - $('.cms-content.TestReactFormBuilder').entwine({ - onmatch() { - setTimeout(() => this._renderForm(), 100); - }, + /** + * Kick off Test React FormBuilder admin section. + * Uses React to rebuild the list of fields from FrameworkTest's TestPages. + */ + $('.TestReactFormBuilder').entwine({ + onmatch() { + setTimeout(() => this._renderForm(), 100); + // need to force scrollable .css() doesn't work with important which is needed for this case + this[0].style.setProperty('overflow-y', 'scroll', 'important'); + }, - onunmatch() { - this._clearForm(); - }, + onunmatch() { + this._clearForm(); + this.css('overflow-y', false); + }, - open() { - this._renderForm(); - }, + open() { + this._renderForm(); + }, - close() { - this._clearForm(); - }, + close() { + this._clearForm(); + }, - _renderForm() { - const store = window.ss.store; - const sectionConfig = store.getState() - .config.sections['TestReactFormBuilder']; - const schemaUrl = sectionConfig.form.TestEditForm.schemaUrl; + _renderForm() { + const store = window.ss.store; + const sectionConfig = store.getState() + .config.sections['TestReactFormBuilder']; + const schemaUrl = sectionConfig.form.TestEditForm.schemaUrl; - ReactDOM.render( - - this._handleSubmit(...args)} - /> - , - this[0] - ); - }, + ReactDOM.render( + + this._handleSubmit(...args)} + /> + , + this[0] + ); + }, - _clearForm() { - ReactDOM.unmountComponentAtNode(this[0]); - // this.empty(); - }, + _clearForm() { + ReactDOM.unmountComponentAtNode(this[0]); + // this.empty(); + }, - _handleSubmit(event, fieldValues, submitFn) { - event.preventDefault(); + _handleSubmit(event, fieldValues, submitFn) { + event.preventDefault(); - return submitFn(); - }, + return submitFn(); + }, - }); + }); - $('.cms-content.TestReactFormBuilder .nav-link').entwine({ - onclick: function (e) { - // this is required because the React version of e.preventDefault() doesn't work - // this is to stop React Tabs from navigating the page - e.preventDefault(); - } - }); + $('.TestReactFormBuilder .nav-link').entwine({ + onclick: function (e) { + // this is required because the React version of e.preventDefault() doesn't work + // this is to stop React Tabs from navigating the page + e.preventDefault(); + } + }); }); diff --git a/code/TestReactFormBuilder.php b/code/TestReactFormBuilder.php index 5cc9e93..93d1927 100644 --- a/code/TestReactFormBuilder.php +++ b/code/TestReactFormBuilder.php @@ -46,7 +46,7 @@ class TestReactFormBuilder extends LeftAndMain } public function getEditForm($id = null, $fields = null) { - Requirements::javascript('frameworktest/client/dist/bundle-legacy.js'); + Requirements::javascript('frameworktest/client/dist/legacy.js'); return Form::create($this, 'TestEditForm', FieldList::create(), FieldList::create()); } diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 771a8be..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,70 +0,0 @@ -const gulp = require('gulp'); -const browserify = require('browserify'); -const buffer = require('vinyl-buffer'); -const sourcemaps = require('gulp-sourcemaps'); -const uglify = require('gulp-uglify'); -const gulpUtil = require('gulp-util'); -const notify = require('gulp-notify'); -const source = require('vinyl-source-stream'); - -const isDev = typeof process.env.npm_config_development !== 'undefined'; - -const PATHS = { - JS_SRC: './client/src', - JS_DIST: './client/dist', -}; - -const browserifyOptions = { - debug: true, - paths: [PATHS.JS_SRC], -}; - -const babelifyOptions = { - presets: ['es2015', 'es2015-ie', 'react'], - plugins: ['transform-object-assign', 'transform-object-rest-spread'], - ignore: /(node_modules|thirdparty)/, - comments: false, -}; - -const uglifyOptions = { - mangle: false, -}; - -gulp.task('build', ['bundle']); - -gulp.task('bundle', ['bundle-legacy']); - -gulp.task('bundle-legacy', function bundleLeftAndMain() { - const bundleFileName = 'bundle-legacy.js'; - - return browserify(Object.assign({}, browserifyOptions, - { entries: `${PATHS.JS_SRC}/bundles/legacy.js` } - )) - .on('update', bundleLeftAndMain) - .on('log', (msg) => - gulpUtil.log('Finished', `bundled ${bundleFileName} ${msg}`) - ) - .transform('babelify', babelifyOptions) - .external('config') - .external('jQuery') - .external('i18n') - .external('i18nx') - .external('react') - .external('react-dom') - .external('components/FormBuilder/FormBuilder') - .bundle() - .on('update', bundleLeftAndMain) - .on('error', notify.onError({ message: `${bundleFileName}: <%= error.message %>` })) - .pipe(source(bundleFileName)) - .pipe(buffer()) - .pipe(sourcemaps.init({ loadMaps: true })) - .pipe(uglify(uglifyOptions)) - .pipe(sourcemaps.write('./')) - .pipe(gulp.dest(PATHS.JS_DIST)); -}); - -gulp.task('default', ['build'], () => { - if (isDev) { - gulp.watch(`${PATHS.JS_SRC}/**/*.js`, ['build']); - } -}); diff --git a/package.json b/package.json index 459d7f8..ce9290e 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,12 @@ "node": "4.x" }, "scripts": { - "build": "gulp", - "test": "NODE_PATH=\"./client/src:../framework/client/src:../framework/admin/client/src\" jest", - "coverage": "jest --coverage", + "build": "webpack", + "watch": "webpack --config ./webpack-dev.config.js --watch", "lock": "npm-shrinkwrap --dev", - "lint": "eslint client/src" + "test": "NODE_PATH=\"./client/src\" jest", + "coverage": "NODE_PATH=\"./client/src\" jest --coverage", + "lint": "eslint client/src & sass-lint -v" }, "jest": { "scriptPreprocessor": "/node_modules/babel-jest", @@ -36,44 +37,50 @@ "bail": true, "testRunner": "/node_modules/jest-cli/src/testRunners/jasmine/jasmine2.js" }, - "devDependencies": { - "babel-core": "^6.7.7", - "babel-jest": "^11.0.2", - "babel-plugin-transform-es2015-modules-umd": "^6.6.5", - "babel-plugin-transform-object-assign": "^6.5.0", - "babel-plugin-transform-object-rest-spread": "^6.8.0", - "babel-preset-es2015": "^6.6.0", - "babel-preset-es2015-ie": "^6.6.1", - "babel-preset-react": "^6.5.0", - "babelify": "^7.2.0", - "browserify": "^11.1.0", - "deep-freeze-strict": "^1.1.1", - "eslint": "^2.5.3", - "eslint-config-airbnb": "^6.2.0", - "eslint-plugin-react": "^4.2.3", - "gulp": "^3.9.0", - "gulp-if": "^2.0.0", - "gulp-notify": "^2.2.0", - "gulp-sourcemaps": "^1.6.0", - "gulp-uglify": "^1.5.2", - "jest-cli": "^0.9.2", - "npm-shrinkwrap": "^200.4.0", - "react": "^0.14.8", - "react-addons-css-transition-group": "^0.14.8", + "dependencies": { + "react": "^15.3.1", + "react-addons-css-transition-group": "^15.3.1", "react-bootstrap-ss": "^0.30.5", - "react-dom": "^0.14.8", + "react-dom": "^15.3.1", "react-redux": "^4.4.1", "react-router": "^2.4.1", "react-router-redux": "^4.0.5", "redux": "https://registry.npmjs.org/redux/-/redux-3.0.5.tgz", "redux-thunk": "^2.1.0", - "semver": "^5.0.3", - "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.1.0", - "watchify": "^3.7.0" + "tether": "^1.3.2", + "url": "^0.11.0" }, - "dependencies": { - "gulp-util": "^3.0.7" + "devDependencies": { + "autoprefixer": "^6.4.0", + "babel-core": "^6.7.4", + "babel-jest": "^9.0.3", + "babel-loader": "^6.2.5", + "babel-plugin-transform-es2015-modules-umd": "^6.6.5", + "babel-plugin-transform-object-assign": "^6.5.0", + "babel-plugin-transform-object-rest-spread": "^6.8.0", + "babel-preset-es2015": "^6.6.0", + "babel-preset-react": "^6.5.0", + "css-loader": "^0.23.1", + "eslint": "^2.5.3", + "eslint-config-airbnb": "^6.2.0", + "eslint-plugin-react": "^4.2.3", + "expose-loader": "^0.7.1", + "extract-text-webpack-plugin": "^1.0.1", + "file-loader": "^0.9.0", + "imports-loader": "^0.6.5", + "jest-cli": "^0.9.2", + "node-sass": "^3.8.0", + "npm-shrinkwrap": "^6.0.1", + "postcss-loader": "^0.10.1", + "react-addons-test-utils": "^15.3.1", + "redux-logger": "^2.6.1", + "resolve-url-loader": "^1.6.0", + "sass-lint": "^1.9.1", + "sass-loader": "^4.0.0", + "script-loader": "^0.7.0", + "semver": "^5.1.0", + "url-loader": "^0.5.7", + "webpack": "^1.13.2" }, "babel": { "presets": [ diff --git a/webpack-dev.config.js b/webpack-dev.config.js new file mode 100644 index 0000000..852f212 --- /dev/null +++ b/webpack-dev.config.js @@ -0,0 +1,12 @@ +const webpack = require('webpack'); +const Config = require('./webpack.config'); + +Config.plugins = [ + new webpack.ProvidePlugin({ + jQuery: 'jQuery', + $: 'jQuery', + }), +]; +Config.devtool = 'source-map'; + +module.exports = Config; diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..f905c59 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,113 @@ +const webpack = require('webpack'); +const autoprefixer = require('autoprefixer'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); +// const SprityWebpackPlugin = require('sprity-webpack-plugin'); + +const PATHS = { + MODULES: './node_modules', + JS_SRC: './client/src', + JS_DIST: './client/dist', +}; + +// Used for autoprefixing css properties (same as Bootstrap Aplha.2 defaults) +const SUPPORTED_BROWSERS = [ + 'Chrome >= 35', + 'Firefox >= 31', + 'Edge >= 12', + 'Explorer >= 9', + 'iOS >= 8', + 'Safari >= 8', + 'Android 2.3', + 'Android >= 4', + 'Opera >= 12', +]; + +const config = { + // TODO Split out with new 'admin' module + name: 'js', + entry: { + legacy: `${PATHS.JS_SRC}/bundles/legacy.js`, + }, + resolve: { + modulesDirectories: [PATHS.MODULES], + }, + output: { + path: 'client/dist', + filename: '[name].js', + }, + + // lib.js provies these globals and more. These references allow the framework bundle + // to access them. + externals: { + 'components/Breadcrumb/Breadcrumb': 'Breadcrumb', + 'components/FormBuilderModal/FormBuilderModal': 'FormBuilderModal', + 'components/FormBuilder/FormBuilder': 'FormBuilder', + 'components/Toolbar/Toolbar': 'Toolbar', + 'state/breadcrumbs/BreadcrumbsActions': 'BreadcrumbsActions', + 'deep-freeze-strict': 'DeepFreezeStrict', + i18n: 'i18n', + jQuery: 'jQuery', + 'lib/Backend': 'Backend', + 'lib/Config': 'Config', + 'lib/Injector': 'Injector', + 'lib/ReducerRegister': 'ReducerRegister', + 'lib/Router': 'Router', + 'lib/ReactRouteRegister': 'ReactRouteRegister', + 'lib/SilverStripeComponent': 'SilverStripeComponent', + 'page.js': 'Page', + 'react-addons-css-transition-group': 'ReactAddonsCssTransitionGroup', + 'react-addons-test-utils': 'ReactAddonsTestUtils', + 'react-dom': 'ReactDom', + 'react-redux': 'ReactRedux', + 'react-router-redux': 'ReactRouterRedux', + 'react-router': 'ReactRouter', + react: 'React', + 'redux-thunk': 'ReduxThunk', + redux: 'Redux', + }, + module: { + loaders: [ + { + test: /\.js$/, + exclude: /(node_modules|thirdparty)/, + loader: 'babel', + query: { + presets: ['es2015', 'react'], + plugins: ['transform-object-assign', 'transform-object-rest-spread'], + comments: false, + }, + }, + { + test: '/i18n.js/', + loader: 'script-loader', + }, + ], + }, + plugins: [ + new webpack.ProvidePlugin({ + jQuery: 'jQuery', + $: 'jQuery', + }), + new webpack.DefinePlugin({ + 'process.env':{ + // Builds React in production mode, avoiding console warnings + 'NODE_ENV': JSON.stringify('production') + } + }), + new webpack.optimize.UglifyJsPlugin({ + compress: { + unused: false, + warnings: false, + }, + output: { + beautify: false, + semicolons: false, + comments: false, + max_line_len: 200, + }, + }), + ], + }; + +// Use WEBPACK_CHILD=js or WEBPACK_CHILD=css env var to run a single config +module.exports = config;