summaryrefslogtreecommitdiff
path: root/config
diff options
context:
space:
mode:
authorClement Ho <clemmakesapps@gmail.com>2018-05-07 19:46:42 +0000
committerClement Ho <clemmakesapps@gmail.com>2018-05-07 19:46:42 +0000
commit797a080681233e97ccc0c9ba72431e4b450fff7b (patch)
tree4bbfcc9c05c033e28c5b8126a09489982b5b1603 /config
parentec970e8a3f060986d4e2c0da724c15f6b34587d7 (diff)
parentcaf49264b47999a5b888a3ada3b70cc76e94d2bd (diff)
downloadgitlab-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.rb2
-rw-r--r--config/karma.config.js21
-rw-r--r--config/webpack.config.js181
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());
}