@mapbox/batfish
Version:
The React-powered static-site generator you didn't know you wanted
147 lines (137 loc) • 4.47 kB
JavaScript
//
;
const _ = require('lodash');
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const AssetsPlugin = require('assets-webpack-plugin');
const resolveFrom = require('resolve-from');
const createWebpackConfigBase = require('./create-webpack-config-base');
const constants = require('./constants');
// We need the directory for the module instead of the filename to its main
// file.
function resolveModuleDirectoryFrom(src , name ) {
return resolveFrom(src, name).replace(
/node_modules\/([^/]+).*$/,
'node_modules/$1'
);
}
// Create a Webpack configuration for all the assets that will be loaded by the client.
function createWebpackConfigClient(
batfishConfig ,
options
) {
// Resolve these peerDependencies from the pagesDirectory so we are sure
// to get the same version that the pages are getting. Alias them below.
const reactPath = resolveModuleDirectoryFrom(
batfishConfig.pagesDirectory,
'react'
);
const reactDomPath = resolveModuleDirectoryFrom(
batfishConfig.pagesDirectory,
'react-dom'
);
const reactHelmetPath = resolveModuleDirectoryFrom(
batfishConfig.pagesDirectory,
'react-helmet'
);
return createWebpackConfigBase(batfishConfig, {
target: constants.TARGET_BROWSER
}).then((baseConfig) => {
let vendorModules = [
reactPath,
reactDomPath,
reactHelmetPath,
require.resolve('@mapbox/scroll-restorer'),
require.resolve('@mapbox/link-hijacker')
];
if (batfishConfig.includePromisePolyfill) {
vendorModules.unshift(require.resolve('es6-promise/auto'));
}
if (batfishConfig.vendorModules !== undefined) {
vendorModules = vendorModules.concat(batfishConfig.vendorModules);
}
const clientPlugins = [
// Emit a file with assets' paths.
// This is used in build processes to grab built files, whose names
// include hashes so cannot be known without this dictionary.
new AssetsPlugin({
path: path.resolve(batfishConfig.outputDirectory),
filename: 'assets.json',
processOutput: (x) => JSON.stringify(x, null, 2)
}),
new webpack.DefinePlugin({
'process.env.DEV_SERVER': (options && options.devServer) || false
})
].concat(batfishConfig.webpackPlugins || []);
const appEntry = [
require.resolve('core-js/modules/es6.promise'),
require.resolve('core-js/modules/es6.array.iterator')
];
if (!batfishConfig.production && batfishConfig.inlineJs) {
batfishConfig.inlineJs.forEach((jsData) => {
appEntry.push(jsData.filename);
});
}
if (batfishConfig.spa) {
appEntry.push(
path.join(__dirname, '../webpack/render-batfish-spa-app.js')
);
} else {
appEntry.push(path.join(__dirname, '../webpack/render-batfish-app.js'));
}
const clientConfig = {
entry: {
app: appEntry,
vendor: vendorModules
},
output: {
filename: !batfishConfig.production
? '[name].js'
: '[name]-[chunkhash].js',
chunkFilename: !batfishConfig.production
? '[name].chunk.js'
: '[name]-[chunkhash].chunk.js'
},
resolve: {
alias: Object.assign({}, _.get(baseConfig, 'resolve.alias'), {
react: reactPath,
'react-dom': reactDomPath,
'react-helmet': reactHelmetPath
})
},
target: 'web',
plugins: clientPlugins,
// This helps us import more libraries with fewer errors.
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
optimization: {
moduleIds: 'hashed',
runtimeChunk: {
name: 'manifest'
},
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'initial',
name: 'vendor',
test: 'vendor',
enforce: true
}
}
}
}
};
let config = webpackMerge(baseConfig, clientConfig);
if (batfishConfig.webpackConfigClientTransform) {
config = batfishConfig.webpackConfigClientTransform(config);
}
return config;
});
}
module.exports = createWebpackConfigClient;