I've been optimizing the load time of my app and after some quick wins with optimizing my code I've noticed there seems to be a 500ms long intialization phase where all the require statements seems to be resolved, or something.
Can this be optimized and how?
I am using webpack, react and couple dozens of npm packages. The result file is 2.8M unzipped and around 900k zipped. There is not a huge amount of code of the app itself, its mostly npm packages.
I wonder if I can just compile this differently to avoid all the requires and what not in real time.
Update: I am using production build with dedupe plugin currently.
As some comments have already pointed out, we have to differentiate between build- and run-time. The referenced guide from the webpack docs is about build performance.
While not using devtools like source maps and minifying code has impacts on the execution speed, I think the most important one is chunking/lazy loading (as estus has already pointed out).
You should decide which parts of your application are not needed for the initial render. These parts should be moved into another chunk and loaded lazily via require.ensure()
.
Usually your router is a typical place to load stuff asynchronously:
<Router>
<Route
path="/dashboard"
getComponent={loadPage("Dashboard")}
/>
</Router>
function loadPage(page) {
return (location, cb) => pages[page](cb);
}
const pages = {
Dashboard(cb) {
require.ensure(
["./Dashboard.js"],
require => cb(null, require("./Dashboard.js").default)
// .default is required in case you are using ES2015 modules
);
}
};
Now, all modules that are only needed on the Dashboard
will be moved into a separate chunk.
The verbose require.ensure
part can even be optimized by moving all top-level components (I call them pages
here) into a dedicated folder like pages
. Then you can configure webpack to always load these things asynchronously by using the bundle-loader:
// webpack.config.js
...
{
test: /\.jsx$/,
include: [
path.resolve("path", "to", "pages"),
],
loaders: [
"bundle-loader?" + JSON.stringify({
lazy: true
})
]
},
Then your router looks like:
// This does not actually import the Dashboard,
// but a function which loads the dashboard.
import Dashboard from "path/to/pages/Dashboard";
function loadPage(page) {
return (location, cb) => pages[page](module => {
cb(null, module.default);
});
}
const pages = {
Dashboard
};
And if you're super-lazy and you only want to refer to the same filename without creating a pages
-Object manually, you can also use require contexts:
function loadPage(page) {
return (location, cb) =>
require("./path/to/pages/" + page + ".jsx")(
module => cb(null, module.default)
);
}
One thing you could do is to play around with the devTool config and change the way you generate your sourcemaps. That should speed things up a bit at the expense of ease of debugging.
Webpack actually has a great little guide on how to optimise performance here http://webpack.github.io/docs/build-performance.html.
Basically it boils down to how much debugging information you feel you need.
By setting
{
devtool: "#source-map"
}
You preserve the original code, which is obviously the easiest to debug, but this comes at the expense of files size / build time.
Updated: As per Chris' comment below, here is another guide
I don't believe that your timeline comes from minify code (compare __webpack_require__
in maped files and f
in minify code).
I will show that minify and some plugins can reduce two times running time of this script. In webpack configs I will show only the main difference between to configurations.
webpack.config.js
devtool: 'cheap-module-eval-source-map',
cache: true,
debug: true,
Timeline - 473 ms
webpack.config.js
plugins: [
'transform-react-remove-prop-types',
'transform-react-constant-elements',
'transform-react-inline-elements'
],
cache: false,
debug: false,
plugins: [
// Search for equal or similar files and deduplicate them in the output
// https://webpack.github.io/docs/list-of-plugins.html#dedupeplugin
new webpack.optimize.DedupePlugin(),
// Minimize all JavaScript output of chunks
// https://github.com/mishoo/UglifyJS2#compressor-options
new webpack.optimize.UglifyJsPlugin({
compress: {
screw_ie8: true,
warnings: false,
},
}),
// A plugin for a more aggressive chunk merging strategy
// https://webpack.github.io/docs/list-of- plugins.html#aggressivemergingplugin
new webpack.optimize.AggressiveMergingPlugin(),
]
Timeline - 228 ms
If you would like to analize in depth webpack.config.js
from this explanation you can take a look at source code from react-starter-kit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With