diff --git a/config.js b/config.js index f5b81ddd85..3578137a4a 100644 --- a/config.js +++ b/config.js @@ -1,8 +1,8 @@ const path = require('path') -const yargs = require('yargs') - -const { argv } = yargs +// ------------------------------------ +// Environment vars +// ------------------------------------ const env = process.env.NODE_ENV || 'development' const __DEV__ = env === 'development' const __STAGING__ = env === 'staging' @@ -18,12 +18,10 @@ let config = { path_base: __dirname, dir_src: 'src', dir_dist: 'dist', - dir_docs_root: 'docs', - dir_docs_src: 'docs/app', + dir_dll: 'dll', dir_docs_dist: 'docs/build', + dir_docs_src: 'docs/app', dir_umd_dist: 'dist/umd', - dir_server: 'server', - dir_test: 'test', } // ------------------------------------ @@ -35,10 +33,10 @@ const paths = { base, src: base.bind(null, config.dir_src), dist: base.bind(null, config.dir_dist), - test: base.bind(null, config.dir_test), + dll: base.bind(null, config.dir_dll), docsDist: base.bind(null, config.dir_docs_dist), - umdDist: base.bind(null, config.dir_umd_dist), docsSrc: base.bind(null, config.dir_docs_src), + umdDist: base.bind(null, config.dir_umd_dist), } config = Object.assign({}, config, { @@ -53,30 +51,23 @@ config = Object.assign({}, config, { // ---------------------------------- // Compiler Configuration // ---------------------------------- - compiler_devtool: __DEV__ && 'cheap-source-map' - || __TEST__ && 'cheap-source-map' - || __STAGING__ && 'source-map', + compiler_devtool: (__DEV__ || __TEST__) && 'cheap-source-map' || __STAGING__ && 'source-map', + compiler_globals: { + process: { + env: { + NODE_ENV: JSON.stringify(env), + }, + }, + __DEV__, + __STAGING__, + __PATH_SEP__: JSON.stringify(path.sep), + __TEST__, + __PROD__, + }, compiler_hash_type: __PROD__ ? 'chunkhash' : 'hash', - compiler_inline_manifest: false, compiler_fail_on_warning: __TEST__ || __PROD__, - compiler_lint: argv.lint !== false, - compiler_quiet: false, compiler_output_path: paths.base(config.dir_docs_dist), compiler_public_path: __PROD__ ? '//cdn.rawgit.com/Semantic-Org/Semantic-UI-React/gh-pages/' : '/', - compiler_vendor: [ - 'babel-standalone', - 'brace', - 'brace/ext/language_tools', - 'brace/mode/jsx', - 'brace/mode/html', - 'brace/theme/tomorrow', - 'classnames', - 'copy-to-clipboard', - 'faker', - 'react', - 'react-ace', - 'react-dom', - ], compiler_stats: { hash: false, // the hash of the compilation version: false, // webpack version info @@ -95,19 +86,20 @@ config = Object.assign({}, config, { chunksSort: '', // (string) sort the chunks by that field assetsSort: '', // (string) sort the assets by that field }, - compiler_globals: { - process: { - env: { - NODE_ENV: JSON.stringify(env), - }, - }, - __DEV__, - __DEBUG__: !!argv.debug, - __STAGING__, - __PATH_SEP__: JSON.stringify(path.sep), - __TEST__, - __PROD__, - }, + compiler_vendor: [ + 'babel-standalone', + 'brace', + 'brace/ext/language_tools', + 'brace/mode/jsx', + 'brace/mode/html', + 'brace/theme/tomorrow', + 'classnames', + 'copy-to-clipboard', + 'faker', + 'react', + 'react-ace', + 'react-dom', + ], }) module.exports = config diff --git a/docs/.eslintrc b/docs/.eslintrc index 8af532ecd5..0e9a7bbe36 100644 --- a/docs/.eslintrc +++ b/docs/.eslintrc @@ -1,7 +1,6 @@ { "globals": { "__DEV__": false, - "__DEBUG__": false, "__STAGING__": false, "__TEST__": false, "__PATH_SEP__": false, diff --git a/docs/app/Components/ComponentDoc/ComponentExample.js b/docs/app/Components/ComponentDoc/ComponentExample.js index ecb51a2103..bed5dbd145 100644 --- a/docs/app/Components/ComponentDoc/ComponentExample.js +++ b/docs/app/Components/ComponentDoc/ComponentExample.js @@ -146,7 +146,7 @@ class ComponentExample extends Component { getOriginalSourceCode = () => { const { examplePath } = this.props - if (!this.sourceCode) this.sourceCode = require(`!raw!docs/app/Examples/${examplePath}`) + if (!this.sourceCode) this.sourceCode = require(`!raw-loader!../../Examples/${examplePath}`) return this.sourceCode } diff --git a/docs/app/Components/ExternalExampleLayout.js b/docs/app/Components/ExternalExampleLayout.js index 00bf67abad..72d06451b3 100644 --- a/docs/app/Components/ExternalExampleLayout.js +++ b/docs/app/Components/ExternalExampleLayout.js @@ -1,4 +1,3 @@ -import 'semantic-ui-css/semantic.css' import _ from 'lodash/fp' import React, { Component, PropTypes } from 'react' diff --git a/docs/app/Components/Layout.js b/docs/app/Components/Layout.js index 0a2d3b2afa..a7c438ee6a 100644 --- a/docs/app/Components/Layout.js +++ b/docs/app/Components/Layout.js @@ -1,4 +1,3 @@ -import 'semantic-ui-css/semantic.css' import AnchorJS from 'anchor-js' import React, { Component, PropTypes } from 'react' diff --git a/docs/app/Components/Root.js b/docs/app/Components/Root.js index 74feb52d2f..2121ea6438 100644 --- a/docs/app/Components/Root.js +++ b/docs/app/Components/Root.js @@ -1,4 +1,3 @@ -import 'semantic-ui-css/semantic.css' import _ from 'lodash/fp' import React, { Component, PropTypes } from 'react' diff --git a/karma.conf.js b/karma.conf.js index d2e466cb56..0a1c65e691 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,49 +1,34 @@ -const { argv } = require('yargs') const config = require('./config') const webpackConfig = require('./webpack.config') -module.exports = (karmaConfig) => { - karmaConfig.set({ - basePath: process.cwd(), - browsers: ['PhantomJS'], - singleRun: !argv.watch, - reporters: ['mocha', 'coverage'], - files: [ - './test/tests.bundle.js', - ], - formatError(msg) { - let haveSeenStack = false - return msg - .split('\n') - .reduce((list, line) => { - // filter out node_modules - if (/~/.test(line)) return list +const formatError = (msg) => { + // filter out empty lines and node_modules + if (!msg.trim() || /~/.test(msg)) return '' - // indent the error beneath the it() message - let newLine = ' ' + line + // indent the error beneath the it() message + let newLine = ' ' + msg - if (newLine.includes('webpack:///')) { - if (haveSeenStack === false) { - const indent = newLine.slice(0, newLine.search(/\S/)) - newLine = `\n${indent}Stack:\n${newLine}` - haveSeenStack = true - } + if (newLine.includes('webpack:///')) { + // remove webpack:/// + newLine = newLine.replace('webpack:///', '') - // remove webpack:/// - newLine = newLine.replace('webpack:///', '') + // remove bundle location, showing only the source location + newLine = newLine.slice(0, newLine.indexOf(' <- ')) + } - // remove bundle location, showing only the source location - newLine = newLine.slice(0, newLine.indexOf(' <- ')) - } + return newLine + '\n' +} - return list.concat(newLine) - }, []) - .join('\n') +module.exports = (karmaConfig) => { + karmaConfig.set({ + basePath: process.cwd(), + browsers: ['PhantomJS'], + client: { + mocha: { + reporter: 'html', // change Karma's debug.html to mocha web reporter + ui: 'bdd', + }, }, - frameworks: [ - 'phantomjs-shim', - 'mocha', - ], coverageReporter: { reporters: [ { type: 'lcov', dir: 'coverage', subdir: '.' }, @@ -51,18 +36,20 @@ module.exports = (karmaConfig) => { ], includeAllSources: true, }, + files: [ + './test/tests.bundle.js', + ], + formatError, + frameworks: ['phantomjs-shim', 'mocha'], + reporters: ['mocha', 'coverage'], + singleRun: true, preprocessors: { // do not include 'coverage' preprocessor for karma-coverage // code is already instrumented by babel-plugin-__coverage__ - '**/*.bundle.js': ['webpack'], - }, - client: { - mocha: { - reporter: 'html', // change Karma's debug.html to mocha web reporter - ui: 'bdd', - }, + './test/tests.bundle.js': ['webpack'], }, webpack: { + entry: './test/tests.bundle.js', devtool: config.compiler_devtool, module: webpackConfig.module, plugins: webpackConfig.plugins, diff --git a/package.json b/package.json index f07708b0dc..f842523805 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "deploy:docs": "gh-pages -d docs/build -m 'deploy docs [ci skip]'", "lint": "cross-env NODE_ENV=production eslint .", "lint:fix": "npm run lint -- --fix", - "lint:watch": "watch 'npm run lint --silent' docs gulp src test", "prerelease": "npm run lint && npm run tsd:lint && npm test && cross-env NODE_ENV=production npm run build", "postrelease": "NODE_ENV=production npm run deploy:docs", "release:major": "npm run prerelease && ta-script npm/release.sh major && npm run prerelease", @@ -37,7 +36,7 @@ "start:local-modules": "npm run docs -- --local-modules", "pretest": "npm run build:dll", "test": "cross-env NODE_ENV=test karma start", - "test:watch": "npm run test --silent -- --watch", + "test:watch": "npm run test --silent -- --no-single-run", "tsd": "gulp tsd", "tsd:lint": "tslint './src/**/*.d.ts'", "tsd:lint:fix": "npm run -s tsd:lint -- --fix" @@ -79,7 +78,6 @@ "connect-history-api-fallback": "^1.2.0", "copy-to-clipboard": "^3.0.5", "cross-env": "^4.0.0", - "css-loader": "^0.27.1", "del": "^2.2.2", "dirty-chai": "^1.2.2", "doctoc": "^1.2.0", @@ -90,7 +88,6 @@ "eslint-plugin-jsx-a11y": "^3.0.1", "express": "^4.13.4", "faker": "^3.0.1", - "file-loader": "^0.11.1", "gh-pages": "^0.12.0", "gulp": "github:gulpjs/gulp#4.0", "gulp-html-replace": "^1.6.2", @@ -98,7 +95,7 @@ "gulp-plumber": "^1.0.1", "gulp-util": "^3.0.6", "html-webpack-plugin": "^2.24.0", - "imports-loader": "^0.7.0", + "imports-loader": "^0.7.1", "js-beautify": "^1.6.8", "json-loader": "^0.5.3", "karma": "^1.4.0", @@ -123,22 +120,18 @@ "react-router-dom": "^4.0.0", "require-dir": "^0.3.0", "rimraf": "^2.5.2", - "sass-loader": "^4.0.2", "semantic-ui-css": "^2.2.2", "simulant": "^0.2.2", "sinon": "^2.1.0", "sinon-chai": "^2.9.0", - "style-loader": "^0.14.0", "ta-scripts": "^2.5.2", "through2": "^2.0.2", "tslint": "^5.0.0", "tslint-config-typings": "^0.3.1", "typescript": "^2.1.5", - "watch": "^1.0.1", - "webpack": "^1.12.14", - "webpack-dev-middleware": "^1.5.1", - "webpack-hot-middleware": "^2.15.0", - "yargs": "^7.0.2" + "webpack": "^2.3.2", + "webpack-dev-middleware": "^1.10.1", + "webpack-hot-middleware": "^2.17.1" }, "peerDependencies": { "react": ">=0.14.0 <= 15", diff --git a/test/specs/lib/isBrowser-test.js b/test/specs/lib/isBrowser-test.js index 621e152fa2..7be371857d 100644 --- a/test/specs/lib/isBrowser-test.js +++ b/test/specs/lib/isBrowser-test.js @@ -7,12 +7,12 @@ describe('isBrowser', () => { }) it('should return false when there is no document', () => { - require('imports?document=>undefined!src/lib/isBrowser').default.should.be.false() - require('imports?document=>null!src/lib/isBrowser').default.should.be.false() + require('imports-loader?document=>undefined!src/lib/isBrowser').default.should.be.false() + require('imports-loader?document=>null!src/lib/isBrowser').default.should.be.false() }) it('should return false when there is no window', () => { - require('imports?window=>undefined!src/lib/isBrowser').default.should.be.false() - require('imports?window=>null!src/lib/isBrowser').default.should.be.false() + require('imports-loader?window=>undefined!src/lib/isBrowser').default.should.be.false() + require('imports-loader?window=>null!src/lib/isBrowser').default.should.be.false() }) }) diff --git a/webpack.config.js b/webpack.config.js index 9ec7cf2681..1fa8f711de 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,23 +1,29 @@ -const config = require('./config') -const webpack = require('webpack') const HtmlWebpackPlugin = require('html-webpack-plugin') const _ = require('lodash') -const { argv } = require('yargs') - +const webpack = require('webpack') +const config = require('./config') const { paths } = config -const { __DEV__, __TEST__ } = config.compiler_globals +const { __DEV__, __STAGING__, __TEST__, __PROD__ } = config.compiler_globals const webpackConfig = { name: 'client', target: 'web', devtool: config.compiler_devtool, + externals: {}, + module: { + noParse: [], + rules: [], + }, + plugins: [], resolve: { - root: paths.base(), + modules: [ + paths.base(), + 'node_modules', + ], alias: { 'semantic-ui-react': paths.src('index.js'), }, }, - module: {}, } // ------------------------------------ @@ -25,7 +31,6 @@ const webpackConfig = { // ------------------------------------ const webpackHotPath = `${config.compiler_public_path}__webpack_hmr` - const webpackHotMiddlewareEntry = `webpack-hot-middleware/client?${_.map({ path: webpackHotPath, // The path which the middleware is serving the event stream on timeout: 2000, // The time to wait after a disconnection before attempting to reconnect @@ -54,17 +59,17 @@ webpackConfig.entry = __DEV__ ? { // ------------------------------------ // Bundle Output // ------------------------------------ -webpackConfig.output = { +webpackConfig.output = Object.assign({}, webpackConfig.output, { filename: `[name].[${config.compiler_hash_type}].js`, path: config.compiler_output_path, - publicPath: config.compiler_public_path, pathinfo: true, -} + publicPath: config.compiler_public_path, +}) // ------------------------------------ // Plugins // ------------------------------------ -webpackConfig.plugins = [ +webpackConfig.plugins = [...webpackConfig.plugins, new webpack.DefinePlugin(config.compiler_globals), new webpack.DllReferencePlugin({ context: paths.base('node_modules'), @@ -72,34 +77,47 @@ webpackConfig.plugins = [ }), new HtmlWebpackPlugin({ template: paths.docsSrc('index.ejs'), - hash: false, filename: 'index.html', + hash: false, inject: 'body', minify: { collapseWhitespace: true, }, versions: { babel: require('babel-standalone/package.json').version, - sui: require('semantic-ui-css/package.json').version, - suir: require('./package.json').version, faker: require('faker/package.json').version, + jsBeautify: require('js-beautify/package.json').version, lodash: require('lodash/package.json').version, react: require('react/package.json').version, reactDOM: require('react-dom/package.json').version, - jsBeautify: require('js-beautify/package.json').version, + sui: require('semantic-ui-css/package.json').version, + suir: require('./package.json').version, }, }), ] +if (!__TEST__) { + webpackConfig.plugins.push( + // Don't split bundles during testing as karma can only import one bundle + // https://github.com/webpack-contrib/karma-webpack/issues/22 + new webpack.optimize.CommonsChunkPlugin({ + names: ['vendor'], + }) + ) +} + if (__DEV__) { webpackConfig.plugins.push( new webpack.HotModuleReplacementPlugin(), - new webpack.NoErrorsPlugin() + new webpack.NoEmitOnErrorsPlugin() ) -} else if (!__TEST__) { +} + +if (__PROD__ || __STAGING__) { webpackConfig.plugins.push( - new webpack.optimize.OccurrenceOrderPlugin(), - new webpack.optimize.DedupePlugin(), + new webpack.LoaderOptionsPlugin({ + minimize: true, + }), new webpack.optimize.UglifyJsPlugin({ compress: { unused: true, @@ -110,91 +128,55 @@ if (__DEV__) { ) } -// Don't split bundles during testing, since we only want import one bundle +// ------------------------------------ +// Externals +// ------------------------------------ if (!__TEST__) { - webpackConfig.plugins.push(new webpack.optimize.CommonsChunkPlugin({ - names: ['vendor'], - })) + // find modules loaded via CDN on the window + webpackConfig.externals = Object.assign({}, webpackConfig.externals, { + 'anchor-js': 'AnchorJS', + 'babel-standalone': 'Babel', + faker: 'faker', + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/server': 'ReactDOMServer', + }) } // ------------------------------------ // No Parse // ------------------------------------ -webpackConfig.module.noParse = [ +webpackConfig.module.noParse = [...webpackConfig.module.noParse, /\.json$/, + /anchor-js/, + /babel-standalone/, ] -// ------------------------------------ -// Pre-Loaders -// ------------------------------------ -webpackConfig.module.preLoaders = [] +if (!__TEST__) { + webpackConfig.module.noParse = [...webpackConfig.module.noParse, + // Do not parse browser ready modules loaded via CDN (faster builds) + /faker/, + /js-beautify/, + /react/, + /react-dom/, + ] +} // ------------------------------------ -// Loaders +// Rules // ------------------------------------ -webpackConfig.module.loaders = [{ +webpackConfig.module.rules = [...webpackConfig.module.rules, { // // Babel // test: /\.js$/, exclude: /node_modules/, - loader: 'babel', - query: { - cacheDirectory: true, + use: { + loader: 'babel-loader', + options: { + cacheDirectory: true, + }, }, -}, { - // - // JSON - // - test: /\.(json|.*rc)$/, - loader: 'json', }] -// ---------------------------------------- -// Local Modules -// ---------------------------------------- -// For faster builds in dev, rely on prebuilt libraries -// Local modules can still be enabled (ie for offline development) -// in TEST we need local modules because karma uses a different index.html (no CDNs) -if (__TEST__ || argv.localModules) { - webpackConfig.module.loaders = [ - ...webpackConfig.module.loaders, - { - // - // SASS - // - test: /\.s?css$/, - loaders: ['style', 'css', 'sass'], - }, { - // - // Files - // - test: /\.(eot|ttf|woff|woff2|svg|png)$/, - loader: 'file', - }, - ] -} else { - // these are browser ready modules or aliased to empty - // do not parse their source for faster builds - webpackConfig.module.noParse = [ - ...webpackConfig.module.noParse, - /faker/, - ] - - // alias imports to empty - webpackConfig.resolve.alias = Object.assign({}, webpackConfig.resolve.alias, { - 'semantic-ui-css/semantic.css': 'empty', - }) - - // find them on the window - webpackConfig.externals = Object.assign({}, webpackConfig.externals, { - faker: 'faker', - 'anchor-js': 'AnchorJS', - 'babel-standalone': 'Babel', - react: 'React', - 'react-dom': 'ReactDOM', - 'react-dom/server': 'ReactDOMServer', - }) -} - module.exports = webpackConfig diff --git a/webpack.dll.js b/webpack.dll.js index 9af1cfa244..e46a162605 100644 --- a/webpack.dll.js +++ b/webpack.dll.js @@ -1,9 +1,8 @@ const webpack = require('webpack') - const config = require('./config') -const webpackDllConfig = { module: {} } const { paths } = config +const webpackDllConfig = { module: {} } // ------------------------------------ // Entry Points @@ -15,11 +14,11 @@ webpackDllConfig.entry = { // ------------------------------------ // Bundle Output // ------------------------------------ -webpackDllConfig.output = Object.assign({}, webpackDllConfig.output, { - path: 'dll', +webpackDllConfig.output = { + path: paths.dll(), filename: `dll.[name].[${config.compiler_hash_type}].js`, library: '[name]_[hash]', -}) +} // ------------------------------------ // Plugins @@ -31,32 +30,4 @@ webpackDllConfig.plugins = [ }), ] -// ------------------------------------ -// Pre-Loaders -// ------------------------------------ -webpackDllConfig.module.preLoaders = [] - -// ------------------------------------ -// Loaders -// ------------------------------------ -webpackDllConfig.module.loaders = [{ - // - // JSON - // - test: /\.json$/, - loader: 'json', -}, { - // - // SASS - // - test: /\.s?css$/, - loaders: ['style', 'css', 'sass'], -}, { - // - // Files - // - test: /\.(eot|ttf|woff|woff2|svg|png)$/, - loader: 'file', -}] - module.exports = webpackDllConfig diff --git a/webpack.umd.config.js b/webpack.umd.config.js index bff52695b0..369ccb18ac 100644 --- a/webpack.umd.config.js +++ b/webpack.umd.config.js @@ -1,5 +1,6 @@ -const config = require('./config') const webpack = require('webpack') + +const config = require('./config') const webpackConfig = require('./webpack.config') const pkg = require('./package.json') @@ -11,6 +12,10 @@ const webpackUMDConfig = { entry: { [pkg.name]: paths.src('umd.js'), }, + externals: { + react: 'React', + 'react-dom': 'ReactDOM', + }, output: { filename: '[name].min.js', libraryTarget: 'umd', @@ -19,13 +24,7 @@ const webpackUMDConfig = { publicPath: '/', pathinfo: true, }, - externals: { - react: 'React', - 'react-dom': 'ReactDOM', - }, plugins: [ - new webpack.optimize.OccurrenceOrderPlugin(), - new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({ compress: { unused: true, @@ -36,7 +35,7 @@ const webpackUMDConfig = { ], module: { noParse: webpackConfig.module.noParse, - loaders: webpackConfig.module.loaders, + rules: webpackConfig.module.rules, }, }