summaryrefslogtreecommitdiff
path: root/config
diff options
context:
space:
mode:
Diffstat (limited to 'config')
-rw-r--r--config/application.rb1
-rw-r--r--config/initializers/8_metrics.rb9
-rw-r--r--config/initializers/console_message.rb10
-rw-r--r--config/initializers/forbid_sidekiq_in_transactions.rb2
-rw-r--r--config/initializers/session_store.rb26
-rw-r--r--config/initializers/static_files.rb2
-rw-r--r--config/initializers/trusted_proxies.rb13
-rw-r--r--config/initializers/warden.rb16
-rw-r--r--config/karma.config.js92
-rw-r--r--config/prometheus/additional_metrics.yml12
-rw-r--r--config/routes/group.rb7
-rw-r--r--config/routes/profile.rb1
-rw-r--r--config/routes/project.rb9
-rw-r--r--config/routes/repository.rb1
-rw-r--r--config/routes/user.rb7
-rw-r--r--config/sidekiq_queues.yml3
-rw-r--r--config/webpack.config.js184
17 files changed, 241 insertions, 154 deletions
diff --git a/config/application.rb b/config/application.rb
index ad7338763f7..09f706e3d70 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -115,6 +115,7 @@ module Gitlab
config.assets.precompile << "test.css"
config.assets.precompile << "snippets.css"
config.assets.precompile << "locale/**/app.js"
+ config.assets.precompile << "emoji_sprites.css"
# Import gitlab-svgs directly from vendored directory
config.assets.paths << "#{config.root}/node_modules/@gitlab-org/gitlab-svgs/dist"
diff --git a/config/initializers/8_metrics.rb b/config/initializers/8_metrics.rb
index 7cdf49159b4..8a851b89c56 100644
--- a/config/initializers/8_metrics.rb
+++ b/config/initializers/8_metrics.rb
@@ -119,7 +119,14 @@ def instrument_classes(instrumentation)
end
# rubocop:enable Metrics/AbcSize
-if Gitlab::Metrics.enabled?
+# With prometheus enabled by default this breaks all specs
+# that stubs methods using `any_instance_of` for the models reloaded here.
+#
+# We should deprecate the usage of `any_instance_of` in the future
+# check: https://github.com/rspec/rspec-mocks#settings-mocks-or-stubs-on-any-instance-of-a-class
+#
+# Related issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/33587
+if Gitlab::Metrics.enabled? && !Rails.env.test?
require 'pathname'
require 'influxdb'
require 'connection_pool'
diff --git a/config/initializers/console_message.rb b/config/initializers/console_message.rb
new file mode 100644
index 00000000000..536ab337d85
--- /dev/null
+++ b/config/initializers/console_message.rb
@@ -0,0 +1,10 @@
+# rubocop:disable Rails/Output
+if defined?(Rails::Console)
+ # note that this will not print out when using `spring`
+ justify = 15
+ puts "-------------------------------------------------------------------------------------"
+ puts " Gitlab:".ljust(justify) + "#{Gitlab::VERSION} (#{Gitlab::REVISION})"
+ puts " Gitlab Shell:".ljust(justify) + Gitlab::Shell.new.version
+ puts " #{Gitlab::Database.adapter_name}:".ljust(justify) + Gitlab::Database.version
+ puts "-------------------------------------------------------------------------------------"
+end
diff --git a/config/initializers/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb
index 4603123665d..deb94d7dbce 100644
--- a/config/initializers/forbid_sidekiq_in_transactions.rb
+++ b/config/initializers/forbid_sidekiq_in_transactions.rb
@@ -27,7 +27,7 @@ module Sidekiq
Use an `after_commit` hook, or include `AfterCommitQueue` and use a `run_after_commit` block instead.
MSG
rescue Sidekiq::Worker::EnqueueFromTransactionError => e
- Rails.logger.error(e.message) if Rails.env.production?
+ ::Rails.logger.error(e.message) if ::Rails.env.production?
Gitlab::Sentry.track_exception(e)
end
end
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index f2fde1e0048..da24881885e 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -15,19 +15,15 @@ cookie_key = if Rails.env.development?
"_gitlab_session"
end
-if Rails.env.test?
- Gitlab::Application.config.session_store :cookie_store, key: "_gitlab_session"
-else
- sessions_config = Gitlab::Redis::SharedState.params
- sessions_config[:namespace] = Gitlab::Redis::SharedState::SESSION_NAMESPACE
+sessions_config = Gitlab::Redis::SharedState.params
+sessions_config[:namespace] = Gitlab::Redis::SharedState::SESSION_NAMESPACE
- Gitlab::Application.config.session_store(
- :redis_store, # Using the cookie_store would enable session replay attacks.
- servers: sessions_config,
- key: cookie_key,
- secure: Gitlab.config.gitlab.https,
- httponly: true,
- expires_in: Settings.gitlab['session_expire_delay'] * 60,
- path: Rails.application.config.relative_url_root.nil? ? '/' : Gitlab::Application.config.relative_url_root
- )
-end
+Gitlab::Application.config.session_store(
+ :redis_store, # Using the cookie_store would enable session replay attacks.
+ servers: sessions_config,
+ key: cookie_key,
+ secure: Gitlab.config.gitlab.https,
+ httponly: true,
+ expires_in: Settings.gitlab['session_expire_delay'] * 60,
+ path: Rails.application.config.relative_url_root.nil? ? '/' : Gitlab::Application.config.relative_url_root
+)
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/initializers/trusted_proxies.rb b/config/initializers/trusted_proxies.rb
index 0c32528311e..ca2eed664ed 100644
--- a/config/initializers/trusted_proxies.rb
+++ b/config/initializers/trusted_proxies.rb
@@ -22,3 +22,16 @@ end.compact
Rails.application.config.action_dispatch.trusted_proxies = (
['127.0.0.1', '::1'] + gitlab_trusted_proxies)
+
+# A monkey patch to make trusted proxies work with Rails 5.0.
+# Inspired by https://github.com/rails/rails/issues/5223#issuecomment-263778719
+# Remove this monkey patch when upstream is fixed.
+if Gitlab.rails5?
+ module TrustedProxyMonkeyPatch
+ def ip
+ @ip ||= (get_header("action_dispatch.remote_ip") || super).to_s
+ end
+ end
+
+ ActionDispatch::Request.send(:include, TrustedProxyMonkeyPatch)
+end
diff --git a/config/initializers/warden.rb b/config/initializers/warden.rb
index ee034d21eae..8cc36820d3c 100644
--- a/config/initializers/warden.rb
+++ b/config/initializers/warden.rb
@@ -1,9 +1,21 @@
Rails.application.configure do |config|
- Warden::Manager.after_set_user do |user, auth, opts|
+ Warden::Manager.after_set_user(scope: :user) do |user, auth, opts|
Gitlab::Auth::UniqueIpsLimiter.limit_user!(user)
end
- Warden::Manager.before_failure do |env, opts|
+ Warden::Manager.before_failure(scope: :user) do |env, opts|
Gitlab::Auth::BlockedUserTracker.log_if_user_blocked(env)
end
+
+ Warden::Manager.after_authentication(scope: :user) do |user, auth, opts|
+ ActiveSession.cleanup(user)
+ end
+
+ Warden::Manager.after_set_user(scope: :user, only: :fetch) do |user, auth, opts|
+ ActiveSession.set(user, auth.request)
+ end
+
+ Warden::Manager.before_logout(scope: :user) do |user, auth, opts|
+ ActiveSession.destroy(user || auth.user, auth.request.session.id)
+ end
end
diff --git a/config/karma.config.js b/config/karma.config.js
index 691cda98861..28a688797d9 100644
--- a/config/karma.config.js
+++ b/config/karma.config.js
@@ -1,47 +1,87 @@
-var path = require('path');
-var webpack = require('webpack');
-var argumentsParser = require('commander');
-var webpackConfig = require('./webpack.config.js');
-var ROOT_PATH = path.resolve(__dirname, '..');
-
-// 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
- );
- });
+const path = require('path');
+const glob = require('glob');
+const chalk = require('chalk');
+const webpack = require('webpack');
+const argumentsParser = require('commander');
+const webpackConfig = require('./webpack.config.js');
+
+const ROOT_PATH = path.resolve(__dirname, '..');
+
+function fatalError(message) {
+ console.error(chalk.red(`\nError: ${message}\n`));
+ process.exit(1);
}
-var testFiles = argumentsParser
+// 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(
'-f, --filter-spec [filter]',
'Filter run spec files by path. Multiple filters are like a logical OR.',
- (val, memo) => {
- memo.push(val);
+ (filter, memo) => {
+ memo.push(filter, filter.replace(/\/?$/, '/**/*.js'));
return memo;
},
[]
)
.parse(process.argv).filterSpec;
-webpackConfig.plugins.push(
- new webpack.DefinePlugin({
- 'process.env.TEST_FILES': JSON.stringify(testFiles),
- })
-);
+if (specFilters.length) {
+ const specsPath = /^(?:\.[\\\/])?spec[\\\/]javascripts[\\\/]/;
+
+ // resolve filters
+ let filteredSpecFiles = specFilters.map(filter =>
+ glob
+ .sync(filter, {
+ root: ROOT_PATH,
+ matchBase: true,
+ })
+ .filter(path => path.endsWith('spec.js'))
+ );
+
+ // flatten
+ filteredSpecFiles = Array.prototype.concat.apply([], filteredSpecFiles);
+
+ // remove duplicates
+ filteredSpecFiles = [...new Set(filteredSpecFiles)];
-webpackConfig.devtool = process.env.BABEL_ENV !== 'coverage' && 'cheap-inline-source-map';
+ if (filteredSpecFiles.length < 1) {
+ fatalError('Your filter did not match any test files.');
+ }
+
+ if (!filteredSpecFiles.every(file => specsPath.test(file))) {
+ fatalError('Test files must be located within /spec/javascripts.');
+ }
+
+ const newContext = filteredSpecFiles.reduce((context, file) => {
+ const relativePath = file.replace(specsPath, '');
+ context[file] = `./${relativePath}`;
+ return context;
+ }, {});
+
+ webpackConfig.plugins.push(
+ new webpack.ContextReplacementPlugin(
+ /spec[\\\/]javascripts$/,
+ path.join(ROOT_PATH, 'spec/javascripts'),
+ newContext
+ )
+ );
+}
// Karma configuration
module.exports = function(config) {
process.env.TZ = 'Etc/UTC';
- var progressReporter = process.env.CI ? 'mocha' : 'progress';
+ const progressReporter = process.env.CI ? 'mocha' : 'progress';
- var karmaConfig = {
+ const karmaConfig = {
basePath: ROOT_PATH,
browsers: ['ChromeHeadlessCustom'],
customLaunchers: {
diff --git a/config/prometheus/additional_metrics.yml b/config/prometheus/additional_metrics.yml
index 10ca612b246..13732384953 100644
--- a/config/prometheus/additional_metrics.yml
+++ b/config/prometheus/additional_metrics.yml
@@ -103,10 +103,10 @@
- title: "Throughput"
y_label: "Requests / Sec"
required_metrics:
- - nginx_responses_total
+ - nginx_server_requests
weight: 1
queries:
- - query_range: 'sum(rate(nginx_responses_total{server_zone!="*", server_zone!="_", %{environment_filter}}[2m])) by (status_code)'
+ - query_range: 'sum(rate(nginx_server_requests{server_zone!="*", server_zone!="_", %{environment_filter}}[2m])) by (code)'
unit: req / sec
label: Status Code
series:
@@ -121,19 +121,19 @@
- title: "Latency"
y_label: "Latency (ms)"
required_metrics:
- - nginx_upstream_response_msecs_avg
+ - nginx_server_requestMsec
weight: 1
queries:
- - query_range: 'avg(nginx_upstream_response_msecs_avg{%{environment_filter}})'
+ - query_range: 'avg(nginx_server_requestMsec{%{environment_filter}})'
label: Upstream
unit: ms
- title: "HTTP Error Rate"
y_label: "HTTP 500 Errors / Sec"
required_metrics:
- - nginx_responses_total
+ - nginx_server_requests
weight: 1
queries:
- - query_range: 'sum(rate(nginx_responses_total{status_code="5xx", %{environment_filter}}[2m]))'
+ - query_range: 'sum(rate(nginx_server_requests{code="5xx", %{environment_filter}}[2m]))'
label: HTTP Errors
unit: "errors / sec"
- group: System metrics (Kubernetes)
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 170508e893d..7c4c3d370e0 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -58,6 +58,13 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
# On CE only index and show actions are needed
resources :boards, only: [:index, :show]
+
+ resources :runners, only: [:index, :edit, :update, :destroy, :show] do
+ member do
+ post :resume
+ post :pause
+ end
+ end
end
scope(path: '*id',
diff --git a/config/routes/profile.rb b/config/routes/profile.rb
index bcfc17a5f66..a9ba5ac2c0b 100644
--- a/config/routes/profile.rb
+++ b/config/routes/profile.rb
@@ -30,6 +30,7 @@ resource :profile, only: [:show, :update] do
put :revoke
end
end
+ resources :active_sessions, only: [:index, :destroy]
resources :emails, only: [:index, :create, :destroy] do
member do
put :resend_confirmation_instructions
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 2a1bcb8cde2..5a1be1a8b73 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -161,7 +161,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
get :diff_for_path
- get :update_branches
get :branch_from
get :branch_to
end
@@ -175,6 +174,12 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ resource :mirror, only: [:show, :update] do
+ member do
+ post :update_now
+ end
+ end
+
resources :pipelines, only: [:index, :new, :create, :show] do
collection do
resource :pipelines_settings, path: 'settings', only: [:show, :update]
@@ -183,6 +188,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
member do
get :stage
+ get :stage_ajax
post :cancel
post :retry
get :builds
@@ -410,6 +416,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
collection do
post :toggle_shared_runners
+ post :toggle_group_runners
end
end
diff --git a/config/routes/repository.rb b/config/routes/repository.rb
index 9e506a1a43a..e2bf8d6a7ff 100644
--- a/config/routes/repository.rb
+++ b/config/routes/repository.rb
@@ -18,6 +18,7 @@ scope format: false do
resources :compare, only: [:index, :create] do
collection do
get :diff_for_path
+ get :signatures
end
end
diff --git a/config/routes/user.rb b/config/routes/user.rb
index f8677693fab..bc7df5e7584 100644
--- a/config/routes/user.rb
+++ b/config/routes/user.rb
@@ -27,6 +27,13 @@ devise_scope :user do
get '/users/almost_there' => 'confirmations#almost_there'
end
+scope '-/users', module: :users do
+ resources :terms, only: [:index] do
+ post :accept, on: :member
+ post :decline, on: :member
+ end
+end
+
scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) do
scope(path: 'users/:username',
as: :user,
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 47fbbed44cf..e1e8f36b663 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -73,3 +73,6 @@
- [object_storage, 1]
- [plugin, 1]
- [pipeline_background, 1]
+ - [repository_update_remote_mirror, 1]
+ - [repository_remove_remote, 1]
+
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 39e9fbbd530..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: {
@@ -69,6 +109,9 @@ const config = {
test: /\.js$/,
exclude: /(node_modules|vendor\/assets)/,
loader: 'babel-loader',
+ options: {
+ cacheDirectory: path.join(ROOT_PATH, 'tmp/cache/babel-loader'),
+ },
},
{
test: /\.vue$/,
@@ -89,10 +132,10 @@ const config = {
{
loader: 'worker-loader',
options: {
- inline: true,
+ name: '[name].[hash:8].worker.js',
},
},
- { loader: 'babel-loader' },
+ 'babel-loader',
],
},
{
@@ -100,7 +143,7 @@ const config = {
exclude: /node_modules/,
loader: 'file-loader',
options: {
- name: '[name].[hash].[ext]',
+ name: '[name].[hash:8].[ext]',
},
},
{
@@ -111,7 +154,7 @@ const config = {
{
loader: 'css-loader',
options: {
- name: '[name].[hash].[ext]',
+ name: '[name].[hash:8].[ext]',
},
},
],
@@ -121,7 +164,7 @@ const config = {
include: /node_modules\/katex\/dist\/fonts/,
loader: 'file-loader',
options: {
- name: '[name].[hash].[ext]',
+ name: '[name].[hash:8].[ext]',
},
},
{
@@ -163,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([
{
@@ -257,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) {
@@ -289,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());
}