I'm recently working on some website optimization works, and I start using code splitting in webpack by using import statement like this:
import(/* webpackChunkName: 'pageB-chunk' */ './pageB')
Which correctly create the pageB-chunk.js, now let's say I want to prefetch this chunk in pageA, I can do it by add this statement in pageA:
import(/* webpackChunkName: 'pageB-chunk' */ /* webpackPrefetch: true */ './pageB')
Which will result in a
<link rel="prefetch" href="pageB-chunk.js">
being append to HTML's head, then the browser will prefetch it, so far so good.
The problem is the import statement I use here not just prefetch the js file, but also evaluate the js file, means the code of that js file is parsed & compile to bytecodes, the top-level code of that JS is executed.
This is a very time-consuming operation on a mobile device and I want to optimize it, I only want the prefetch part, I don't want the evaluate & execute part, because later when some user interactions happen, I will trigger the parsing & evaluate myself
↑↑↑↑↑↑↑↑ I only want to trigger the first two steps, pictures come from https://calendar.perfplanet.com/2011/lazy-evaluation-of-commonjs-modules/ ↑↑↑↑↑↑↑↑↑
Sure I can do this by adding the prefetch link myself, but this means I need to know which URL I should put in the prefetch link, webpack definitely knows this URL, how can I get it from webpack?
Does webpack have any easy way to achieve this?
The chunk will be fetched on the first call to import() , and subsequent calls to import() will use the same network response. Note that this only makes sense in the case of a partially dynamic statement, e.g. import(`./locales/${language}. json`) , where multiple module paths that can potentially be requested.
You can bundle your JavaScript using the CLI command by providing an entry file and output path. Webpack will automatically resolve all dependencies from import and require and bundle them into a single output together with your app's script.
As you may know, webpack supports a couple of module types out of the box, including both CommonJS and ES modules. Webpack also works on both client- and server-side JavaScript, so with webpack, we can also easily handle assets and resources like images, fonts, stylesheets, and so on.
webpackChunkName: A name for the new chunk. Since webpack 2.6. 0, the placeholders [index] and [request] are supported within the given string to an incremented number or the actual resolved filename respectively. You can use [request] placeholder to set dynamic chunk name.
Updates: I include all the things into a npm package, check it out! https://www.npmjs.com/package/webpack-prefetcher
After few days of research, I end up with writing a customize babel plugin...
In short, the plugin work like this:
Prefetcher is a helper class that contain the manifest of webpack output, and can help us on inserting the prefetch link:
export class Prefetcher {
static manifest = {
"pageA.js": "/pageA.hash.js",
"app.js": "/app.hash.js",
"index.html": "/index.html"
}
static function fetch(chunkId) {
const link = document.createElement('link')
link.rel = "prefetch"
link.as = "script"
link.href = Prefetcher.manifest[chunkId + '.js']
document.head.appendChild(link)
}
}
An usage example:
const pageAImporter = {
prefetch: () => import(/* prefetch: true */ './pageA.js')
load: () => import(/* webpackChunkName: 'pageA' */ './pageA.js')
}
a.onmousehover = () => pageAImporter.prefetch()
a.onclick = () => pageAImporter.load().then(...)
The detail of this plugin can found in here:
Prefetch - Take control from webpack
Again, this is a really hacky way and I don't like it, if u want webpack team to implement this, pls vote here:
Feature: prefetch dynamic import on demand
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