Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

On webpack how can I import a script without evaluate it?

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

enter image description here

↑↑↑↑↑↑↑↑ 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?

like image 950
小广东 Avatar asked Jan 21 '20 10:01

小广东


People also ask

How import works in webpack?

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.

How do I include a JavaScript file in webpack?

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.

Does webpack use CommonJS?

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.

What is webpackChunkName?

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.


1 Answers

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:

  • Gather all the import(args) statements in the code
  • If the import(args) contains /* prefetch: true */ comment
  • Find the chunkId from the import() statement
  • Replace it with Prefetcher.fetch(chunkId)

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

like image 155
小广东 Avatar answered Sep 28 '22 05:09

小广东