From c358c0c31e4882e5dc571097b37f5e26ee0210f9 Mon Sep 17 00:00:00 2001 From: Eli Perelman Date: Mon, 6 Feb 2017 14:22:20 -0600 Subject: [PATCH] ESLint fixes and webpack-chain integration --- package.json | 1 + packages/neutrino-preset-base/package.json | 1 + packages/neutrino-preset-base/src/eslint.js | 8 +- packages/neutrino-preset-base/src/index.js | 141 ++++---- packages/neutrino-preset-base/yarn.lock | 27 +- packages/neutrino-preset-node/package.json | 1 + packages/neutrino-preset-node/src/index.js | 154 ++++----- packages/neutrino-preset-node/yarn.lock | 4 + packages/neutrino-preset-react/src/index.js | 105 +++--- packages/neutrino-preset-web/src/index.js | 342 ++++++++++---------- packages/neutrino-preset-web/yarn.lock | 8 +- packages/neutrino/src/get-preset.js | 10 +- packages/neutrino/yarn.lock | 18 +- 13 files changed, 432 insertions(+), 388 deletions(-) diff --git a/package.json b/package.json index 352526e..cb0a924 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "author": "Eli Perelman ", "license": "MPL-2.0", "scripts": { + "bootstrap": "autolink bootstrap", "postinstall": "autolink bootstrap", "clean-all": "autolink clean", "link-all": "autolink link", diff --git a/packages/neutrino-preset-base/package.json b/packages/neutrino-preset-base/package.json index ea238c9..526098e 100644 --- a/packages/neutrino-preset-base/package.json +++ b/packages/neutrino-preset-base/package.json @@ -27,6 +27,7 @@ "imports-loader": "^0.7.0", "progress-bar-webpack-plugin": "^1.9.3", "webpack": "^2.2.1", + "webpack-chain": "^1.0.0", "webpack-merge": "^2.6.1" }, "peerDependencies": { diff --git a/packages/neutrino-preset-base/src/eslint.js b/packages/neutrino-preset-base/src/eslint.js index df0465e..3b34e5c 100644 --- a/packages/neutrino-preset-base/src/eslint.js +++ b/packages/neutrino-preset-base/src/eslint.js @@ -3,12 +3,10 @@ const eslint = { useEslintrc: false, root: true, plugins: ['babel', 'mocha'], - extends: [ - 'eslint:recommended', - ], - env: { - es6: true + baseConfig: { + extends: ['eslint:recommended'] }, + envs: ['es6'], parser: 'babel-eslint', parserOptions: { ecmaVersion: 2017, diff --git a/packages/neutrino-preset-base/src/index.js b/packages/neutrino-preset-base/src/index.js index 119811c..6b02b6a 100644 --- a/packages/neutrino-preset-base/src/index.js +++ b/packages/neutrino-preset-base/src/index.js @@ -1,5 +1,6 @@ 'use strict'; +const Config = require('webpack-chain'); const CleanPlugin = require('clean-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin'); const path = require('path'); @@ -14,83 +15,81 @@ const BASE_MODULES = path.join(__dirname, '../node_modules'); const SRC = path.join(CWD, 'src'); const TEST = path.join(CWD, 'test'); -const config = { - context: CWD, - entry: { - index: [path.join(SRC, 'index.js')] - }, - output: { - path: BUILD, - filename: '[name].bundle.js', - chunkFilename: '[id].[chunkhash].js' - }, - plugins: [], - resolve: { - modules: [PROJECT_MODULES, BASE_MODULES], - extensions: ['.js', '.json'] - }, - resolveLoader: { - modules: [PROJECT_MODULES, BASE_MODULES] - }, - module: { - rules: [ - { - test: /\.js$/, - include: [SRC], - enforce: 'pre', - use: { - loader: require.resolve('eslint-loader'), - options: lint - } - }, - { - test: /\.js$/, - include: [SRC, TEST], - use: { - loader: require.resolve('babel-loader'), - options: { - presets: [ - [require.resolve('babel-preset-env'), { modules: false, targets: {} }] - ], - plugins: [], - env: { - test: { - plugins: [ - // FIXME: This currently breaks the coverage - //[require.resolve('babel-plugin-istanbul'), { exclude: ['test/**/*'] }] - ] - } - } +const config = new Config(); + +config + .context(CWD) + .entry('index') + .add(path.join(SRC, 'index.js')) + .end() + .output + .path(path.join(process.cwd(), 'build')) + .filename('[name].bundle.js') + .chunkFilename('[id].[chunkhash].js') + .end() + .resolve + .modules + .add(PROJECT_MODULES) + .add(BASE_MODULES) + .end() + .extensions + .add('.js') + .add('json') + .end() + .end() + .resolveLoader + .modules + .add(PROJECT_MODULES) + .add(BASE_MODULES); + +config + .module + .rule('lint') + .test(/\.js$/) + .pre() + .include(SRC) + .loader('eslint', require.resolve('eslint-loader'), Object.assign({ + failOnError: process.env.NODE_ENV !== 'development', + emitWarning: process.env.NODE_ENV !== 'development', + emitError: process.env.NODE_ENV !== 'development' + }, lint)); + +config + .module + .rule('compile') + .test(/\.js$/) + .include(SRC, TEST) + .loader('babel', require.resolve('babel-loader'), { + presets: [ + [require.resolve('babel-preset-env'), { modules: false, targets: {} }] + ], + plugins: [], + env: { + test: { + plugins: [ + // FIXME: This currently breaks the coverage + //[require.resolve('babel-plugin-istanbul'), { exclude: ['test/**/*'] }] + ] } } - } - ] - } -}; - -const eslint = { - emitError: true, - failOnError: true -}; + }); if (process.env.NODE_ENV === 'development') { - config.devtool = 'eval'; - eslint.failOnError = false; - eslint.emitWarning = false; - eslint.emitError = false; + config.devtool('eval'); } else { - // Copy all files except JS files, since they will be Babel-compiled to the output directory. - // This only needs to be done in production since in development assets should be served from the - // webpack-development-server via the source directory. - config.plugins.push( - new CopyPlugin([{ context: SRC, from: `**/*` }], { ignore: ['*.js*'] }), - new ProgressBarPlugin(), - new CleanPlugin([BUILD], { root: CWD }) - ); + config.output.filename('[name].[chunkhash].bundle.js'); - config.output.filename = '[name].[chunkhash].bundle.js'; -} + config + .plugin('copy') + .use(CopyPlugin, [{ context: SRC, from: `**/*` }], { ignore: ['*.js*'] }); -config.plugins.push(new webpack.LoaderOptionsPlugin({ options: { eslint }})); + config + .plugin('progress') + .use(ProgressBarPlugin); + + config + .plugin('clean') + .use(CleanPlugin, [BUILD], { root: CWD }); +} module.exports = config; diff --git a/packages/neutrino-preset-base/yarn.lock b/packages/neutrino-preset-base/yarn.lock index 0fdc020..ffdaa23 100644 --- a/packages/neutrino-preset-base/yarn.lock +++ b/packages/neutrino-preset-base/yarn.lock @@ -18,7 +18,7 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" -acorn@4.0.4, acorn@^4.0.3, acorn@^4.0.4: +acorn@4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" @@ -26,6 +26,10 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" +acorn@^4.0.3, acorn@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.8.tgz#f41e52020ce78118a3c68ed0e9215eb8fc68b5b1" + ajv-keywords@^1.0.0, ajv-keywords@^1.1.1: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" @@ -1097,20 +1101,13 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" -doctrine@1.5.0: +doctrine@1.5.0, doctrine@^1.2.2: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^1.2.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.3.0.tgz#13e75682b55518424276f7c173783456ef913d26" - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" @@ -1274,8 +1271,8 @@ eslint-plugin-mocha@^4.8.0: ramda "^0.22.1" eslint@^3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.14.1.tgz#8a62175f2255109494747a1b25128d97b8eb3d97" + version "3.15.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.15.0.tgz#bdcc6a6c5ffe08160e7b93c066695362a91e30f2" dependencies: babel-code-frame "^6.16.0" chalk "^1.1.3" @@ -1283,7 +1280,7 @@ eslint@^3.14.1: debug "^2.1.1" doctrine "^1.2.2" escope "^3.6.0" - espree "^3.3.1" + espree "^3.4.0" estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" @@ -1312,7 +1309,7 @@ eslint@^3.14.1: text-table "~0.2.0" user-home "^2.0.0" -espree@^3.3.1: +espree@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" dependencies: @@ -3005,6 +3002,10 @@ watchpack@^1.2.0: chokidar "^1.4.3" graceful-fs "^4.1.2" +webpack-chain@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/webpack-chain/-/webpack-chain-1.0.0.tgz#42da40d66e98200ccca3fa274f7fc111b1e1c2c1" + webpack-merge@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-2.6.1.tgz#f1d801d2c5d39f83ffec9f119240b3e3be994a1c" diff --git a/packages/neutrino-preset-node/package.json b/packages/neutrino-preset-node/package.json index 3fcd8f5..31525c5 100644 --- a/packages/neutrino-preset-node/package.json +++ b/packages/neutrino-preset-node/package.json @@ -12,6 +12,7 @@ "repository": "mozilla-neutrino/neutrino-dev", "dependencies": { "babel-runtime": "^6.22.0", + "deepmerge": "^1.3.2", "source-map-support": "^0.4.6", "webpack": "^2.2.1", "webpack-merge": "^2.6.1", diff --git a/packages/neutrino-preset-node/src/index.js b/packages/neutrino-preset-node/src/index.js index 3155fac..c4bc9ba 100644 --- a/packages/neutrino-preset-node/src/index.js +++ b/packages/neutrino-preset-node/src/index.js @@ -1,99 +1,105 @@ 'use strict'; -const merge = require('webpack-merge').smart; -const preset = require('neutrino-preset-base'); +const config = require('neutrino-preset-base'); const nodeExternals = require('webpack-node-externals'); const path = require('path'); const webpack = require('webpack'); +const merge = require('deepmerge'); const MODULES = path.join(__dirname, '../node_modules'); -const config = merge(preset, { - target: 'node', - output: { - filename: '[name].js', - libraryTarget: 'commonjs2' - }, - resolve: { - modules: [MODULES] - }, - resolveLoader: { - modules: [MODULES] - }, - devtool: 'source-map', - node: { - __filename: false, - __dirname: false - }, - plugins: [ - new webpack.LoaderOptionsPlugin({ - options: { - emitError: true, - failOnError: true, - mocha: { - reporter: 'spec', - ui: 'tdd', - bail: true - } - } - }), - new webpack.BannerPlugin({ - banner: 'require("source-map-support").install();', - raw: true, - entryOnly: true - }) - ], - externals: [nodeExternals()], - performance: { - hints: false - } +config + .target('node') + .devtool('source-map') + .externals([nodeExternals()]) + .node + .set('__filename', false) + .set('__dirname', false) + .end() + .output + .filename('[name].js') + .libraryTarget('commonjs2'); + +config.resolve.modules.add(MODULES); +config.resolveLoader.modules.add(MODULES); + +config + .plugin('options') + .use(webpack.LoaderOptionsPlugin, { + emitError: true, + failOnError: true, + mocha: { + reporter: 'spec', + ui: 'tdd', + bail: true + } + }); + +config + .plugin('banner') + .use(webpack.BannerPlugin, { + banner: `require('source-map-support').install();`, + raw: true, + entryOnly: true + }); + +config.options.set('performance', { + hints: false }); -const babelLoader = config.module.rules.find(r => r.use && r.use.loader && r.use.loader.includes('babel')); - -// Polyfill based on Node.js LTS 6.9.0 -babelLoader.use.options.presets[0][1].targets.node = 6.9; - -const eslintLoader = config.module.rules.find(r => r.use && r.use.loader && r.use.loader.includes('eslint')); +config.module + .rule('compile') + .loader('babel', ({ options }) => { + options.presets[0][1].targets.node = 6.9; -eslintLoader.use.options.env.node = true; + return { options }; + }); -Object.assign(eslintLoader.use.options.rules, { - // enforce return after a callback - 'callback-return': 'off', +config.module + .rule('lint') + .loader('eslint', ({ options }) => { + return { + options: merge(options, { + envs: ['node'], + rules: { + // enforce return after a callback + 'callback-return': 'off', - // require all requires be top-level - // http://eslint.org/docs/rules/global-require - 'global-require': 'error', + // require all requires be top-level + // http://eslint.org/docs/rules/global-require + 'global-require': 'error', - // enforces error handling in callbacks (node environment) - 'handle-callback-err': 'off', + // enforces error handling in callbacks (node environment) + 'handle-callback-err': 'off', - // Allow console in Node.js - 'no-console': 'off', + // Allow console in Node.js + 'no-console': 'off', - // disallow mixing regular variable and require declarations - 'no-mixed-requires': ['off', false], + // disallow mixing regular variable and require declarations + 'no-mixed-requires': ['off', false], - // disallow use of new operator with the require function - 'no-new-require': 'error', + // disallow use of new operator with the require function + 'no-new-require': 'error', - // disallow string concatenation with __dirname and __filename - // http://eslint.org/docs/rules/no-path-concat - 'no-path-concat': 'error', + // disallow string concatenation with __dirname and __filename + // http://eslint.org/docs/rules/no-path-concat + 'no-path-concat': 'error', - // disallow use of process.env - 'no-process-env': 'off', + // disallow use of process.env + 'no-process-env': 'off', - // disallow process.exit() - 'no-process-exit': 'off', + // disallow process.exit() + 'no-process-exit': 'off', - // restrict usage of specified node modules - 'no-restricted-modules': 'off', + // restrict usage of specified node modules + 'no-restricted-modules': 'off', - // disallow use of synchronous methods (off by default) - 'no-sync': 'off' -}); + // disallow use of synchronous methods (off by default) + 'no-sync': 'off' + } + }) + }; + }); module.exports = config; diff --git a/packages/neutrino-preset-node/yarn.lock b/packages/neutrino-preset-node/yarn.lock index 47452b8..311ed12 100644 --- a/packages/neutrino-preset-node/yarn.lock +++ b/packages/neutrino-preset-node/yarn.lock @@ -450,6 +450,10 @@ deep-extend@~0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" +deepmerge@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.3.2.tgz#1663691629d4dbfe364fa12a2a4f0aa86aa3a050" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" diff --git a/packages/neutrino-preset-react/src/index.js b/packages/neutrino-preset-react/src/index.js index c543cb6..8928089 100644 --- a/packages/neutrino-preset-react/src/index.js +++ b/packages/neutrino-preset-react/src/index.js @@ -1,62 +1,75 @@ 'use strict'; -const preset = require('neutrino-preset-web'); +const config = require('neutrino-preset-web'); const merge = require('deepmerge'); -const webpackMerge = require('webpack-merge').smart; const path = require('path'); const webpack = require('webpack'); const MODULES = path.join(__dirname, '../node_modules'); -const eslintLoader = preset.module.rules.find(r => r.use && r.use.loader && r.use.loader.includes('eslint')); -const babelLoader = preset.module.rules.find(r => r.use && r.use.loader && r.use.loader.includes('babel')); - -eslintLoader.test = /\.jsx?$/; -babelLoader.test = /\.jsx?$/; -babelLoader.use.options.presets.push(require.resolve('babel-preset-stage-0')); -babelLoader.use.options.presets.push(require.resolve('babel-preset-react')); - -eslintLoader.use.options = merge(eslintLoader.use.options, { - plugins: ['react'], - extends: [ - 'plugin:react/recommended' - ], - settings: { - pragma: 'React', - version: '15.0' - }, - parserOptions: { - ecmaFeatures: { - experimentalObjectRestSpread: true, - jsx: true + +// modify lint rule and loader +config.module + .rule('lint') + .test(/\.jsx?$/) + .loader('eslint', ({ options }) => { + return { + options: merge(options, { + plugins: ['react'], + baseConfig: { + extends: ['plugin:react/recommended'] + }, + parserOptions: { + ecmaFeatures: { + experimentalObjectRestSpread: true + } + }, + rules: { + 'react/prop-types': ['off'], + 'jsx-quotes': ['error', 'prefer-double'] + } + }) + }; + }); + +// modify babel rule and loader +config.module + .rule('compile') + .test(/\.jsx?$/) + .loader('babel', ({ options }) => { + if (process.env.NODE_ENV === 'development') { + options.plugins.push(require.resolve('react-hot-loader/babel')); } - }, - rules: { - 'react/prop-types': ['off'], - - // specify whether double or single quotes should be used in JSX attributes - // http://eslint.org/docs/rules/jsx-quotes - 'jsx-quotes': ['error', 'prefer-double'] - } -}); - -const config = webpackMerge(preset, { - resolve: { - modules: [MODULES], - extensions: ['.jsx'] - }, - resolveLoader: { - modules: [MODULES] - }, - externals: { + + return { + options: merge(options, { + presets: [ + require.resolve('babel-preset-stage-0'), + require.resolve('babel-preset-react') + ] + }) + }; + }); + +config.resolve + .modules + .add(MODULES) + .end() + .extensions + .add('.jsx'); + +config.resolveLoader.modules.add(MODULES); + +config + .externals({ 'react/addons': true, 'react/lib/ExecutionEnvironment': true, 'react/lib/ReactContext': 'window' - } -}); + }); if (process.env.NODE_ENV === 'development') { - config.entry.index.unshift(require.resolve('react-hot-loader/patch')); - babelLoader.use.options.plugins.push(require.resolve('react-hot-loader/babel')); + config + .entry('index') + .add(require.resolve('react-hot-loader/patch')); } module.exports = config; diff --git a/packages/neutrino-preset-web/src/index.js b/packages/neutrino-preset-web/src/index.js index 3704bc3..eec3500 100644 --- a/packages/neutrino-preset-web/src/index.js +++ b/packages/neutrino-preset-web/src/index.js @@ -4,9 +4,8 @@ const exists = require('exists-file'); const webpack = require('webpack'); const HtmlPlugin = require('html-webpack-plugin'); const merge = require('deepmerge'); -const preset = require('neutrino-preset-base'); +const config = require('neutrino-preset-base'); const path = require('path'); -const webpackMerge = require('webpack-merge').smart; const CWD = process.cwd(); const SRC = path.join(CWD, 'src'); @@ -34,122 +33,116 @@ function findTemplate() { return PROJECT_TEMPLATE; } -const config = webpackMerge(preset, { - target: 'web', - node: { - console: false, - global: true, - process: true, - Buffer: true, - __filename: 'mock', - __dirname: 'mock', - setImmediate: true, - fs: 'empty', - tls: 'empty' - }, - output: { - publicPath: './' - }, - plugins: [ - new webpack.EnvironmentPlugin(['NODE_ENV']), - new HtmlPlugin({ - template: findTemplate(), - inject: 'body', - xhtml: true - }) - ], - resolve: { - modules: [MODULES] - }, - resolveLoader: { - modules: [MODULES] - }, - module: { - rules: [ - { - test: /\.html$/, - use: { - loader: FILE_LOADER, - options: { - name: '[name].[ext]' - } - } - }, - { - test: /\.css$/, - loaders: [STYLE_LOADER, CSS_LOADER] - }, - { - test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, - use: { - loader: URL_LOADER, - options: { - limit: 10000, - mimetype: 'application/font-woff' - } - } - }, - { - test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, - use: { - loader: URL_LOADER, - options: { - limit: '10000', - mimetype: 'application/octet-stream' - } - } - }, - { - test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, - use: FILE_LOADER - }, - { - test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, - use: { - loader: URL_LOADER, - options: { - limit: '10000', - mimetype: 'application/svg+xml' - } - } - }, - { - test: /\.(png|jpg)$/, - use: { - loader: URL_LOADER, - options: { - limit: 8192 - } - } - }, - { - test: /\.ico(\?v=\d+\.\d+\.\d+)?$/, - use: URL_LOADER - } - ] - } -}); +config.target('web'); +config.output.publicPath('./'); +config.resolve.modules.add(MODULES); +config.resolveLoader.modules.add(MODULES); -const babelLoader = config.module.rules.find(r => r.use && r.use.loader && r.use.loader.includes('babel')); +config.node + .set('console', false) + .set('global', true) + .set('process', true) + .set('Buffer', true) + .set('__filename', 'mock') + .set('__dirname', 'mock') + .set('setImmediate', true) + .set('fs', 'empty') + .set('tls', 'empty'); -// Polyfill based on last 2 major browser versions -babelLoader.use.options.presets[0][1].targets.browsers = ['last 2 versions']; +config.module + .rule('html') + .test(/\.html$/) + .loader('file', FILE_LOADER, { + name: '[name].[ext]' + }); -const eslintLoader = config.module.rules.find(r => r.use && r.use.loader && r.use.loader.includes('eslint')); +config.module + .rule('css') + .test(/\.css$/) + .loader('style', STYLE_LOADER) + .loader('css', CSS_LOADER); -eslintLoader.use.options = merge(eslintLoader.use.options, { - globals: ['Buffer'], - env: { - browser: true, - commonjs: true - } -}); +config.module + .rule('woff') + .test(/\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/) + .loader('url', URL_LOADER, { + limit: '10000', + mimetype: 'application/font-woff' + }); + +config.module + .rule('ttf') + .test(/\.ttf(\?v=\d+\.\d+\.\d+)?$/) + .loader('url', URL_LOADER, { + limit: '10000', + mimetype: 'application/octet-stream' + }); + +config.module + .rule('eot') + .test(/\.eot(\?v=\d+\.\d+\.\d+)?$/) + .loader('file', FILE_LOADER); + +config.module + .rule('svg') + .test(/\.svg(\?v=\d+\.\d+\.\d+)?$/) + .loader('url', URL_LOADER, { + limit: '10000', + mimetype: 'application/svg+xml' + }); + +config.module + .rule('img') + .test(/\.(png|jpg)$/) + .loader('url', URL_LOADER, { + limit: 8192 + }); + +config.module + .rule('ico') + .test(/\.ico(\?v=\d+\.\d+\.\d+)?$/) + .loader('url', URL_LOADER); + +// modify the babel loader +config.module + .rule('compile') + .loader('babel', ({ options }) => { + options.presets[0][1].targets.browsers = ['last 2 versions']; + + return { options }; + }); + +// modify the lint loader +config.module + .rule('lint') + .loader('eslint', ({ options }) => { + return { + options: merge(options, { + globals: ['Buffer'], + envs: ['browser', 'commonjs'] + }) + }; + }); + +config + .plugin('env') + .use(webpack.EnvironmentPlugin, ['NODE_ENV']); + +config + .plugin('html') + .use(HtmlPlugin, { + template: findTemplate(), + inject: 'body', + xhtml: true + }); if (process.env.NODE_ENV !== 'test') { - config.plugins.push(new webpack.optimize.CommonsChunkPlugin({ - names: ['vendor', 'manifest'], - minChunks: Infinity - })); + config + .plugin('chunk') + .use(webpack.optimize.CommonsChunkPlugin, { + names: ['vendor', 'manifest'], + minChunks: Infinity + }); } if (process.env.NODE_ENV === 'development') { @@ -157,67 +150,82 @@ if (process.env.NODE_ENV === 'development') { const host = process.env.HOST || 'localhost'; const port = parseInt(process.env.PORT) || 5000; - config.devServer = { - host, - port, - https: protocol === 'https', - contentBase: SRC, - // Enable history API fallback so HTML5 History API based - // routing works. This is a good default that will come - // in handy in more complicated setups. - historyApiFallback: true, - stats: { - colors: true, - chunks: false, - version: false, + config + .devServer + .host(host) + .port(port) + .https(protocol === 'https') + .contentBase(SRC) + .historyApiFallback(true) + .stats({ assets: false, - modules: false, children: false, - source: false - } - }; + chunks: false, + colors: true, + errors: true, + errorDetails: true, + hash: false, + modules: false, + publicPath: false, + timings: false, + version: false, + warnings: true + }); + + config + .entry('index') + .add(`webpack-dev-server/client?${protocol}://${host}:${port}/`) + .add('webpack/hot/dev-server'); - config.entry.index.push(`webpack-dev-server/client?${protocol}://${host}:${port}/`); - config.entry.index.push(`webpack/hot/dev-server`); - config.plugins.push(new webpack.HotModuleReplacementPlugin()); + config + .plugin('hot') + .use(webpack.HotModuleReplacementPlugin); } else if (process.env.NODE_ENV === 'production') { - config.plugins.push( - new webpack.optimize.UglifyJsPlugin({ sourceMap: false, compress: { warnings: false }}), - new webpack.LoaderOptionsPlugin({ minimize: true }) - ); + config + .plugin('minify') + .use(webpack.optimize.UglifyJsPlugin, { + sourceMap: false, + compress: { warnings: false } + }); + + config + .plugin('minimize') + .use(webpack.LoaderOptionsPlugin, { minimize: true }); } else if (process.env.NODE_ENV === 'test') { - config.karma = { - plugins: [ - require.resolve('karma-webpack'), - require.resolve('karma-chrome-launcher'), - require.resolve('karma-coverage'), - require.resolve('karma-mocha'), - require.resolve('karma-mocha-reporter') - ], - basePath: process.cwd(), - browsers: [process.env.CI ? 'ChromeCI' : 'Chrome'], - customLaunchers: { - ChromeCI: { - base: 'Chrome', - flags: ['--no-sandbox'] + config + .options + .set('karma', { + plugins: [ + require.resolve('karma-webpack'), + require.resolve('karma-chrome-launcher'), + require.resolve('karma-coverage'), + require.resolve('karma-mocha'), + require.resolve('karma-mocha-reporter') + ], + basePath: process.cwd(), + browsers: [process.env.CI ? 'ChromeCI' : 'Chrome'], + customLaunchers: { + ChromeCI: { + base: 'Chrome', + flags: ['--no-sandbox'] + } + }, + frameworks: ['mocha'], + files: ['test/**/*_test.js'], + preprocessors: { + 'test/**/*_test.js': ['webpack'], + 'src/**/*.js': ['webpack'] + }, + webpackMiddleware: { noInfo: true }, + reporters: ['mocha', 'coverage'], + coverageReporter: { + dir: '.coverage', + reporters: [ + { type: 'html', subdir: 'report-html' }, + { type: 'lcov', subdir: 'report-lcov' } + ] } - }, - frameworks: ['mocha'], - files: ['test/**/*_test.js'], - preprocessors: { - 'test/**/*_test.js': ['webpack'], - 'src/**/*.js': ['webpack'] - }, - webpackMiddleware: { noInfo: true }, - reporters: ['mocha', 'coverage'], - coverageReporter: { - dir: '.coverage', - reporters: [ - { type: 'html', subdir: 'report-html' }, - { type: 'lcov', subdir: 'report-lcov' } - ] - } - }; + }); } module.exports = config; diff --git a/packages/neutrino-preset-web/yarn.lock b/packages/neutrino-preset-web/yarn.lock index ffb445c..c4f49c3 100644 --- a/packages/neutrino-preset-web/yarn.lock +++ b/packages/neutrino-preset-web/yarn.lock @@ -523,8 +523,8 @@ clap@^1.0.9: chalk "^1.1.3" clean-css@4.0.x: - version "4.0.3" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.0.3.tgz#9da7b59301d940c345757f175e6dfa6872c7de8e" + version "4.0.4" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.0.4.tgz#629896cc364f3c3d00b9908ee60dd18e4c6c6462" dependencies: source-map "0.5.x" @@ -1435,7 +1435,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@7.0.5, glob@^7.0.5: +glob@7.0.5: version "7.0.5" resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95" dependencies: @@ -1456,7 +1456,7 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1: +glob@^7.0.5, glob@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: diff --git a/packages/neutrino/src/get-preset.js b/packages/neutrino/src/get-preset.js index ef84686..2873828 100644 --- a/packages/neutrino/src/get-preset.js +++ b/packages/neutrino/src/get-preset.js @@ -26,11 +26,13 @@ module.exports = (preset) => { // try requiring it as relative to the project for (let i = 0; i < modules.length; i++) { try { - const config = require(modules[i]); + const module = require(modules[i]); + const core = 'toConfig' in module ? module.toConfig() : module; + const config = pkg.config && pkg.config.neutrino ? + merge(core, pkg.config.neutrino) : + core; - return pkg.config && pkg.config.neutrino ? - merge(config, pkg.config.neutrino) : - config; + return config; } catch (err) { if (!/Cannot find module/.test(err.message)) { throw err; diff --git a/packages/neutrino/yarn.lock b/packages/neutrino/yarn.lock index 7f005c6..76a161e 100644 --- a/packages/neutrino/yarn.lock +++ b/packages/neutrino/yarn.lock @@ -805,7 +805,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@2.2.0, debug@^2.0.0, debug@^2.1.1, debug@~2.2.0: +debug@2.2.0, debug@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: @@ -817,7 +817,7 @@ debug@2.3.3: dependencies: ms "0.7.2" -debug@2.6.0, debug@^2.2.0: +debug@2.6.0, debug@^2.0.0, debug@^2.1.1, debug@^2.2.0: version "2.6.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" dependencies: @@ -2149,10 +2149,14 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.1.0, object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" @@ -2947,7 +2951,7 @@ strip-json-comments@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" -supports-color@3.1.2, supports-color@^3.1.0, supports-color@^3.1.1: +supports-color@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" dependencies: @@ -2961,6 +2965,12 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" +supports-color@^3.1.0, supports-color@^3.1.1: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + swap-case@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3"