Lazy code loading

This is the 10th day of my participation in the August More Text Challenge. For details, see:August is more challenging

One of the most commonly used scenarios for dynamic import is lazy loading (such as route lazy loading)

For example, lazy loading can be used when we want to render something on the page after clicking a button

element.js

const divElem = document.createElement('div')
divElem.innerHTML = 'hello world'
export default divElem
Copy the code

index.js

const btn = document.createElement('button')
btn.innerHTML = 'click me'
document.body.appendChild(btn)

btn.addEventListener('click'.() = > {
  // Simple implementation of lazy loading
  import('./element').then(({default: element}) = > document.body.appendChild(element))
})
Copy the code

Prefetch and Preload

The previous lazy loading case has a point that can be optimized:

By default, after we click the button, the browser downloads the script and then loads and parses the corresponding script

Now, if the script is large, it might not give the user a very good idea,

So we can download these scripts in advance at the right time

At execution time, you simply load and parse the corresponding script

Starting with Webpack V4.6.0 +, WebPack has added support for prefetch and preload

configuration instructions
prefetch(Pre-acquired) Wait for the browser needs to load the resources loaded, the browser idle, to the corresponding resources to pre-download down

Typically used to display resources that may be needed under some future navigation
preload(Preloading) Along with the parent chunk(the file in which the current import is located)paralleldownload

Typically used to display resources that may be required under the current navigation
btn.addEventListener('click'.() = > {
  // The preload and Prefetch functions are enabled using magic comments. Multiple magic comments can be configured at the same time
  Set preload and prefetch to true
  import(
    /* webpackPrefetch: true */
    /* webpackChunkName: 'element' */
    './element'
  ).then(({default: element}) = > document.body.appendChild(element))
})
Copy the code

runtimeChunk

To configure whether runtime related code is extracted into a separate chunk:

Runtime code refers to the code that parses, loads, and relates to module information in the runtime environment

That is, code that we didn’t write, but that was necessary at runtime, and that was added to us by WebPack

At this point, we can pull out the runtime code

So that when we change the business code, the Runtime code does not need to be reloaded

value instructions
The default value Runtime does not perform separate extraction operations
true/multiple Package a Runtime file for each entry and generate runtime~${entryPoint. Name} files for each entry
single Package a Runtime file
object The name attribute determines the name of runtimeChunk
optimization: {
  runtimeChunk: {
    // The resulting file is spliced with runtimechunk.name and output.filename, such as foo.bundle.js
    name: 'runtime'}}Copy the code
optimization: {
  runtimeChunk: {
    // entryPoint is an object
    // This object has an attribute name whose value is the name of the entry name in the entry
    name: (entryPoint) = > {
      return `runtime~${entryPoint.name}`}}}Copy the code

In principle, it is not recommended to split runtime into multiple packages for parsing, because the JS files will eventually be imported in a certain order in index.html.

This means that objects exposed in the Runtime are set to global objects. If you split them into multiple Runtime objects, you will have global variable contamination.

An object of the same name in the later Runtime overwrites an object of the same name in the previous Runtime. For example, every Runtime may have a __webPack__require__ object

CDN

A CDN is called a Content Delivery Network or Content Distribution Network.

  • It refers to using the server closest to each user through an interconnected network system
  • Faster and more reliable delivery of music, photos, videos, apps, and other files to users
  • To provide high performance, scalability and low cost network content delivery to users

When a user requests a resource, it will go to the server nearest to the user (edge node) to request the resource

If the resource exists, download it directly. If the resource does not exist, go to the parent node of the edge node to find it.

And so on, find direct return, no find continue to go to the node’s parent node to find, until find the source (source node)

When resources are delivered, each node server will cache the corresponding resources on this node

In this way, when the next user needs to access the same resource, the user can return the required resource through the node closest to the user.

In development, we use CDN in two main ways

  1. All static resources are packaged and put into the CDN server. All user resources are loaded through the CDN server
  2. Its own business code is stored on its own server, and some third-party resources are put on the CDN server

Place them all on the CDN server

If we want to put all our static resources on a CDN server, we need to buy our own CDN server

At present, Alibaba, Tencent, Amazon, Google and so on can buy CDN servers

output: {
  path: path.resolve(__dirname, '.. /dist'),
  filename: '[name].bundle.js'.// Set the CDN path to publicPath. All resources will be automatically added to this path when they are packaged
  publicPath: 'https://www.example.com/cdn'
},
Copy the code

Only third parties are placed on the CDN server

Usually some of the better known open source frameworks will package the source code to some of the better known, free CDN servers

The international use is more unPkg, JSDelivr, CDNJS

There is also a more useful CDN is BOOTCDN

webpack.config.js

module.exports = {
  // Externals is the top-level configuration option for WebPack
  externals: {
    // key ===> Module name
    // value ===> The object exposed by the module
    'dayjs': 'dayjs'.'lodash': '_'}}Copy the code

index.html

<body>
  <! Because all third-party libraries are not packaged into the source code, you need to set up the CDN links for all third-party libraries in the HTML -->
  <script src="https://unpkg.com/[email protected]/dayjs.min.js"></script>
  <script src="https://unpkg.com/[email protected]/lodash.js"></script>
</body>
Copy the code

At the time of development, our server and browser are both local, so there is no need to set third-party packages to the CDN, because this can be done multiple times

At this point we can use EJS to determine the development environment for our HTML template

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta Name ="viewport" content="width=device-width, initial-scale=1.0"> <title>Webpack</title> <body> <! Process.env.node_env === 'production'){%> <script (process.env.node_env === 'production') SRC = "https://unpkg.com/[email protected]/dayjs.min.js" > < / script > < script SRC = "https://unpkg.com/[email protected]/lodash.js" > < / script > < %} % > < / body > < / HTML >Copy the code

Pull out the CSS code

The MiniCssExtractPlugin helps us extract the CSS into a separate CSS file

This plug-in is intended for use in production environments, but development environments are optional

#The installation
npm install mini-css-extract-plugin -D
Copy the code

configuration

config.common.js

const miniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = env= >  {
  const commonConfig = env= > ({
        module: {
        rules: [{test: /\.css$/,
            use: [
              // The development environment uses styleloader, and the production environment uses miniCssExtractPlugin
              env.production ? miniCssExtractPlugin.loader : 'style-loader'.'css-loader']}]}})return env.production ? merge(commonConfig(env), prodConfig) : merge(commonConfig(env), devConfig)
}
Copy the code

config.prod.js

const miniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  plugins: [
    new miniCssExtractPlugin({
      // There is no placeholder named ext because the style is pulled away
      filename: 'css/[name].[hash:6].css'}})]Copy the code

The value of env

Env is a very special object in Node. All values in env are converted to strings before being stored

This is node’s special treatment of env objects, which does not exist in any other Node objects

In webpack.config.js, if you need to store values in process.env, you need to pay attention and handle them accordingly

const un = undefined
const num = 123

process.env.un = un
process.env.num = num

console.log(process.env.un, typeof process.env.un) // => undefined string
console.log(process.env.num, typeof process.env.num) // => 123 string
Copy the code