I. Js modular development

Javascript needs to be packaged and merged because of modular development. During the development stage, we need to write js files separately in many fragmentary files, which is convenient for debugging and modification, but if we go online like this, the number of HTTP requests on the home page will directly explode. On the same project, someone will get the required documents in 2-3 requests, while yours may need 20-30.

But merge scripts are not just a “copy all the fragments into one JS file” solution. Not only do they resolve namespace conflicts, they also need to be compatible with different modularity schemes, not to mention manually determining the loading order of modules based on the complex dependencies between modules. Therefore, it is necessary to combine and optimize THE JS script fragments in the development stage with automatic tools.

2. General packaging requirements of Js files

  • Code compilation (TSorES6Compilation of code)
  • The script to merge
  • Common module identification
  • The code segment
  • Code compression confusion

3. Use Webpack to process JS files

3.1 Use Babel to convert ES6+ syntax

Babel is a syntax conversion tool for ES6. If you are not familiar with Babel, you should first read the article “Big Front End Automation Factory (3) — Babel”. The method of using Babel with WebPack is also described in this article.

webpack.config.js:

.module: {
    rules: [{test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
             loader: 'babel-loader'}}]},...Copy the code

.babelrc:

{
    "presets":[
        ["env", {"targets": {"browsers":"last 2 versions"}}]],"plugins": [
         "babel-plugin-transform-runtime"]}Copy the code

3.2 Script Merging

Merging scripts with WebPack is very convenient, after all, module management and file merging are the two main functions webPack was originally designed for, until it comes to the topic of subcontracting and lazy loading. Webpack is easy to use because of the compatibility handling of various module specifications, and it is more important for front-end developers to understand how this compatibility is implemented than to learn how to configure WebPack. By default, WebPack supports the CommonJs specification, but in order to expand its usage, webPack has added compatibility processing for ES Harmony and other specification defined modules in subsequent iterations. The specific processing methods will be analyzed in detail in the next chapter ** “WebPackage 4.0 Divided (5) — Module”.

3.3 Common Module Identification

You can see the following section in the output file of Webpack:

/ * * * * * * / 	function __webpack_require__(moduleId) {
/ * * * * * * /
/ * * * * * * / 		// Check if module is in cache
/ * * * * * * / 		if(installedModules[moduleId]) {
/ * * * * * * / 			return installedModules[moduleId].exports;
/ * * * * * * / 		}
/ * * * * * * / 		// Create a new module (and put it into the cache)
/ * * * * * * / 		var module = installedModules[moduleId] = {
/ * * * * * * / 			i: moduleId,
/ * * * * * * / 			l: false./ * * * * * * / 			exports: {}
/ * * * * * * / 		};
/ * * * * * * /
/ * * * * * * / 		// Execute the module function
/ * * * * * * / 		modules[moduleId].call(module.exports, module.module.exports, __webpack_require__);
/ * * * * * * /
/ * * * * * * / 		// Flag the module as loaded
/ * * * * * * / 		module.l = true;
/ * * * * * * /
/ * * * * * * / 		// Return the exports of the module
/ * * * * * * / 		return module.exports;
/ * * * * * * / 	}

Copy the code

The __webpack_require__() method above is the module loader for Webpack, and it’s easy to see that there is a unified installedModules object that manages loaded modules to avoid module reloading. Common modules are also typically extracted from bundle.js files, which covers “Code splitting” in the next section.

3.4 Code Segmentation

1. Why code splitting?

Code for the most basic task is to isolate the third party relies on library, because the content of the third party libraries may be a long time will not change, so that tag changes the hash contentHash also unchanged for a long time, it also means that we can use local cache to avoid unnecessary repetition of packaging, and use the browser cache to avoid redundant client load. In addition, when a new version of the project is released, if the third party’s contentHash is not changed, the client’s original cache file can be used (common practice is to set a large max-age for static resource requests) to improve access speed. In other scenarios, code splitting can also provide control over the loading timing of scripts throughout the load cycle.

2. Usage scenarios of code segmentation

For example, if you’re building a data visualization site and you use Baidu’s Echarts as a third-party library to render diagrams, if you package your code with Echarts to create a main.bundle.js file, As a result, when you open your site on a slow Internet connection, you may be faced with a long blank screen, and you will soon be thinking of separating Echarts from the main file, and having the smaller main file render some animations or prompts on the interface before loading Echarts. Separate Echarts can also be obtained from faster CDN nodes. If you load a large library, you can also choose to use lazy loading, delaying the script download until the user actually uses the corresponding functionality. This is a kind of artificial code splitting.

In the entire lifecycle of the example above, we split the script that could have been loaded once into two times. This undoubtedly increases the performance cost of the server side. After all, establishing a TCP connection is an expensive operation, but this can be in return for controlling the rendering rhythm and improving the user experience. Asynchronous modules and lazy-loaded modules actually belong to the category of code segmentation from a macro perspective. The most extreme case of Code Splitting is actually what the source code looks like before it is split and packaged, that is, the source code is put online directly.

3. The nature of code segmentation

The essence of code splitting is to find a more realistic middle ground between the extremes of “source code live” and “packaged as a single script main.bundle.js”, with an acceptable increase in server performance in exchange for a better user experience.

4. Configure code splitting

The configuration and use of code-Splitting technology is described in more detail in the next section.

5. More detailed code segmentation

Interested readers can do their own research with the Article Reduce JavaScript Payloads with Code Splitting from the Google Developer community.

3.5 Code confusion compression

Webpack4 has built-in UglifyJs plug-in, which will automatically start when the packaging mode parameter mode is set to production. Of course, this is not the only choice, Babel plug-in can also provide code compression processing, the specific effect and principle of the author has not been deeply studied, interested readers can study by themselves.

4. SplitChunks in detail

4.1 Parameter Description

Webpack4 abandoned CommonsChunkPlugin plug-in, using optimization. SplitChunks and optimization runtimeChunk instead, reason can refer to the evolution of webpack4: legato. As for the runtimeChunk parameter, some articles say that the runtime part of the chunk is extracted to form a separate file. Since this part does not change often, the cache can be used. The Google Developer Community blog post describes it this way:

The runtimeChunk option is also specified to move webpack’s runtime into the vendors chunk to avoid duplication of it in our app code.

The default code auto-splitting requirements in splitChunks are as follows:

  • Modules in node_modules or other modules that are repeatedly referenced

    That is, if the referenced module comes from node_modules, then as long as it is referenced, it can be split automatically if other conditions are met. Otherwise, the module needs to be referenced repeatedly to proceed to other criteria. (This corresponds to the scenario with minChunks 1 or 2 in the configuration options below)

  • Lower limit of minimum volume for separated front modules (default 30K, modifiable)

    30K is the default value officially given, which can be modified. As mentioned in the previous section, each subcontract corresponds to an increase in the performance cost of the server, so the cost performance of the subcontract must be considered.

  • For asynchronous modules, no more than 5 (modifiable) public module files can be generated

    When lazy module downloads are triggered, the number of concurrent requests should not exceed 5. For developers who have a little knowledge of server-side technology, the keywords ** [high concurrency] and [stress test] ** should be familiar.

  • For entry modules, no more than 3 public module files can be extracted (modifiable)

    This means that the maximum number of parallel requests per entry file cannot exceed 3 by default, for the same reason as above.

4.2 Parameter Configuration

SplitChunks are used as follows in webpack4.0 and later:

module.exports = {
  / /...
  optimization: {
    splitChunks: {
      chunks: 'async'.// This works only on asynchronous modules by default. 'all' works for all modules and 'initial' works for synchronous modules
      minSize: 30000.// Merge the volume of the front module files
      minChunks: 1.// Minimum number of citations
      maxAsyncRequests: 5.maxInitialRequests: 3.automaticNameDelimiter: '~'.// Automatically name the connecter
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          minChunks:1./ / on the blackboard
          priority: -10// The priority is higher
        },
        default: {
          test: /[\\/]src[\\/]js[\\/]/
          minChunks: 2.// Generally non-third-party public modules
          priority: -20.reuseExistingChunk: true}},runtimeChunk: {name:'manifest'}}}Copy the code

4.3 Code segmentation example

Note: The demo and configuration file used in the example have been attached.

  • Single page application

    A single-page application has only one entry file, and the main purpose of splitChunks is to separate the referenced third-party libraries. As you can see from the subcontracting results below, third-party references in node_modules are detached and placed in vendor-main.[hash].js.

  • Multi-page application

    The case of multi-page application is a little more complicated. The example in “webpack4: evolution in legato” is used for code segmentation. The source code dependency is as follows:

    entryA.js: vue vuex component10k
    entryB.js: vue axios component10k
    entryC.js: vue vuex axios component10k
    
    Copy the code

    The package obtained after code segmentation is shown in the figure below:

SplitChunks provide a more precise segmentation strategy, but it seems impossible to dynamically resolve the injection of post-segmentation code directly through the HTML-webpack-plugin configuration parameter because the subcontracting names are uncertain. This scenario does not exist with the chunks:’async’ default configuration because the reference code for the asynchronous module does not need to be injected into an HTML file as a

This can be a problem when the chunks configuration item is set to all or INITIAL. For example, in the example above, excludeChunks can be configured to remove the chunks of Page and About by configuring them in the HTML-webpack-plugin. However, chunk Vendor-about-Page cannot be excluded in advance because it is not known whether such a chunk will be generated before packaging. The author has not found a ready-made solution for this scenario. Readers who need this scenario may use the event extension of htML-webpack-plugin to handle this scenario, or they can use a compromise solution, which is to record the name of the newly generated chunk after the first packaging. Fill in the chunks configuration item of the HTML-webpack-plugin as required.

4.4 Result Analysis

Using the Bundle Buddy analysis tool or the Webpack-bundle-Analyser plug-in, you can see the impact of the extraction of common code before and after subcontracting (image from the references blog post) :

5. Reference and appendix notes

[1] Attached file description:

  • webpack.spa.config.js— Single page application code split configuration example
  • main.jsSingle page application entry file
  • webpack.multi.config.js– Multi-page application code split configuration example
  • entryA.js.entryB.js.entryC.js— 3 entry points for multi-page applications

[2] Reference: Reduce JavaScript Payloads with Code Splitting

Link: Webpackage 4.0 split (4) — Javascript & splitChunk source: Blogpark Copyright by the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.