diff options
author | Clement Ho <clemmakesapps@gmail.com> | 2018-05-07 19:46:42 +0000 |
---|---|---|
committer | Clement Ho <clemmakesapps@gmail.com> | 2018-05-07 19:46:42 +0000 |
commit | 797a080681233e97ccc0c9ba72431e4b450fff7b (patch) | |
tree | 4bbfcc9c05c033e28c5b8126a09489982b5b1603 /config | |
parent | ec970e8a3f060986d4e2c0da724c15f6b34587d7 (diff) | |
parent | caf49264b47999a5b888a3ada3b70cc76e94d2bd (diff) | |
download | gitlab-ce-797a080681233e97ccc0c9ba72431e4b450fff7b.tar.gz |
Merge branch 'upgrade-to-webpack-v4' into 'master'
Upgrade to Webpack 4
Closes #43400
See merge request gitlab-org/gitlab-ce!17218
Diffstat (limited to 'config')
-rw-r--r-- | config/initializers/static_files.rb | 2 | ||||
-rw-r--r-- | config/karma.config.js | 21 | ||||
-rw-r--r-- | config/webpack.config.js | 181 |
3 files changed, 89 insertions, 115 deletions
diff --git a/config/initializers/static_files.rb b/config/initializers/static_files.rb index d3a7a2b9f8b..6c28686e69a 100644 --- a/config/initializers/static_files.rb +++ b/config/initializers/static_files.rb @@ -34,7 +34,7 @@ if app.config.serve_static_files ) app.config.middleware.insert_before( Gitlab::Middleware::Static, - Gitlab::Middleware::WebpackProxy, + Gitlab::Webpack::DevServerMiddleware, proxy_path: app.config.webpack.public_path, proxy_host: dev_server.host, proxy_port: dev_server.port diff --git a/config/karma.config.js b/config/karma.config.js index 3eb220eed99..28a688797d9 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -12,16 +12,14 @@ function fatalError(message) { process.exit(1); } -// remove problematic plugins -if (webpackConfig.plugins) { - webpackConfig.plugins = webpackConfig.plugins.filter(function(plugin) { - return !( - plugin instanceof webpack.optimize.CommonsChunkPlugin || - plugin instanceof webpack.optimize.ModuleConcatenationPlugin || - plugin instanceof webpack.DefinePlugin - ); - }); -} +// disable problematic options +webpackConfig.entry = undefined; +webpackConfig.mode = 'development'; +webpackConfig.optimization.runtimeChunk = false; +webpackConfig.optimization.splitChunks = false; + +// use quicker sourcemap option +webpackConfig.devtool = 'cheap-inline-source-map'; const specFilters = argumentsParser .option( @@ -77,9 +75,6 @@ if (specFilters.length) { ); } -webpackConfig.entry = undefined; -webpackConfig.devtool = 'cheap-inline-source-map'; - // Karma configuration module.exports = function(config) { process.env.TZ = 'Etc/UTC'; diff --git a/config/webpack.config.js b/config/webpack.config.js index b9d098ff9b9..5096f35e808 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -1,4 +1,3 @@ -const crypto = require('crypto'); const fs = require('fs'); const path = require('path'); const glob = require('glob'); @@ -6,9 +5,7 @@ const webpack = require('webpack'); const StatsWriterPlugin = require('webpack-stats-plugin').StatsWriterPlugin; const CopyWebpackPlugin = require('copy-webpack-plugin'); const CompressionPlugin = require('compression-webpack-plugin'); -const NameAllModulesPlugin = require('name-all-modules-plugin'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; -const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); const ROOT_PATH = path.resolve(__dirname, '..'); const IS_PRODUCTION = process.env.NODE_ENV === 'production'; @@ -21,10 +18,12 @@ const NO_COMPRESSION = process.env.NO_COMPRESSION; let autoEntriesCount = 0; let watchAutoEntries = []; +const defaultEntries = ['./main']; function generateEntries() { // generate automatic entry points const autoEntries = {}; + const autoEntriesMap = {}; const pageEntries = glob.sync('pages/**/index.js', { cwd: path.join(ROOT_PATH, 'app/assets/javascripts'), }); @@ -33,25 +32,38 @@ function generateEntries() { function generateAutoEntries(path, prefix = '.') { const chunkPath = path.replace(/\/index\.js$/, ''); const chunkName = chunkPath.replace(/\//g, '.'); - autoEntries[chunkName] = `${prefix}/${path}`; + autoEntriesMap[chunkName] = `${prefix}/${path}`; } pageEntries.forEach(path => generateAutoEntries(path)); - autoEntriesCount = Object.keys(autoEntries).length; + const autoEntryKeys = Object.keys(autoEntriesMap); + autoEntriesCount = autoEntryKeys.length; + + // import ancestor entrypoints within their children + autoEntryKeys.forEach(entry => { + const entryPaths = [autoEntriesMap[entry]]; + const segments = entry.split('.'); + while (segments.pop()) { + const ancestor = segments.join('.'); + if (autoEntryKeys.includes(ancestor)) { + entryPaths.unshift(autoEntriesMap[ancestor]); + } + } + autoEntries[entry] = defaultEntries.concat(entryPaths); + }); const manualEntries = { - common: './commons/index.js', - main: './main.js', + default: defaultEntries, raven: './raven/index.js', - webpack_runtime: './webpack.js', - ide: './ide/index.js', }; return Object.assign(manualEntries, autoEntries); } const config = { + mode: IS_PRODUCTION ? 'production' : 'development', + context: path.join(ROOT_PATH, 'app/assets/javascripts'), entry: generateEntries, @@ -59,8 +71,36 @@ const config = { output: { path: path.join(ROOT_PATH, 'public/assets/webpack'), publicPath: '/assets/webpack/', - filename: IS_PRODUCTION ? '[name].[chunkhash].bundle.js' : '[name].bundle.js', - chunkFilename: IS_PRODUCTION ? '[name].[chunkhash].chunk.js' : '[name].chunk.js', + filename: IS_PRODUCTION ? '[name].[chunkhash:8].bundle.js' : '[name].bundle.js', + chunkFilename: IS_PRODUCTION ? '[name].[chunkhash:8].chunk.js' : '[name].chunk.js', + globalObject: 'this', // allow HMR and web workers to play nice + }, + + optimization: { + nodeEnv: false, + runtimeChunk: 'single', + splitChunks: { + maxInitialRequests: 4, + cacheGroups: { + default: false, + common: () => ({ + priority: 20, + name: 'main', + chunks: 'initial', + minChunks: autoEntriesCount * 0.9, + }), + vendors: { + priority: 10, + chunks: 'async', + test: /[\\/](node_modules|vendor[\\/]assets[\\/]javascripts)[\\/]/, + }, + commons: { + chunks: 'all', + minChunks: 2, + reuseExistingChunk: true, + }, + }, + }, }, module: { @@ -92,10 +132,10 @@ const config = { { loader: 'worker-loader', options: { - inline: true, + name: '[name].[hash:8].worker.js', }, }, - { loader: 'babel-loader' }, + 'babel-loader', ], }, { @@ -103,7 +143,7 @@ const config = { exclude: /node_modules/, loader: 'file-loader', options: { - name: '[name].[hash].[ext]', + name: '[name].[hash:8].[ext]', }, }, { @@ -114,7 +154,7 @@ const config = { { loader: 'css-loader', options: { - name: '[name].[hash].[ext]', + name: '[name].[hash:8].[ext]', }, }, ], @@ -124,7 +164,7 @@ const config = { include: /node_modules\/katex\/dist\/fonts/, loader: 'file-loader', options: { - name: '[name].[hash].[ext]', + name: '[name].[hash:8].[ext]', }, }, { @@ -166,54 +206,6 @@ const config = { jQuery: 'jquery', }), - // assign deterministic module ids - new webpack.NamedModulesPlugin(), - new NameAllModulesPlugin(), - - // assign deterministic chunk ids - new webpack.NamedChunksPlugin(chunk => { - if (chunk.name) { - return chunk.name; - } - - const moduleNames = []; - - function collectModuleNames(m) { - // handle ConcatenatedModule which does not have resource nor context set - if (m.modules) { - m.modules.forEach(collectModuleNames); - return; - } - - const pagesBase = path.join(ROOT_PATH, 'app/assets/javascripts/pages'); - - if (m.resource.indexOf(pagesBase) === 0) { - moduleNames.push( - path - .relative(pagesBase, m.resource) - .replace(/\/index\.[a-z]+$/, '') - .replace(/\//g, '__') - ); - } else { - moduleNames.push(path.relative(m.context, m.resource)); - } - } - - chunk.forEachModule(collectModuleNames); - - const hash = crypto - .createHash('sha256') - .update(moduleNames.join('_')) - .digest('hex'); - - return `${moduleNames[0]}-${hash.substr(0, 6)}`; - }), - - // create cacheable common library bundles - new webpack.optimize.CommonsChunkPlugin({ - names: ['main', 'common', 'webpack_runtime'], - }), - // copy pre-compiled vendor libraries verbatim new CopyWebpackPlugin([ { @@ -260,20 +252,6 @@ const config = { if (IS_PRODUCTION) { config.devtool = 'source-map'; - config.plugins.push( - new webpack.NoEmitOnErrorsPlugin(), - new webpack.LoaderOptionsPlugin({ - minimize: true, - debug: false, - }), - new webpack.optimize.ModuleConcatenationPlugin(), - new webpack.optimize.UglifyJsPlugin({ - sourceMap: true, - }), - new webpack.DefinePlugin({ - 'process.env': { NODE_ENV: JSON.stringify('production') }, - }) - ); // compression can require a lot of compute time and is disabled in CI if (!NO_COMPRESSION) { @@ -292,29 +270,30 @@ if (IS_DEV_SERVER) { hot: DEV_SERVER_LIVERELOAD, inline: DEV_SERVER_LIVERELOAD, }; - config.plugins.push( - // watch node_modules for changes if we encounter a missing module compile error - new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules')), - - // watch for changes to our automatic entry point modules - { - apply(compiler) { - compiler.plugin('emit', (compilation, callback) => { - compilation.contextDependencies = [ - ...compilation.contextDependencies, - ...watchAutoEntries, - ]; - - // report our auto-generated bundle count - console.log( - `${autoEntriesCount} entries from '/pages' automatically added to webpack output.` - ); - - callback(); - }); - }, - } - ); + config.plugins.push({ + apply(compiler) { + compiler.hooks.emit.tapAsync('WatchForChangesPlugin', (compilation, callback) => { + const missingDeps = Array.from(compilation.missingDependencies); + const nodeModulesPath = path.join(ROOT_PATH, 'node_modules'); + const hasMissingNodeModules = missingDeps.some( + file => file.indexOf(nodeModulesPath) !== -1 + ); + + // watch for changes to missing node_modules + if (hasMissingNodeModules) compilation.contextDependencies.add(nodeModulesPath); + + // watch for changes to automatic entrypoints + watchAutoEntries.forEach(watchPath => compilation.contextDependencies.add(watchPath)); + + // report our auto-generated bundle count + console.log( + `${autoEntriesCount} entries from '/pages' automatically added to webpack output.` + ); + + callback(); + }); + }, + }); if (DEV_SERVER_LIVERELOAD) { config.plugins.push(new webpack.HotModuleReplacementPlugin()); } |