I am trying to optimize the build and bundle size of my project. However, whenever I run npm run build
it does not create any bundle chunk files under my /dist
folder. However npm run dev
creates a the bundle chunks under my /dist
folder just fine. The only difference between the two npm scripts is that build
uses my webpack.prod
configurations and dev
uses my webpack.dev
configuration.
The output of npm run build
in my terminal seems to indicate that it's creating all the chunks that I specified (I create one chunk for the main bundle and one chunk for each node module to minimize the bundles a user needs to download whenever we update our project).
I'm not sure if there's some default behavior in Webpack's production mode that's causing this.
npm run build
Output:
Here are my two Webpack configuration files:
Webpack.prod:
module.exports = env => {
// Get the root path (assuming your webpack config is in the root of your project!)
const currentPath = path.join(__dirname);
// Create the fallback path (the production .env)
const basePath = currentPath + '/.env';
// We're concatenating the environment name to our filename to specify the correct env file!
const envPath = basePath + '.' + env.ENVIRONMENT;
// Check if the file exists, otherwise fall back to the production .env
const finalPath = fs.existsSync(envPath) ? envPath : basePath;
return {
mode: 'production',
entry: ['babel-polyfill', 'react', 'react-dom', './src/Index.tsx'],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist/')
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".json"]
},
watch: false,
devServer: {
contentBase: 'dist',
port: 3000,
historyApiFallback: true,
inline: true,
https: true
},
optimization: {
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like @ symbols
return `npm.${packageName.replace('@', '')}`;
},
},
},
}
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader",
exclude: [
/node_modules/,
],
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: [
/node_modules/,
],
},
{
test: /\.(png|gif|jpg|woff|eot|ttf|svg|woff2|ico)$/i,
use: "file-loader?name=images/[name].[ext]",
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(config)$/,
use: "file-loader?name=[name].[ext]"
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: "index.html",
filename: "index.html",
}),
new TSLintPlugin({
files: ['./src/**/*.ts']
}),
new CopyWebpackPlugin([
{ from: './src/favicon.ico' },
{ from: './data/*.json', to: path.resolve(__dirname, 'dist/'), force: true },
], {}),
new Dotenv({
path: finalPath
})
]
}
};
Webpack.dev:
module.exports = env => {
// Get the root path (assuming your webpack config is in the root of your project!)
const currentPath = path.join(__dirname);
// Create the fallback path (the production .env)
const basePath = currentPath + '/.env';
// We're concatenating the environment name to our filename to specify the correct env file!
const envPath = basePath + '.' + env.ENVIRONMENT;
// Check if the file exists, otherwise fall back to the production .env
const finalPath = fs.existsSync(envPath) ? envPath : basePath;
return {
mode: 'development',
devtool: "inline-source-map",
entry: ['babel-polyfill', 'react', 'react-dom', './src/Index.tsx'],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist/')
},
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json"]
},
watch: false,
// Enable sourcemaps for debugging webpack's output.
devServer: {
contentBase: 'dist',
historyApiFallback: true,
inline: true,
port: 3000,
https: true
},
optimization: {
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like @ symbols
return `npm.${packageName.replace('@', '')}`;
},
},
},
}
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{
test: /\.tsx?$/,
loader: "ts-loader"
},
{
test: /\.(png|gif|jpg|woff|eot|ttf|svg|woff2|ico)$/i,
use: "file-loader?name=images/[name].[ext]",
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader",
exclude: [/node_modules/, /build/, /__test__/],
},
{
test: /\.(config)$/,
use: "file-loader?name=[name].[ext]"
},
{
test: /\.js$/,
loader: 'babel-loader'
}
]
},
// When importing a module whose path matches one of the following, just
// assume a corresponding global variable exists and use that instead.
// This is important because it allows us to avoid bundling all of our
// dependencies, which allows browsers to cache those libraries between builds.
externals: {
// "react": "React",
// "react-dom": "ReactDOM"
},
performance: { hints: false },
plugins: [
new HtmlWebpackPlugin({
template: "index.html",
filename: "index.html",
}),
new TSLintPlugin({
files: ['./src/**/*.ts']
}),
new CopyWebpackPlugin([
{ from: './src/favicon.ico' },
{ from: './data/*.json', to: path.resolve(__dirname, 'dist/'), force: true } ,
], {}),
new Dotenv({
path: finalPath
})
]
}
};
I figured it out. By default, Webpack's production mode sets the property onEmitOnErrors
under optimization
to true. I'm using TypeScript and because I had an unresolved type error (it did not break the application so it wasn't critical), the build wasn't emitted by Webpack.
I hope this helps!