Why “Import on Demand”

On-demand loading is generally distinct from asynchronous loading, but this article covers similar scenarios where resources are taken or removed “as needed,” so the “on-demand” in the title represents a general concept of these practices.

As the size of the project increases, if we do not intervene, we may encounter a series of problems such as slow loading of the project homepage, large chunk volume, unseparated environment configuration, and manual elimination of debugging code, among which many problems are caused by unreasonable construction behavior. This article shares some “import on demand” implementations of these issues.

Asynchronous loadingimport()

The import() syntax is divided into static import and dynamic import.

Static import needless to say, dynamic import has also been implemented in ES6. Import will be a global function in an ES6 syntax-enabled environment that accepts the address of the script to be dynamically imported, returns a Promise, and its asynchronous return value will be an object containing the exported information of the dynamically imported module.

For compatibility, Webpack will compile the import() syntax and convert it to WebpackJsonp loading. Webpack packs the imported modules into a separate chunk, and when needed, requests them locally and runs them by injecting

Native use of ES6

Webpack compilation results

Introduce as neededbabel-plugin-import

Babel-plugin-import is a Babel plug-in that handles module imports.

Its on-demand processing of the tripartite library is somewhat conventional in its default configuration, requiring the tripartite library to have a lib folder and a module file with the same name as the tripartite library (Camel-case). In addition to the default, it also provides a set of configurations that allow us to customize the import form of the tripartite library. This feature allows you to import different modules depending on the environment, component libraries on demand, tool libraries on demand, and so on.

Using the default configuration as an example, import the Ant Design component library on demand

The configuration file.babelrc

Business code

Compile the results

We can clearly see that the Button component that was imported directly from ANTd was compiled to be imported from ANTd /lib/button.

Use custom configurations as an example to introduce Ant Design component libraries on demand

The configuration filebabel.config.js

We can also customize the customName function to change the import path. Use methods and other configurations can be found on the Babel website.

As an aside, we could also write our own Babel plug-in to implement on-demand imports to internal libraries by intercepting the ImportDeclaration node in the custom Babel plug-in visitor configuration and deciding which other module path to replace based on the node configuration.

Take the example of the custom Babel plug-in introduced on demand

This is part of a custom Babel plug-in our team made that implements something like import {ABC} from ‘XXX ‘; The effect of converting to import ABC from ‘XXX /lib/abc.js at compile time is very similar to the effect of babel-plugin-import.

Tree Shaking on Demand

People have to do subtraction, focus and focus, and so does the system. Compared with on-demand introduction, Tree Shaking focuses on on-demand culling from the opposite direction.

Tree Shaking is a term used to describe removing dead-code from a JavaScript context. It relies on the “static structure” features of ES2015 module syntax, such as import and export. This term and concept was actually popularized by the ES2015 module packaging tool Rollup.

What is unreferenced code

Speaking of “unreferenced”, to understand the concepts of “purity” and “side effects”, let’s look at the following two pieces of code.

Pure code

Code with side-effects

“Pure” in the file dimension refers to a pure ES2015 module, which contains only exported code and does not contain other code that has “side effects”, as we can easily understand from the code sample above. By “side effects”, we mean that other code that affects the current environment will be executed when the module is imported.

Tree Shaking is really about analyzing code and removing unimported modules (files or parts of code) that have no side effects from the final build.

How do I weed out code that has no side effects

Webpack 4 naturally supports Tree Shaking, and we have to do the following to make it work:

  • Using ES2015 module syntax (i.eimportexport);
  • Make sure no compiler converts your ES2015 module syntax to CommonJS (incidentally, this is the default behavior of the now common @babel/preset-env, see the documentation for details);
  • In the projectpackage.jsonFile, addsideEffectsProperty to mark which files have side effects;

  • You can also mark locally affected code in the module as pure if necessary;

  • usemodeproductionConfiguration items to enableMore optimizations, including zip code and Tree Shaking.

Going back to the meaning of the term “Tree Shaking,” literally means Shaking a Tree.

You can think of an application as a tree. Green indicates the actual source code and libraries used, which are the living leaves on the tree. Gray indicates unreferenced code and is the withered leaves on a tree in autumn. To get rid of dead leaves, you must shake the tree to make it fall.

Conditional compilation introduced on demand

For those of you who are familiar with uni-App, here is an example of conditional compilation using UNI-App:

demo.html

demo.js

The code example above means that the above HTML code will only be compiled into the final code of the miniprogram on wechat or Baidu when the platform is wechat or Baidu, and the above JavaScript code will only be compiled into the final code when the platform is APP.

This is the concept of conditional compilation, which makes logical distinctions directly at compile time, preventing extraneous code from contaminating each output. With conditional compilation, we can have a piece of code that behaves differently depending on the environment or output target, without having to worry about runtime code waste and related performance issues.

Conditional compilation can be easily implemented through Webpack tripartite plug-ins. This article introduces two tripartite plug-ins — traditional Ugliy-js-plugin and JS-conditional-compile-loader, and the following is a brief description of how to use them.

uglify-js-plugin

We configure webpack.config.js:

Then in the business code we’ll just write:

If is compiled into the result only when ENV_TEST is true.

Conditional compilation using Uglip-js-plugin is equivalent to curve-saving. It does not have the function of conditional compilation itself, but it does have a function to eliminate dead code, which means something like:

It’s easy to see that the code will never be executed, which is called dead code.

We can make a piece of code dead by using the define-plugin by writing the condition in the if as a global variable that we define with define-plugin. This variable is always false under certain circumstances, making it dead code. Therefore, conditional compilation using Ugliy-js-plugin and define-plugin is curve-saving.

js-conditional-compile-loader

Js-conditional-compile-loader is a professional Webpack loader for conditional compilation. Compared with ugliy-Js-plugin, jS-conditional-compile-loader is more flexible. In theory, it supports conditional compilation of any part of any file. It treats the file as if it were a string, preserving or excluding strings wrapped in a particular format under certain circumstances.

Let’s say we use it in a Vue component:

The way it decides whether or not to strip the contents of the comment package is also done through its Loader configuration, using its internal environment variables, and let’s look at how it is configured into Webpack.

Note here that jS-conditional-compile-loader needs to be placed at the end of the Loader array in each file processing rule as the first step in processing the source file. The reason is easy to imagine, because it prevents other loaders from changing the file structure and causing the file contents to change and not take effect.

summary

  • Asynchronous loadingimport()
    • ES6
    • WebpackJsonp
  • According to the need to introducebabel-plugin-import
    • customName
    • ImportDeclaration
  • Culling Tree Shaking on demand
    • Pure
    • Side-effect
  • Conditional compilation
    • uglify-js-plugin
    • js-conditional-compile-loader

In total, we’ve looked at four broad categories of “on-demand” approaches that we believe can solve many of the build problems in our work. In my daily work, I adhere to the principle that we should not repeat the wheel if we can not repeat the wheel. If there is an excellent tripartite library, we can directly use it. Of course, if we have our own personalized needs, we can also refer to their excellent implementation methods to create our own improvement tools.

Reference:

  1. What is your import compiled by Webpack? : juejin. Cn/post / 685956…
  2. The NPM Babel – plugin – import “: www.npmjs.com/package/bab…
  3. The Tree Shaking: webpack.docschina.org/guides/tree…
  4. The conditional compilation: blog.csdn.net/qiuzijian06…
  5. Js-conditional-compile-loader: github.com/hzsrc/js-co…

More exciting, please pay attention to our public number “100 bottle technology”, there are not regular benefits!