Skip to content

Instantly share code, notes, and snippets.

@mmcgahan
Created February 1, 2019 22:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmcgahan/dbf9b685eb80d604487df31c11e093d1 to your computer and use it in GitHub Desktop.
Save mmcgahan/dbf9b685eb80d604487df31c11e093d1 to your computer and use it in GitHub Desktop.
const path = require('path');
const webpack = require('webpack');
const ManifestPlugin = require('webpack-manifest-plugin');
const StatsPlugin = require('webpack-stats-plugin').StatsWriterPlugin;
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const { env, paths } = require('mwp-config');
const prodPlugins = require('./prodPlugins');
const rules = require('./rules');
/**
* When in dev, we need to manually inject some configuration to enable HMR
*
* @param {Object} config webpack config object
* @returns {Object} HMR-ified config
*/
function injectHotReloadConfig(config) {
/**
* @see http://gaearon.github.io/react-hot-loader/getstarted/
* - "Option 2: Webpack Dev Server with custom server (client-side rendering only)"
*/
config.entry.app.unshift(
`webpack-dev-server/client?http://${env.properties.asset_server.host}:${env.properties.asset_server.port}/`, // connect to HMR websocket
'webpack/hot/only-dev-server' // run the dev server
);
// plugins
config.plugins.push(new webpack.HotModuleReplacementPlugin()); // enable module.hot
// show HMR module filenames
config.optimization = {
namedModules: true
};
return config;
}
/*
* Webpack config object determined by passed-in localeCode. The language is
* used to resolve the translated message module paths in applications that
* support translations (currently not supported by starter kit), but also
* to determine the output path
*/
function getConfig(localeCode) {
const publicPath = `${env.properties.publicPathBase}${localeCode}/`;
const baseWebfontDir = path.resolve(paths.src.asset, 'fonts');
const webfontDir =
localeCode === 'ru-RU'
? path.resolve(baseWebfontDir, localeCode)
: baseWebfontDir;
const config = {
mode: env.properties.isProd ? 'production' : 'development',
entry: {
app: [paths.src.browser.entry]
},
output: {
path: path.resolve(paths.output.browser, localeCode),
filename: env.properties.isDev
? "[name].js" // in dev, keep the filename consistent to make reloading easier
: "[name].[chunkhash].js", // in prod, add hash to enable long-term caching
chunkFilename: "[name].[chunkhash].js",
hashDigestLength: 8,
publicPath
},
devtool: 'cheap-module-source-map', // similar speed to 'eval', but with proper source maps
module: {
rules: [
rules.file,
rules.scssModule,
rules.baseScss,
rules.css,
rules.externalCss,
rules.js.browser,
rules.raw
]
},
resolve: {
alias: {
src: paths.src.browser.app,
trns: path.resolve(paths.src.trns, 'modules', localeCode),
webfont: webfontDir
},
// module name extensions that Webpack will try if no extension provided
// '*' matches imports with extensions
extensions: ['.js', '.jsx', '.json', '*']
},
plugins: [
/**
* @see https://webpack.js.org/plugins/environment-plugin/
*
* Replaces references to process.env.NODE_ENV in the code
* with the build-time string value of NODE_ENV.
*/
new webpack.EnvironmentPlugin({
// React relies on process.env.NODE_ENV for including dev warnings,
// and we use it for similar purposes in application code.
NODE_ENV: 'development',
INTERCOM_APP_ID: null // only needs to be overriden if application wants Intercom config available on client and server
}),
/**
* @see https://webpack.js.org/plugins/dll-plugin/
*/
new webpack.DllReferencePlugin({
context: '.',
manifest: require(path.resolve(
paths.output.vendor,
'react-dll-manifest.json'
))
}),
/**
* @see https://webpack.js.org/plugins/dll-plugin/
*/
new webpack.DllReferencePlugin({
context: '.',
manifest: require(path.resolve(
paths.output.vendor,
'vendor-dll-manifest.json'
))
}),
/**
* @see https://github.com/danethurber/webpack-manifest-plugin
*/
new ManifestPlugin({
publicPath,
writeToFileEmit: true // emit manifest from dev-server build
}),
/**
* @see https://github.com/FormidableLabs/webpack-stats-plugin
*/
new StatsPlugin({
fields: null // null means `all fields in stats file`
})
]
};
if (env.properties.isDev) {
injectHotReloadConfig(config);
}
if (env.properties.isProd) {
config.plugins = config.plugins.concat(
prodPlugins,
new SWPrecacheWebpackPlugin({
cacheId: 'mwp',
dontCacheBustUrlsMatching: /\.\w{8}\./, // no need for cache-busting querystring on hashed filenames
filename: `asset-service-worker.js`,
minify: true,
staticFileGlobsIgnorePatterns: [
// don't cache these files
/\.map$/, // source-maps
/.json$/, // manifest files
/.jpg$/,
/.png$/,
/.mp4$/
]
})
);
}
return config;
}
// export the config-building function _only_ - this cannot be run by the CLI
module.exports = getConfig;
const path = require('path');
const { babel, env, paths } = require('mwp-config');
const postCssLoaderConfig = require('./postCssLoaderConfig.js');
/**
* @see https://webpack.js.org/configuration/module/#module-rules
*/
module.exports = {
scssModule: {
test: /\.module\.scss$/,
include: [paths.srcPath],
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: true,
localIdentName: '_[name]_[local]__[hash:base64:5]',
},
},
postCssLoaderConfig,
'sass-loader',
],
},
baseScss: {
test: /main\.scss$/,
include: [paths.srcPath],
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash:8].css',
},
},
'extract-loader',
'css-loader',
postCssLoaderConfig,
'sass-loader',
],
},
css: {
test: /\.css$/,
include: [path.resolve(paths.src.asset, 'css')],
use: ['style-loader', 'css-loader'],
},
externalCss: {
test: /\.css$/,
include: [path.resolve(paths.repoRoot, 'node_modules')],
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash:8].css',
},
},
],
},
js: {
browser: {
// standard ES5 transpile through Babel
test: /\.jsx?$/,
include: [paths.src.browser.app, paths.packages.webComponents.src],
exclude: paths.src.asset,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
plugins: env.properties.isDev
? babel.plugins.browser.concat([
'react-hot-loader/babel',
])
: babel.plugins.browser,
presets: babel.presets.browser,
},
},
],
},
server: {
test: /\.jsx?$/,
include: [paths.src.server.app, paths.packages.webComponents.src],
exclude: paths.src.asset,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
plugins: babel.plugins.server,
presets: babel.presets.server,
},
},
],
},
},
file: {
test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|mp4|m4a|aac|oga)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash:8].[ext]',
},
},
],
},
raw: {
test: /\.inc?$/,
use: ['raw-loader'],
},
};
// Require modules
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const webpack = require('webpack');
const StatsPlugin = require('webpack-stats-plugin').StatsWriterPlugin;
const { env, paths } = require('mwp-config');
// Build settings
const prodPlugins = require('./prodPlugins');
const rules = require('./rules');
/*
* Webpack config object determined by passed-in localeCode. The language is
* used to resolve the translated message module paths and determine the output
* path
*
* The server app is a module that exports a rendering function that can be
* imported by the server and used to render requests to the app route.
*/
function getConfig(localeCode) {
const publicPath = `${env.properties.publicPathBase}${localeCode}/`;
const baseWebfontDir = path.resolve(
paths.src.server.app,
'assets',
'fonts'
);
const webfontDir =
localeCode === 'ru-RU'
? path.resolve(baseWebfontDir, localeCode)
: baseWebfontDir;
const config = {
mode: env.properties.isProd ? 'production' : 'development',
entry: {
'server-app': [paths.src.server.entry],
},
// write a CommonJS module that can be imported into Node server scripts
output: {
libraryTarget: 'commonjs2',
path: path.join(paths.output.server, localeCode),
filename: '[name].js',
publicPath,
},
devtool: 'eval',
module: {
rules: [
rules.file,
rules.scssModule,
rules.baseScss,
rules.css,
rules.externalCss,
rules.js.server,
rules.raw,
],
},
plugins: [
/**
* @see https://webpack.js.org/plugins/environment-plugin/
*
* Replaces references to process.env.NODE_ENV in the code
* with the build-time string value of NODE_ENV.
*/
new webpack.EnvironmentPlugin({
// React relies on process.env.NODE_ENV for including dev warnings,
// and we use it for similar purposes in application code.
NODE_ENV: 'development',
}),
/**
* @see https://webpack.js.org/plugins/define-plugin/
*/
new webpack.DefinePlugin({
// server bundles must reference _browser_ bundle public path
// - inject it as a 'global variable' here
VENDOR_MANIFEST_PATH: JSON.stringify(
path.resolve(paths.output.browser, 'manifest.json')
),
BROWSER_MANIFEST_PATH: JSON.stringify(
path.resolve(
paths.output.browser,
localeCode,
'manifest.json'
)
),
}),
/**
* @see https://github.com/FormidableLabs/webpack-stats-plugin
*/
new StatsPlugin({ fields: null }), // null means 'all fields in stats file'
],
target: 'node',
externals: [
nodeExternals({
modulesDir: process.env.NODE_PATH
? process.env.NODE_PATH
: null,
whitelist: [
/^meetup-web-components/,
/^@meetup\//,
/^swarm-icons\/dist\/sprite\/sprite\.inc$/,
],
}),
new RegExp(paths.buildPath),
/\.\/build\//,
],
resolve: {
alias: {
src: paths.src.server.app,
trns: path.resolve(paths.src.trns, 'modules', localeCode),
webfont: webfontDir,
},
// module name extensions that Webpack will try if no extension provided
// '*' matches imports with extensions
extensions: ['.js', '.jsx', '.json', '*'],
},
};
if (env.properties.isProd) {
config.plugins = config.plugins.concat(prodPlugins);
}
return config;
}
// export the config-building function for programmatic consumption
module.exports = getConfig;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment