-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathwebpack.config.js
183 lines (165 loc) · 7.73 KB
/
webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
'use strict';
const
CleanPlugin = require( 'clean-webpack-plugin' ),
path = require( 'path' ),
// The output directory for all build artifacts. Only absolute paths are accepted by
// output.path.
distDir = path.resolve( __dirname, 'resources/dist' ),
// The extension used for source map files.
srcMapExt = '.map.json',
ENTRIES = {
startup: 'mobile.startup',
languages: 'mobile.languages.structured',
mediaViewer: 'mobile.mediaViewer',
mobileInit: 'mobile.init',
mobileOptions: 'mobile.special.mobileoptions.scripts',
userLogin: 'mobile.special.userlogin.scripts',
watchlist: 'mobile.special.watchlist.scripts'
};
module.exports = ( env, argv ) => ( {
// Apply the rule of silence: https://wikipedia.org/wiki/Unix_philosophy.
stats: {
all: false,
// Output a timestamp when a build completes. Useful when watching files.
builtAt: true,
errors: true,
warnings: true
},
// Fail on the first build error instead of tolerating it for prod builds. This seems to
// correspond to optimization.emitOnErrors.
bail: argv.mode === 'production',
// Specify that all paths are relative the Webpack configuration directory not the current
// working directory.
context: __dirname,
// A map of ResourceLoader module / entry chunk names to JavaScript files to pack. E.g.,
// "mobile.startup" maps to src/mobile.startup/mobile.startup.js. The JavaScript entry could be
// named simply "index.js" but the redundancy of "[name].js" improves presentation and search-
// ability in some tools. Entry names are tightly coupled to output.filename and extension.json.
entry: {
// mobile.startup.runtime: reserved entry for the Webpack bootloader
// optimization.runtimeChunk. Without a distinct runtime chunk, it's instead bundled into
// each entry which is inefficient. This chunk should only change when Webpack or this
// configuration changes.
[ENTRIES.startup]: './src/mobile.startup/mobile.startup.js',
// Make some chunks which will be lazy loaded by resource loader.
// If we utilize webpack lazy loading instead of resource loader lazy
// loading, we won't be required to explicitly create this new chunk and
// this can be removed.
[ENTRIES.languages]: './src/mobile.languages.structured/mobile.languages.structured.js',
[ENTRIES.mediaViewer]: './src/mobile.mediaViewer/mobile.mediaViewer.js',
// all mobile skins,
[ENTRIES.mobileInit]: './src/mobile.init/mobile.init.js',
// T212823 Make a chunk for each mobile special page
[ENTRIES.mobileOptions]: './src/mobile.special.mobileoptions.scripts.js',
[ENTRIES.userLogin]: './src/mobile.special.userlogin.scripts.js',
[ENTRIES.watchlist]: './src/mobile.special.watchlist.scripts/mobile.special.watchlist.scripts.js'
},
resolve: {
alias: {
// This avoids leaking unnecessary code into the webpack test build
'./mockMediaWiki': path.resolve( __dirname, 'tests/node-qunit/utils/blank.js' )
}
},
optimization: {
// Don't produce production output when a build error occurs.
emitOnErrors: argv.mode !== 'production',
// Use filenames instead of unstable numerical identifiers for file references. This
// increases the gzipped bundle size some but makes the build products easier to debug and
// appear deterministic. I.e., code changes will only alter the bundle they're packed in
// instead of shifting the identifiers in other bundles.
// https://webpack.js.org/guides/caching/#deterministic-hashes (namedModules replaces NamedModulesPlugin.)
moduleIds: 'named',
// Generate a single Webpack bootstrap chunk for ResourceLoader modules to share. This will
// be packaged inside the mobile.startup module which should be a dependency for
// all modules. The inefficient alternative is for each module to bundle its own runtime.
// The terms bootloader and runtime are used interchangeably.
runtimeChunk: { name: 'mobile.startup.runtime' },
splitChunks: {
cacheGroups: {
// Turn off webpack's default 'default' cache group.
// https://webpack.js.org/plugins/split-chunks-plugin/#optimization-splitchunks
default: false,
// Turn off webpack's default 'vendors' cache group. If this is desired
// later on, we can explicitly turn this on for clarity.
// https://webpack.js.org/plugins/split-chunks-plugin/#optimization-splitchunks
vendors: false,
// TT210210: This was undesirably added when trying to get lazy loaded
// modules to work (e.g. ENTRIES.languages). It will excise modules
// shared between the chunks listed in the whitelist entry array into a
// new 'mobile.common' chunk. Ideally, the common chunk would be merged
// into the mobile.startup chunk and would not exist. However, there was
// difficulty in making webpack cleanly do this. When we overcome
// webpack lazy loading hurdles (or figure out a way to make webpack use
// mobile.startup as the common chunk), we won't be required to do this
// for lazy loaded chunks although it might still be valuable for
// special page chunks.
common: {
name: 'mobile.common',
// Minimum num of chunks module must share before excising into common
// chunk
minChunks: 2,
// Do no reuse existing chunks when splitting (i.e. we do not want
// webpack excising startup modules into an async chunk)
// https://github.com/webpack/webpack.js.org/issues/2122#issuecomment-388609306
reuseExistingChunk: false,
// ignore webpack's default minSize option (and other splitChunks
// defaults) and always create chunks based on criteria specified for
// this cacheGroup
enforce: true,
// Only consider splitting chunks off of these whitelisted entry names
chunks: ( chunk ) => [
ENTRIES.startup,
ENTRIES.categories,
ENTRIES.editor,
ENTRIES.languages,
ENTRIES.mediaViewer,
ENTRIES.mobileInit,
ENTRIES.mobileDiff,
ENTRIES.mobileOptions,
ENTRIES.userLogin,
ENTRIES.watchlist
].includes( chunk.name )
}
}
}
},
target: 'browserslist',
output: {
// Specify the destination of all build products.
path: distDir,
// Store outputs per module in files named after the modules. For the JavaScript entry
// itself, append .js to each ResourceLoader module entry name. This value is tightly
// coupled to sourceMapFilename.
filename: '[name].js',
// Rename source map extensions. Per T173491 files with a .map extension cannot be served
// from prod.
sourceMapFilename: `[file]${ srcMapExt }`,
// Expose the module.exports of each module entry chunk through the global
// mfModules[name].
// This is useful for debugging. E.g., mfModules['mobile.startup'] is set by the
// module.exports of mobile.startup.js.
library: [ 'mfModules', '[name]' ],
libraryTarget: 'this'
},
// Accurate source maps at the expense of build time. The source map is intentionally exposed
// to users via sourceMapFilename for prod debugging. This goes against convention as source
// code is publicly distributed.
devtool: 'source-map',
plugins: [
// Delete the output directory on each build.
new CleanPlugin( distDir, { verbose: false } )
],
performance: {
// Size violations for prod builds fail; development builds are unchecked.
hints: argv.mode === 'production' ? 'error' : false,
// Minified uncompressed size limits for chunks / assets and entrypoints. Keep these numbers
// up-to-date and rounded to the nearest 10th of a kilobyte so that code sizing costs are
// well understood. Related to bundlesize minified, gzipped compressed file size tests.
// Note: entrypoint size implicitly includes the mobile.startup.runtime and mobile.common
// chunks.
maxAssetSize: 48.1 * 1024,
maxEntrypointSize: 85.4 * 1024,
// The default filter excludes map files but we rename ours.
assetFilter: ( filename ) => !filename.endsWith( srcMapExt )
}
} );