Incremental build performance issues
See original GitHub issueI’m experiencing some incremental build performance issues. These are taken by sampling the Time output from webpack incremental builds.
RRWP+babel+ts-loader+ForkTsCheckerWebpackPlugins: 11-17 s RRWP+babel+ts: 9-16 s babel+ts-loader+ForkTsCheckerWebpackPlugin: 1.8-2.0s babel+ts-loader: 1.5s-1.7s babel: 1.4-2.1 s ts-loader+ForkTsCheckerWebpackPlugin: 1.1-1.9 s
It looks like RRWP is adding 8-15 seconds build time to my typescript react project.
The config is as follows: webpack.common.js
const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
module.exports = {
target: 'web',
entry: {
core: [
path.resolve(__dirname, 'ts/core/polyfill.ts'),
path.resolve(__dirname, 'ts/core/core.ts'),
],
reports: [
path.resolve(__dirname, 'ts/core/polyfill.ts'),
path.resolve(__dirname, 'ts/core/reports.ts'),
],
app: [path.resolve(__dirname, 'ts/apps/index.tsx')],
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json', '.html'],
alias: {
Shared: path.resolve(__dirname, 'ts/shared'),
appA: path.resolve(__dirname, 'ts/apps/appA'),
appB: path.resolve(__dirname, 'ts/apps/appB'),
},
},
module: {
rules: [
// All image files will be handled here
{
test: /\.(png|svg|jpg|gif)$/,
loader: 'file-loader',
},
// All font files will be handled here
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
},
// All files with ".html" will be handled
{ test: /\.html$/, loader: 'html-loader' },
// All output ".js" files will have any sourcemaps re-processed by "source-map-loader".
{ enforce: 'pre', test: /\.js$/, exclude: [/node_modules/], loader: 'source-map-loader' },
],
},
plugins: [
// Clean dist folder.
new CleanWebpackPlugin({ verbose: true }),
// Split out library into seperate bundle and remove from app bundle.
new webpack.HashedModuleIdsPlugin(),
// avoid publishing when compilation failed.
new webpack.NoEmitOnErrorsPlugin(),
new HtmlWebpackPlugin({
inject: false,
title: null,
chunks: ['common', 'app', 'core'],
heads: ['common', 'core'],
bodys: ['app'],
filename: '../Views/Shared/_Layout.cshtml',
template: './Views/Shared/_Layout_Template.cshtml',
appMountId: 'react-app',
}),
new HtmlWebpackPlugin({
inject: false,
title: null,
chunks: ['common', 'core'],
heads: ['common', 'core'],
bodys: [],
filename: '../Views/Shared/_ExternalLayout.cshtml',
template: './Views/Shared/_ExternalLayout_Template.cshtml',
}),
new HtmlWebpackPlugin({
inject: false,
title: null,
chunks: ['common', 'reports'],
heads: ['common', 'reports'],
bodys: [],
filename: '../Views/Shared/_ReportLayout.cshtml',
template: './Views/Shared/_reportLayout_Template.cshtml',
}),
new CopyWebpackPlugin([
'ts/core/dependencies/telerik-report-viewer/telerikReportViewerTemplate-sass.html',
]),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how Webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new ForkTsCheckerWebpackPlugin(),
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
// Turn off performance hints during development because we don't do any
// splitting or minification in interest of speed. These warnings become
// cumbersome.
performance: {
hints: false,
},
// pretty terminal output
stats: { colors: true },
// Set up chunks
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
commons: {
name: 'common',
chunks: 'initial',
minChunks: 2,
},
},
},
},
};
and webpack.dev.js
const webpack = require('webpack');
const Merge = require('webpack-merge');
const CommonConfig = require('./webpack.common.js');
const postcssConfig = require('./postcss-config');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const babelLoader = {
loader: 'babel-loader?cacheDirectory', //require.resolve('babel-loader'),
options: {
presets: ['@babel/react', '@babel/typescript', ['@babel/env', { modules: false }]],
plugins: [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator',
'react-refresh/babel',
],
},
};
module.exports = Merge(CommonConfig, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
headers: {
'Access-Control-Allow-Origin': 'http://localhost:2354',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
},
writeToDisk: true,
hot: true,
},
output: {
filename: '[name].js',
path: __dirname + '/dist',
publicPath: 'http://localhost:8080/dist/',
pathinfo: false,
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: [
babelLoader,
{
loader: 'ts-loader',
options: {
transpileOnly: true,
experimentalWatchApi: true,
},
},
],
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [babelLoader],
},
{
// All css files will be handled here
oneOf: [
{
test: /^((?!\.module).)*scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
sourceMap: true,
},
},
postcssConfig,
{
loader: 'sass-loader',
options: {
implementation: require('node-sass'),
sourceMap: true,
},
},
],
},
{
test: /\.module.scss$/,
use: [
'style-loader',
{
loader: 'typings-for-css-modules-loader',
options: {
namedExport: true,
camelCase: true,
importLoaders: 2,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
modules: true,
sourceMap: true,
},
},
postcssConfig,
{
loader: 'sass-loader',
options: {
implementation: require('node-sass'),
sourceMap: true,
},
},
],
},
// All files with ".less" will be handled and transpiled to css
{
test: /^((?!\.module).)*less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
sourceMap: true,
},
},
postcssConfig,
{
loader: 'less-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /\.module.less$/,
use: [
'style-loader',
{
loader: 'typings-for-css-modules-loader',
options: {
namedExport: true,
camelCase: true,
importLoaders: 2,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
modules: true,
sourceMap: true,
},
},
postcssConfig,
{
loader: 'less-loader',
options: {
sourceMap: true,
},
},
],
},
{
test: /^((?!\.module).)*css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
sourceMap: true,
},
},
postcssConfig,
],
},
{
test: /module.css$/,
use: [
'style-loader',
{
loader: 'typings-for-css-modules-loader',
options: {
namedExport: true,
camelCase: true,
importLoaders: 2,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
modules: true,
sourceMap: true,
},
},
postcssConfig,
],
},
],
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
},
PRODUCTION: false,
}),
new ReactRefreshWebpackPlugin({ disableRefreshCheck: true }),
],
});
Issue Analytics
- State:
- Created 4 years ago
- Comments:11 (5 by maintainers)
Top Results From Across the Web
Improving the speed of incremental builds - Apple Developer
When a target has many dependencies, or when it depends on large, monolithic modules, Xcode must serialize more tasks. To improve build performance,...
Read more >Angular incremental build performance problems for existing ...
Current Behavior It seems to be the case that when enabling incremental build for Angular apps (following this guide ...
Read more >Build Performance - webpack
This guide contains some useful tips for improving build/compilation performance. General. The following best practices should help, whether you're running ...
Read more >Improve Visual Studio Build Performance - NDepend
The procedure to know if your solution has a problem with incremental build is easy: first use the command Build > Rebuild Solution...
Read more >Incremental Builds - Nx
In an incremental build scenario, when building the app, all it's dependencies need to be built first. In our scenario above, that means...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I don’t have time to look at this until Sunday night, but from what I read from the Webpack docs, removing
addDependency
is safe, because the file is static. I am guessing thataddDependency
broke Webpack’s default caching behaviour, so thus why addingcacheable
could fix that.Moving the require outside of the loader should further ensure better caching since Node will cache it.
Yeah definitely. I actually ended up moving the require outside of the loader along with removing the dependency. I’ll make a pr too for @pmmmwh to look at whenever there’s free time!