Related
I have a react js project and im actually dont know how to set webpack settings. After i run "npm run build" i get 10 js files names 1.js 2.js 3.js with main.js. I dont know how to bundle them. I searched some questions but couldnt solve it. Its not my first project in react but i didnt try to
build with webpack before. Thanks for helps.
My webpack.prod.js ;
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ResourceManifestPlugin = require('webpack-fivem-manifest');
module.exports = require('./webpack.common')({
mode: 'production',
// In production, we skip all hot-reloading stuff
entry: [path.join(process.cwd(), 'src/app.js')],
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
inject: true,
}),
new ResourceManifestPlugin(),
],
performance: {
assetFilter: assetFilename =>
!/(\.map$)|(^(main\.|favicon\.))/.test(assetFilename),
},
});
My webpack.common.js :
const path = require('path');
const webpack = require('webpack');
module.exports = options => ({
mode: options.mode,
entry: options.entry,
output: {
path: path.resolve(process.cwd(), 'html'),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.jsx?$/, // Transform all .js and .jsx files required somewhere with Babel
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
// Preprocess our own .css files
// This is the place to add your own loaders (e.g. sass/less etc.)
// for a list of loaders, see https://webpack.js.org/loaders/#styling
test: /\.css$/,
exclude: /node_modules/,
use: ['style-loader', 'css-loader'],
},
{
// Preprocess 3rd party .css files located in node_modules
test: /\.css$/,
include: /node_modules/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(eot|otf|ttf|woff|woff2)$/,
use: 'file-loader',
},
{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {
// Inline files smaller than 10 kB
limit: 10 * 1024,
noquotes: true,
},
},
],
},
{
test: /\.(jpg|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
// Inline files smaller than 10 kB
limit: 10 * 1024,
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
enabled: false,
// NOTE: mozjpeg is disabled as it causes errors in some Linux environments
// Try enabling it in your environment by switching the config to:
// enabled: true,
// progressive: true,
},
gifsicle: {
interlaced: false,
},
optipng: {
optimizationLevel: 7,
},
pngquant: {
quality: '65-90',
speed: 4,
},
},
},
],
},
{
test: /\.html$/,
use: 'html-loader',
},
{
test: /\.(mp4|webm)$/,
use: {
loader: 'url-loader',
options: {
limit: 10000,
},
},
},
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: `ifdef-loader`,
options: {
DEBUG: options.mode !== 'production',
version: 3,
'ifdef-verbose': true, // add this for verbose output
'ifdef-triple-slash': true, // add this to use double slash comment instead of default triple slash
},
},
],
},
],
},
plugins: options.plugins.concat([
// Always expose NODE_ENV to webpack, in order to use `process.env.NODE_ENV`
// inside your code for any environment checks; Terser will automatically
// drop any unreachable code.
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
]),
resolve: {
modules: ['src', 'node_modules'],
extensions: ['.js', '.jsx', '.react.js'],
},
});
I am trying to get HMR running with webpack v5, but it does not work. When I modify and save a file, webpack re-compiles the project correctly, but the frontend does not update.
I read this article and followed the instructions: https://webpack.js.org/guides/hot-module-replacement/
This is my webpack config:
{
mode: 'development',
entry: {
babelpoly: 'babel-polyfill',
app: [ './src/index.js', './src/app.js' ]
},
plugins: [
BundleStatsWebpackPlugin { ... },
DefinePlugin { ... },
HtmlWebpackPlugin { ... }
],
stats: { ... },
output: {
path: '[pathTo]/dist',
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js'
},
optimization: {
splitChunks: { chunks: 'all' },
runtimeChunk: 'single',
usedExports: true,
mergeDuplicateChunks: true
},
module: {
rules: [
{
test: /\.(s[ac]ss)$/i,
include: path.resolve(ROOT, 'src'),
use: [
'style-loader', // Creates `style` nodes from JS strings
{
loader: 'css-loader', // Translates CSS into CommonJS
options: {
modules: {
mode: 'local',
localIdentName: devMode
? '[name]_[local]-[hash:base64:3]'
: '[local]-[hash:base64:5]',
},
},
},
{
loader: 'sass-loader', // compiles Sass to CSS
options: {
implementation: require('sass'),
},
},
],
},
{
test: /\.css$/,
include: [path.join(ROOT, 'node_modules')],
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader'],
},
{
test: /\.m?jsx?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'#babel/preset-env',
{
useBuiltIns: 'entry',
corejs: 3,
},
],
'#babel/preset-react',
],
plugins: [['#babel/plugin-proposal-class-properties', {loose: true}]],
},
},
},
],
},
resolve: {
extensions: [ ... ],
alias: {
...
},
modules: [
...
]
},
devtool: 'inline-source-map',
devServer: {
port: 3003,
contentBase: '[pathTo]/dist',
host: '0.0.0.0',
hot: true,
compress: true,
disableHostCheck: true,
historyApiFallback: true,
overlay: { warnings: true, errors: true },
stats: { ... }
}
}
I am using:
webpack 5.7.0
webpack-cli 4.2.0
react 16.13
node 14.15.1
npm 6.14.8
I start webpack with this command: webpack serve --host 0.0.0.0 --config config/webpack.dev.js
What do I do wrong? Thanks for your help. :)
I believe it's a bug in webpack-dev-server v3 https://github.com/webpack/webpack-dev-server/issues/2758 when you're using it with webpack 5 and browserslist. You can wait for webpack-dev-server v4 https://github.com/webpack/webpack-dev-server/pull/2592#issuecomment-734400875, it will come soon, or use target: 'web' for the moment under your development mode.
Solved:
devtool: '#eval-source-map'
Includes a source map in the output
Original issue
As stated, the webpack build produces an enormous bundle/vendor file with Vue as my only import. I cannot see for the life of me how people get it down to 80kb.
As far as I can see, there is a vue-loader and the file gets minified, so why would it come out enormous?
var path = require('path') var webpack = require('webpack')
module.exports = { entry: './src/main.js', output: {
path: path.resolve(__dirname, './static'),
publicPath: '/static/',
filename: 'js/login-view.js' }, module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]',
useRelativePath: true,
publicPath: './static/images/'
}
}
] }, resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json'] }, devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true }, performance: {
hints: false }, devtool: '#eval-source-map' }
if (process.env.NODE_ENV === 'production') { // module.exports.devtool = '#source-map' // http://vue-loader.vuejs.org/en/workflow/production.html module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: false,
// compress: true,
compress: {
warnings: false
},
mangle: true,
}),
new webpack.LoaderOptionsPlugin({
minimize: true
}) ]) }
devtool: '#eval-source-map'
was the culprit. It was getting included in all builds and it puts the sourcemap in the files. I removed this and dropped the file to ~90kb.
I'm trying to improve my WebPack performance so I switched out TS-Loader for Awesome-TypeScript-Loader, and my compile times only increased a tiny bit. I had heard ATL is supposed to be much faster, but I only shaved off maybe a few 100ms.
Here's my webpack.config.js:
'use strict';
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
const CleanWebpackPlugin = require('clean-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const WebpackNotifierPlugin = require('webpack-notifier');
const { CheckerPlugin, TsConfigPathsPlugin } = require('awesome-typescript-loader')
// const ExtractTextPlugin = require('extract-text-webpack-plugin')
// borrowed from the ng2 seed
const entryPoints = ['inline', 'polyfills', 'sw-register', 'styles', 'vendor', 'app'];
const htmlConfig = {
template: 'client/_index.html',
filename: 'index.html',
// borrowed from the ng2 seed
chunksSortMode: (left, right) => {
const leftIndex = entryPoints.indexOf(left.names[0]);
const rightIndex = entryPoints.indexOf(right.names[0]);
if (leftIndex > rightIndex) {
return 1;
} else if (leftIndex < rightIndex) {
return -1;
} else {
return 0;
}
}
};
function isExternal(module) {
const match = typeof module.userRequest === 'string' &&
/node_modules/.test(module.userRequest.split('!').pop());
return match;
}
// const extractCSS = new ExtractTextPlugin({ filename: '[name].[hash].css', allChunks: true })
// const extractJS = new ExtractTextPlugin({ filename: '[name].[hash].js', allChunks: true })
module.exports = {
cache: true,
entry: {
polyfills: './client/app/polyfills.js',
// base: './client/base.js',
app: './client/app/app.ts'
},
output: {
// Absolute output directory
path: path.join(__dirname, '/dist/'),
// Output path from the view of the page
// Uses webpack-dev-server in development
publicPath: '/',
// Filename for entry points
// Only adds hash in build mode
filename: '[name].[hash].js',
// Filename for non-entry points
// Only adds hash in build mode
chunkFilename: '[name].[hash].js'
},
resolve: {
modules: [
path.resolve(__dirname, 'client'),
'node_modules'
],
extensions: ['.ts', '.js'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'vue-router$': 'vue-router/dist/vue-router.esm.js',
'vuex$': 'vuex/dist/vuex.esm.js',
'vuex-class$': 'vuex-class/dist/vuex-class.cjs.js',
'styles': path.resolve(__dirname, 'client/app/styles'),
'core': path.resolve(__dirname, 'client/app/core'),
'components': path.resolve(__dirname, 'client/app/components'),
'containers': path.resolve(__dirname, 'client/app/containers'),
'assets': path.resolve(__dirname, 'client/assets'),
'config': path.resolve(__dirname, 'client/config')
}
},
// Use 'source-map' for more accurate source mapping
// Use 'cheap-module-eval-source-map' for faster rebuilding
devtool: 'cheap-module-eval-source-map',
module: {
rules: [
{
// ES LINT LOADER
// Reference: https://github.com/MoOx/eslint-loader
// Lint ECMAScript
enforce: 'pre',
test: /\.js$/,
use: [
{ loader: 'eslint-loader', options: { cache: true } }
],
include: [path.resolve(__dirname, 'client')]
},
{
// TS LINT LOADER
// Reference: https://github.com/wbuchwalter/tslint-loader
// Lint TypeScript
enforce: 'pre',
test: /\.ts$/,
use: ['tslint-loader'],
include: [path.resolve(__dirname, 'client')]
},
{
// SOURCE MAP LOADER
// Reference: https://github.com/webpack-contrib/source-map-loader
// Extracts SourceMaps for source files that as added as sourceMappingURL comment
enforce: 'pre',
test: /\.(j|t|s?(a|c)s)s$/, // ts or js or css or scss or sass (or ass)
use: ['source-map-loader'],
exclude: [path.resolve(__dirname, 'node_modules/css-loader/lib/convert-source-map.js')] // There is a sourceMappingURL example in this file that triggers a warning
},
{
// JS LOADER
// Reference: https://github.com/babel/babel-loader
// Transpile .js files using babel-loader
// Compiles ES6 and ES7 into ES5 code
test: /\.js$/,
use: [
{ loader: 'babel-loader', options: { sourceMap: true, cacheDirectory: true } }
],
exclude: [path.resolve(__dirname, 'node_modules')]
},
{
// AWESOME TYPESCRIPT LOADER
// Reference: https://github.com/s-panferov/awesome-typescript-loader
// Transpile .ts files using awesome-typescript-loader
// Compiles TS into ES6 code
test: /\.ts$/,
use: [
// { loader: 'babel-loader', options: { sourceMap: true, cacheDirectory: true } },
// { loader: 'ts-loader' }
{ loader: 'awesome-typescript-loader', options: { sourceMap: true, useCache: true, useBabel: true, useTranspileModule: true } }
],
exclude: [path.resolve(__dirname, 'node_modules')]
},
{
// ASSET LOADER
// Reference: https://github.com/webpack/url-loader
// Copy png, jpg, jpeg, gif, svg, woff, woff2, ttf, eot files to output
// Rename the file using the asset hash
// Pass along the updated reference to your code
// You can add here any file extension you want to get copied to your output
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot|mp4)([?]?.*)$/,
use: [
{ loader: 'file-loader', options: { name: 'assets/[name].[hash].[ext]' } }
]
},
{
// HTML LOADER
// Reference: https://github.com/webpack/html-loader
// Allow loading html through js
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: {
sourceMap: true,
exportAsEs6Default: true,
root: path.resolve(__dirname, 'client'),
// Look for and process the following tag:attr on html elements
attrs: [
'img:src',
'video:src'
]
}
}
]
},
{
// CSS LOADER
// Reference: https://github.com/webpack-contrib/css-loader
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { sourceMap: true, importLoaders: 1 } },
{ loader: 'postcss-loader', options: { sourceMap: true } }
]
},
{
// SASS LOADER
// Reference: https://github.com/jtangelder/sass-loader
test: /\.s(a|c)ss$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { sourceMap: true, importLoaders: 2 } },
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: 'sass-loader', options: { sourceMap: true } }
]
}
]
},
plugins: [
new webpack.LoaderOptionsPlugin({
cache: true,
debug: true,
minimize: false
}),
new webpack.NamedModulesPlugin(),
new WebpackNotifierPlugin(),
new TsConfigPathsPlugin(),
new CheckerPlugin(),
new StyleLintPlugin({
files: ['./client/**/*.s?(a|c)ss']
}),
// Remove dist and build directories before building
new CleanWebpackPlugin(['dist']),
// extractCSS,
new CommonsChunkPlugin({
name: 'vendor',
// Only analyze the app entry point, we don't want to change the others
chunks: ['app'],
// Check if module is in node_modules
minChunks: (module) => {
return isExternal(module);
}
}),
new HtmlWebpackPlugin(htmlConfig)
],
devServer: {
historyApiFallback: true,
compress: false,
inline: true,
hot: true
}
};
And my tsconfig.json:
{
"compilerOptions": {
"allowJs": true,
"target": "ES2017",
"module": "ES2015",
"moduleResolution": "Node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"noEmitHelpers": true,
"importHelpers": true,
"pretty": true,
"alwaysStrict": true,
"lib": [
"DOM",
"ES2017",
"DOM.Iterable",
"ScriptHost"
],
"baseUrl": ".",
"paths": {
"styles/*": ["./client/app/styles/*"],
"core/*": ["./client/app/core/*"],
"components/*": ["./client/app/components/*"],
"containers/*": ["./client/app/containers/*"],
"assets/*": ["./client/assets/*"],
"config/*": ["./client/config/*"]
}
}
}
And the .babelrc file:
{
"presets": [
[
"env", {
"modules": false,
"useBuiltIns": true,
"debug": true,
"targets": {
"browsers": [
"last 1 Chrome version"
]
}
}]
]
}
I'm targeting ES2017 from TS and leaving it up to Babel to compile for our target browser; as in development we want the extra performance of native code, and less difference of the transpiled coutput.
It seems to be hung up on Babel, especially, as it gets bogged down in the "asset optimization" stage.
TS-loader + Babel: ~1500ms
ATL + Babel: ~1100ms
ATL - Babel: ~800ms
Also, I don't see any performance difference with ATL between useCache: true/false nor useTranspileModule: true/false. But I do see it making a TON of files in the .awcache folder, every time it recompiles (wondering if something is cache busting).
Running webpack-dev-server with params:
webpack-dev-server --watch --hot --progress --open
Using the latest versions of all packages, loaders, and tools as of this post.
Any help would be greatly appreciated!
Thanks!
I'm trying to figure out how to have a single webpack config file that works for transforming both server (node.js) js and client js with the es2015 preset. Currently I have to specifically set "target: 'node'" for it to correctly process node-based files. If I don't, then webpack does the transformation based on the default "target: 'web'". It then reports errors because the 'mysql' module being imported clearly won't work for web.
How can I unify both into the same config file so that server and client js will be transformed separately? Or do I need separate configs entirely?
Sample webpack.config.js
'use strict';
var path = require('path');
var webpack = require('webpack');
module.exports = {
target: 'node',
resolve: {
root: path.resolve(__dirname),
extensions: ['', '.js']
},
entry: [
'babel-polyfill',
'./index.js',
],
output: {
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015']
}
}
]
}
};
Sample js code
import 'babel-polyfill';
import mysql from 'mysql';
class Test {
constructor () {
}
get read () {
}
};
You can pass multiple configs for Webpack to process at the same time. Simply return an array of configuration objects.
export default [
{
// config 1 here
},
{
// config 2 here
},
];
Extra tip: if you use .babel.js as extension for your config file, Webpack will run it through Babel for you, which allows you to use ES6 in your Webpack config.
Bonus: the snippet below
// Source: https://gist.github.com/Ambroos/f23d517a4261e52b4591224b4c8df826
import webpack from 'webpack';
import path from 'path';
import CleanPlugin from 'clean-webpack-plugin';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import AssetsPlugin from 'assets-webpack-plugin';
import CompressionPlugin from 'compression-webpack-plugin';
import autoprefixer from 'autoprefixer';
import rucksack from 'rucksack-css';
import cssnano from 'cssnano';
import moment from 'moment';
const sharedPlugins = [
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /nl/),
new webpack.optimize.AggressiveMergingPlugin({}),
new webpack.optimize.OccurenceOrderPlugin(true),
new webpack.optimize.UglifyJsPlugin({
compress: {
drop_console: true,
screw_ie8: true,
sequences: true,
properties: true,
dead_code: true,
drop_debugger: true,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
if_return: true,
join_vars: true,
cascade: true,
negate_iife: true,
hoist_funs: true,
warnings: false,
},
mangle: {
screw_ie8: true,
},
output: {
screw_ie8: true,
preamble: '/* Website - ' + moment().format() + ' */',
},
}),
];
const sharedServerPlugins = [
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /nl/),
new webpack.optimize.AggressiveMergingPlugin({}),
new webpack.optimize.OccurenceOrderPlugin(true),
new webpack.optimize.UglifyJsPlugin({
compress: {
drop_console: false,
screw_ie8: true,
sequences: true,
properties: true,
dead_code: true,
drop_debugger: false,
conditionals: true,
comparisons: true,
evaluate: true,
booleans: true,
loops: true,
unused: true,
if_return: true,
join_vars: true,
cascade: true,
negate_iife: true,
hoist_funs: true,
warnings: false,
},
mangle: {
screw_ie8: true,
},
output: {
screw_ie8: true,
preamble: '/* Website - ' + moment().format() + ' */',
},
}),
];
const PATHS = {
build: path.resolve(__dirname, '..', 'build'),
sourcemaps: path.resolve(__dirname, '..', 'build', 'sourcemaps'),
browserSource: path.resolve(__dirname, '..', 'src', 'browser', 'index.js'),
browserBuild: path.resolve(__dirname, '..', 'build', 'browser'),
serverSource: path.resolve(__dirname, '..', 'src', 'server', 'index.js'),
serverAssetsSource: path.resolve(__dirname, '..', 'src', 'server', 'assets', 'index.js'),
serverBuild: path.resolve(__dirname, '..', 'build', 'server'),
};
export default [
// Browser
{
entry: { browser: PATHS.browserSource },
output: {
path: PATHS.browserBuild,
filename: 's/[chunkhash].js',
chunkFilename: 's/async-[chunkhash].js',
publicPath: '/',
sourceMapFilename: '../sourcemaps/browser/[file].map',
},
devtool: 'hidden-source-map',
plugins: [
new AssetsPlugin({
prettyPrint: true,
path: path.resolve(PATHS.build, 'browserAssets'),
filename: 'index.js',
processOutput: assets => `module.exports = ${JSON.stringify(assets, null, ' ')};`,
}),
new CleanPlugin([PATHS.browserBuild, PATHS.sourcemaps], path.resolve(PATHS.build, 'browserAssets')),
new ExtractTextPlugin('s/[contenthash].css'),
new CompressionPlugin({
asset: '{file}.gz',
algorithm: 'gzip',
regExp: /\.js$|\.html$|\.css$|\.svg$|\.eot$|\.xml$/,
threshold: 1400,
minRation: 0.8,
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
WEBPACK_ENV: JSON.stringify('browser'),
APP_ENV: (process.env.APP_ENV && JSON.stringify(process.env.APP_ENV)) || undefined,
},
}),
].concat(sharedPlugins),
externals: [
{ browserConfig: 'var websiteBrowserConfig' },
{ programs: 'var programs' },
],
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
},
{
test: /\.json$/,
loader: 'json',
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract(
'style',
[
'css?importLoaders=2&localIdentName=css-module-[hash:base64]',
'postcss',
'sass',
]
),
},
{
test: /\.(gif|png|jpe?g|svg|ico)$/i,
loaders: [
'url?limit=1400&name=s/i/[sha512:hash:base64:16].[ext]',
'image-webpack?bypassOnDebug',
],
},
{
test: /isotope\-|fizzy\-ui\-utils|desandro\-|masonry|outlayer|get\-size|doc\-ready|eventie|eventemitter/,
loader: 'imports?define=>false&this=>window',
},
{
test: /flickity/,
loader: 'imports?define=>false&this=>window',
},
{
test: /node_modules\/unipointer/,
loader: 'imports?define=>undefined',
},
],
},
postcss: () => {
return [rucksack, autoprefixer, cssnano];
},
},
// Server assets
{
entry: { assets: PATHS.serverAssetsSource },
target: 'node',
output: {
path: PATHS.browserBuild,
libraryTarget: 'commonjs',
filename: '../serverAssets/index.js',
publicPath: '/',
},
plugins: [
// assetsWriter,
new CompressionPlugin({
asset: '{file}.gz',
algorithm: 'gzip',
regExp: /\.js$|\.html$|\.css$|\.svg$|\.eot$|\.xml$/,
threshold: 1400,
minRation: 0.8,
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
WEBPACK_ENV: JSON.stringify('assets'),
APP_ENV: (process.env.APP_ENV && JSON.stringify(process.env.APP_ENV)) || undefined,
},
}),
].concat(sharedPlugins),
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
},
{
test: /\.json$/,
loader: 'json',
},
{
test: /\.(gif|png|jpe?g|svg|ico)$/i,
loaders: [
'url?limit=1400&name=s/i/[sha512:hash:base64:16].[ext]',
'image-webpack?bypassOnDebug',
],
},
],
},
},
// Server
{
entry: PATHS.serverSource,
target: 'node',
output: {
path: PATHS.build,
libraryTarget: 'commonjs',
filename: 'server/server.js',
publicPath: '/s/',
sourceMapFilename: 'sourcemaps/browser/[file].map',
},
externals: [
{ serverAssets: '../serverAssets/index.js' },
{ browserAssets: '../browserAssets/index.js' },
{ vrtConfig: '../../env_vars.js' },
/^(?!\.|\/).+/i,
/webpack-assets\.json/,
],
plugins: [
new CleanPlugin(PATHS.serverBuild),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
WEBPACK_ENV: JSON.stringify('server'),
APP_ENV: (process.env.APP_ENV && JSON.stringify(process.env.APP_ENV)) || undefined,
},
}),
].concat(sharedServerPlugins),
node: {
__dirname: false,
__filename: false,
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
},
{
test: /\.json$/,
loader: 'json',
},
],
},
},
];
That is the config we use in one of our sites with a partially shared codebase, and partially shared assets. It consists of three Webpack builds in one:
Browser
Server assets (images/fonts/... that will be referenced in server-generated HTML)
Server code (Node)
The server code has a few special properties:
target: 'node' (Webpack needs this)
output.libraryTarget: 'commonjs' (makes Webpack use commonjs for unbundled libs)
externals: [ /^(?!\.|\/).+/i, ] (makes Webpack not bundle anything in node_modules, or anything that is not a relative path (starting with . or /)
This combination makes Webpack only process your own code, and access other modules and libraries through require. Which means your dependencies using native bindings won't break as they won't be bundled.