@tdb/web
Version:
Common condiguration for serving a web-site and testing web-based UI components.
397 lines (335 loc) • 16.7 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getBaseWebpackConfig;
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/objectSpread"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
var _keys = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/object/keys"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
var _path = _interopRequireDefault(require("path"));
var _webpack = _interopRequireDefault(require("webpack"));
var _resolve = _interopRequireDefault(require("resolve"));
var _caseSensitivePathsWebpackPlugin = _interopRequireDefault(require("case-sensitive-paths-webpack-plugin"));
var _writeFileWebpackPlugin = _interopRequireDefault(require("write-file-webpack-plugin"));
var _friendlyErrorsWebpackPlugin = _interopRequireDefault(require("friendly-errors-webpack-plugin"));
var _webpackbar = _interopRequireDefault(require("webpackbar"));
var _utils = require("./webpack/utils");
var _pagesPlugin = _interopRequireDefault(require("./webpack/plugins/pages-plugin"));
var _nextjsSsrImport = _interopRequireDefault(require("./webpack/plugins/nextjs-ssr-import"));
var _nextjsSsrModuleCache = _interopRequireDefault(require("./webpack/plugins/nextjs-ssr-module-cache"));
var _nextjsRequireCacheHotReloader = _interopRequireDefault(require("./webpack/plugins/nextjs-require-cache-hot-reloader"));
var _unlinkFilePlugin = _interopRequireDefault(require("./webpack/plugins/unlink-file-plugin"));
var _pagesManifestPlugin = _interopRequireDefault(require("./webpack/plugins/pages-manifest-plugin"));
var _buildManifestPlugin = _interopRequireDefault(require("./webpack/plugins/build-manifest-plugin"));
var _chunkNamesPlugin = _interopRequireDefault(require("./webpack/plugins/chunk-names-plugin"));
var _reactLoadablePlugin = require("./webpack/plugins/react-loadable-plugin");
var _constants = require("../lib/constants");
var _autodllWebpackPlugin = _interopRequireDefault(require("autodll-webpack-plugin"));
var _terserWebpackPlugin = _interopRequireDefault(require("terser-webpack-plugin"));
// The externals config makes sure that
// on the server side when modules are
// in node_modules they don't get compiled by webpack
function externalsConfig(dir, isServer) {
var externals = [];
if (!isServer) {
return externals;
}
externals.push(function (context, request, callback) {
(0, _resolve.default)(request, {
basedir: dir,
preserveSymlinks: true
}, function (err, res) {
if (err) {
return callback();
} // Default pages have to be transpiled
if (res.match(/node_modules[/\\]next[/\\]dist[/\\]pages/)) {
return callback();
} // Webpack itself has to be compiled because it doesn't always use module relative paths
if (res.match(/node_modules[/\\]webpack/) || res.match(/node_modules[/\\]css-loader/)) {
return callback();
}
if (res.match(/node_modules[/\\].*\.js$/)) {
return callback(null, "commonjs ".concat(request));
}
callback();
});
});
return externals;
}
function optimizationConfig(_ref) {
var dir = _ref.dir,
dev = _ref.dev,
isServer = _ref.isServer,
totalPages = _ref.totalPages;
if (isServer) {
return {
splitChunks: false,
minimize: false
};
}
var config = {
runtimeChunk: {
name: _constants.CLIENT_STATIC_FILES_RUNTIME_WEBPACK
},
splitChunks: {
cacheGroups: {
default: false,
vendors: false
}
}
};
if (dev) {
return config;
} // Terser is a better uglifier
config.minimizer = [new _terserWebpackPlugin.default({
parallel: true,
sourceMap: false,
cache: true
})]; // Only enabled in production
// This logic will create a commons bundle
// with modules that are used in 50% of all pages
config.splitChunks.chunks = 'all';
config.splitChunks.cacheGroups.commons = {
name: 'commons',
chunks: 'all',
minChunks: totalPages > 2 ? totalPages * 0.5 : 2
};
config.splitChunks.cacheGroups.react = {
name: 'commons',
chunks: 'all',
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/
};
return config;
}
function getBaseWebpackConfig(_x, _x2) {
return _getBaseWebpackConfig.apply(this, arguments);
}
function _getBaseWebpackConfig() {
_getBaseWebpackConfig = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee3(dir, _ref2) {
var _ref2$dev, dev, _ref2$isServer, isServer, buildId, config, defaultLoaders, nodePathList, distDir, outputPath, pagesEntries, totalPages, clientEntries, resolveConfig, webpackMode, webpackConfig, originalEntry;
return _regenerator.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_ref2$dev = _ref2.dev, dev = _ref2$dev === void 0 ? false : _ref2$dev, _ref2$isServer = _ref2.isServer, isServer = _ref2$isServer === void 0 ? false : _ref2$isServer, buildId = _ref2.buildId, config = _ref2.config;
defaultLoaders = {
babel: {
loader: 'next-babel-loader',
options: {
dev: dev,
isServer: isServer,
cwd: dir
}
},
hotSelfAccept: {
loader: 'hot-self-accept-loader',
options: {
include: [_path.default.join(dir, 'pages')],
// All pages are javascript files. So we apply hot-self-accept-loader here to facilitate hot reloading of pages.
// This makes sure plugins just have to implement `pageExtensions` instead of also implementing the loader
extensions: new RegExp("\\.+(".concat(config.pageExtensions.join('|'), ")$"))
}
} // Support for NODE_PATH
};
nodePathList = (process.env.NODE_PATH || '').split(process.platform === 'win32' ? ';' : ':').filter(function (p) {
return !!p;
});
distDir = _path.default.join(dir, config.distDir);
outputPath = _path.default.join(distDir, isServer ? _constants.SERVER_DIRECTORY : '');
_context3.next = 7;
return (0, _utils.getPages)(dir, {
nextPagesDir: _constants.DEFAULT_PAGES_DIR,
dev: dev,
buildId: buildId,
isServer: isServer,
pageExtensions: config.pageExtensions.join('|')
});
case 7:
pagesEntries = _context3.sent;
totalPages = (0, _keys.default)(pagesEntries).length;
clientEntries = !isServer ? (0, _defineProperty2.default)({
// Backwards compatibility
'main.js': []
}, _constants.CLIENT_STATIC_FILES_RUNTIME_MAIN, [_path.default.join(_constants.NEXT_PROJECT_ROOT_DIST, 'client', dev ? "next-dev" : 'next')].filter(Boolean)) : {};
resolveConfig = {
extensions: ['.wasm', '.mjs', '.js', '.jsx', '.json'],
modules: [_constants.NEXT_PROJECT_ROOT_NODE_MODULES, 'node_modules'].concat((0, _toConsumableArray2.default)(nodePathList)),
alias: {
next: _constants.NEXT_PROJECT_ROOT
}
};
webpackMode = dev ? 'development' : 'production';
webpackConfig = {
mode: webpackMode,
devtool: dev ? 'cheap-module-source-map' : false,
name: isServer ? 'server' : 'client',
cache: true,
target: isServer ? 'node' : 'web',
externals: externalsConfig(dir, isServer),
optimization: optimizationConfig({
dir: dir,
dev: dev,
isServer: isServer,
totalPages: totalPages
}),
recordsPath: _path.default.join(outputPath, 'records.json'),
context: dir,
// Kept as function to be backwards compatible
entry: function () {
var _entry = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee() {
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
return _context.abrupt("return", (0, _objectSpread2.default)({}, clientEntries, pagesEntries));
case 1:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function entry() {
return _entry.apply(this, arguments);
};
}(),
output: {
path: outputPath,
filename: function filename(_ref4) {
var chunk = _ref4.chunk;
// Use `[name]-[contenthash].js` in production
if (!dev && (chunk.name === _constants.CLIENT_STATIC_FILES_RUNTIME_MAIN || chunk.name === _constants.CLIENT_STATIC_FILES_RUNTIME_WEBPACK)) {
return chunk.name.replace(/\.js$/, '-[contenthash].js');
}
return '[name]';
},
libraryTarget: isServer ? 'commonjs2' : 'jsonp',
hotUpdateChunkFilename: 'static/webpack/[id].[hash].hot-update.js',
hotUpdateMainFilename: 'static/webpack/[hash].hot-update.json',
// This saves chunks with the name given via `import()`
chunkFilename: isServer ? "".concat(dev ? '[name]' : '[name].[contenthash]', ".js") : "static/chunks/".concat(dev ? '[name]' : '[name].[contenthash]', ".js"),
strictModuleExceptionHandling: true
},
performance: {
hints: false
},
resolve: resolveConfig,
resolveLoader: {
modules: [_constants.NEXT_PROJECT_ROOT_NODE_MODULES, 'node_modules', _path.default.join(__dirname, 'webpack', 'loaders')].concat((0, _toConsumableArray2.default)(nodePathList))
},
module: {
rules: [dev && !isServer && {
test: defaultLoaders.hotSelfAccept.options.extensions,
include: defaultLoaders.hotSelfAccept.options.include,
use: defaultLoaders.hotSelfAccept
}, {
test: /\.(js|jsx)$/,
include: [dir],
exclude: /node_modules/,
use: defaultLoaders.babel
}].filter(Boolean)
},
plugins: [// Precompile react / react-dom for development, speeding up webpack
dev && !isServer && new _autodllWebpackPlugin.default({
filename: '[name]_[hash].js',
path: './static/development/dll',
context: dir,
entry: {
dll: ['react', 'react-dom']
},
config: {
mode: webpackMode,
resolve: resolveConfig
}
}), // This plugin makes sure `output.filename` is used for entry chunks
new _chunkNamesPlugin.default(), !isServer && new _reactLoadablePlugin.ReactLoadablePlugin({
filename: _constants.REACT_LOADABLE_MANIFEST
}), new _webpackbar.default({
name: isServer ? 'server' : 'client'
}), dev && !isServer && new _friendlyErrorsWebpackPlugin.default(), new _webpack.default.IgnorePlugin(/(precomputed)/, /node_modules.+(elliptic)/), // This removes prop-types-exact in production, as it's not used there.
!dev && new _webpack.default.IgnorePlugin({
checkResource: function checkResource(resource) {
return /prop-types-exact/.test(resource);
},
checkContext: function checkContext(context) {
return context.indexOf(_constants.NEXT_PROJECT_ROOT_DIST) !== -1;
}
}), // Even though require.cache is server only we have to clear assets from both compilations
// This is because the client compilation generates the build manifest that's used on the server side
dev && new _nextjsRequireCacheHotReloader.default(), dev && !isServer && new _webpack.default.HotModuleReplacementPlugin(), dev && new _webpack.default.NoEmitOnErrorsPlugin(), dev && new _unlinkFilePlugin.default(), dev && new _caseSensitivePathsWebpackPlugin.default(), // Since on macOS the filesystem is case-insensitive this will make sure your path are case-sensitive
dev && new _writeFileWebpackPlugin.default({
exitOnErrors: false,
log: false,
// required not to cache removed files
useHashIndex: false
}), // Removes server/client code by minifier
new _webpack.default.DefinePlugin({
'process.browser': (0, _stringify.default)(!isServer)
}), // This is used in client/dev-error-overlay/hot-dev-client.js to replace the dist directory
!isServer && dev && new _webpack.default.DefinePlugin({
'process.env.__NEXT_DIST_DIR': (0, _stringify.default)(distDir)
}), isServer && new _pagesManifestPlugin.default(), !isServer && new _buildManifestPlugin.default(), !isServer && new _pagesPlugin.default(), isServer && new _nextjsSsrImport.default(), isServer && new _nextjsSsrModuleCache.default({
outputPath: outputPath
})].filter(Boolean)
};
if (typeof config.webpack === 'function') {
webpackConfig = config.webpack(webpackConfig, {
dir: dir,
dev: dev,
isServer: isServer,
buildId: buildId,
config: config,
defaultLoaders: defaultLoaders,
totalPages: totalPages
});
} // Backwards compat for `main.js` entry key
originalEntry = webpackConfig.entry;
webpackConfig.entry =
/*#__PURE__*/
(0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2() {
var entry;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.t0 = _objectSpread2.default;
_context2.t1 = {};
_context2.next = 4;
return originalEntry();
case 4:
_context2.t2 = _context2.sent;
entry = (0, _context2.t0)(_context2.t1, _context2.t2);
// Server compilation doesn't have main.js
if (typeof entry['main.js'] !== 'undefined') {
entry[_constants.CLIENT_STATIC_FILES_RUNTIME_MAIN] = (0, _toConsumableArray2.default)(entry['main.js']).concat((0, _toConsumableArray2.default)(entry[_constants.CLIENT_STATIC_FILES_RUNTIME_MAIN]));
delete entry['main.js'];
}
return _context2.abrupt("return", entry);
case 8:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
return _context3.abrupt("return", webpackConfig);
case 17:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
return _getBaseWebpackConfig.apply(this, arguments);
}