webpack: Systematically understand some core concepts of webpack

How does webpack handle applications?

Build a dependency graph from one or more entry points, and then combine each chunk needed in your project into one or more bundles

What is webpack module chunk?

  • ES2015 import statement
  • CommonJS require() statement
  • AMD define and require statements
  • @import statements in css/sass/less files.
  • stylesheet url(…) or <img src=...>image link in HTML file.

Everything that can be referenced by these counts as a module chunk.

Webpack natively supports the following module types:

  • ECMAScript module
  • CommonJS module
  • AMD module
  • Assets
  • WebAssembly module

When you encounter something that is not supported, you can write a loader to support it. In other words, through loader, webpack can support modules written in multiple languages ​​and preprocessor syntax.
for example:

Entry

The default entry is ./src/index.js, which can be configured in entry

output

The default value is./dist/main.js

loader

Webpack can only understand JavaScript and JSON files by default. You can use loader when you need to process other files.

In the webpack configuration, loader has two attributes:

  • The test attribute identifies which files will be converted.
  • The use attribute defines which loader should be used when performing conversion.
// webpack 编译器,当你碰到「在 require()/import 语句中被解析为 '.txt' 的路径」时,在你对它打包之前,先 use(使用) raw-loader 转换一下。
module.exports = {
    
    
  module: {
    
    
    rules: [{
    
     test: /\.txt$/, use: 'raw-loader' }],
  },
};

Loaders support chain calls. The loaders in the array are executed in reverse from back to front, and the results (that is, the converted resources) are passed to the next loader.

Develop loader
module.exports = function (content) {
    
    
  console.log(content);
  return content + '123';
};

plug-in

Introduction

Loaders are used to convert certain types of modules, while plugins can be used to perform a wider range of tasks. Including: packaging optimization, resource management, and injection of environment variables.

const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件

module.exports = {
    
    
  module: {
    
    
    rules: [{
    
     test: /\.txt$/, use: 'raw-loader' }],
  },
  plugins: [new HtmlWebpackPlugin({
    
     template: './src/index.html' })],
};

In the example, html-webpack-plugin generates an HTML file for the application and automatically injects all generated bundles into this file.

process

The overall process of webpack can be divided into env > init > compiler > make > seal > emit > done

The env and init phases are responsible for initializing the environment and activating the webpack internal plug-in.
The compiler phase is the beginning of compilation.
The make phase webpack will perform dependency analysis and collection.
The seal phase webpack will generate chunk files.
The emit phase webpack will write chunks to the hard disk
. The done phase, as the name suggests, will webpack. work done

Plug-in development:

https://webpack.docschina.org/api/plugins

The Compiler module is the main engine of webpack. It creates a compilation instance with all options passed through the CLI or Node API. It extends (extends) from the Tapable class and is used to register and call plug-ins. Most user-facing plugins will first be registered with the Compiler. https://webpack.docschina.org/api/compiler-hooks/#hooks

Tapable class

This small library is a core tool of webpack, provides a similar plug-in interface, and is also an npm package. Kind of like a publish-subscribe tool.

Many objects in webpack extend from the Tapable class. It exposes methods such as tap, tapAsync and tapPromise. Plug-ins can use these methods to inject custom build steps into webpack.

https://github.com/webpack/tapable

monitoring

When listening, the compiler will trigger additional events such as watchRun, watchClose and invalid. It is usually used in the development environment, and is often called at the bottom of tools such as webpack-dev-server, so developers do not need to manually recompile every time.

compiler hook

The following life cycle hook functions are exposed by the compiler

compiler.hooks.someHook.tap('MyPlugin', (params) => {
    
    
  /* ... */
});

Tap is not just tap, you can also access tapAsync and tapPromise on certain hooks, see Tapable for details.

someHook can be the following hook function:
1. environment: called when the compiler prepares the environment, the timing is after the plug-in is initialized in the configuration file.
2. afterEnvironment: After the compiler environment setting is completed, it is called directly after the environment hook.
3. entryOption: Called after the entry in the webpack option has been processed.

compiler.hooks.entryOption.tap('MyPlugin', (context, entry) => {
    
    
  /* ... */
});

4. afterPlugins: Called after initializing the internal plug-in collection and completing the settings.
5. initialize: Called when the compiler object is initialized.
6. beforeRun: Called before starting a build. Called immediately after the compiler.run method starts executing.
7. run: called before starting to read records.
8. watchRun: In listening mode, executed after a new compilation is triggered, but before compilation actually starts.
9. compile: called immediately after beforeCompile, but before a new compilation is created. This hook will not be copied to subcompilers.
10. Compilation: Executed after compilation is created.
11. emit: Executed before outputting the asset to the output directory. This hook will not be copied to subcompilers.
12. done: executed when compilation is completed. This hook will not be copied to subcompilers.
13. failed: called when compilation fails.
14. shutdown: called when the compiler is shut down.

Complete hooks: https://webpack.docschina.org/api/compiler-hooks/#hooks

compilation hook

Compilation instance created by compiler. During the compilation phase, modules are loaded, sealed, optimized, chunked, hashed, and restored.

Hook function:
1. buildModule: Triggered before module building starts and can be used to modify the module.

compilation.hooks.buildModule.tap(
  'SourceMapDevToolModuleOptionsPlugin',
  (module) => {
    
    
    module.useSourceMap = true;
  }
);

2. successfulModule: Executed when the module is successfully built.
3. Optimize: Triggered at the beginning of the optimization phase.
4. optimizeChunks: called at the beginning of the chunk optimization phase. Plug-ins can tap this hook to perform optimizations on chunks.

Complete hooks: https://webpack.docschina.org/api/compilation-hooks/

compiler和compilation

The difference between Compiler and Compilation is that Compiler represents the entire Webpack life cycle from startup to shutdown, while Compilation just represents a new compilation.

Webpack compilation creates two core objects:

  • compiler: Contains all configuration information of the webpack environment, including options, loaders, plugins, and hooks related to the entire webpack life cycle.

  • compilation: As a parameter of the plugin's built-in event callback function, it includes the current module resources, compiled resources, changed files, and status information of tracked files. When a file change is detected, a new file will be generated. Compilation object.

  • The Compiler object contains all the configuration information of the Webpack environment, including options, loaders, and plugins. This object is instantiated when Webpack starts. It is globally unique and can be simply understood as a Webpack instance;

  • The Compilation object contains the current module resources, compiled resources, changed files, etc. When Webpack is running in development mode, a new Compilation will be created every time a file change is detected. The Compilation object also provides many event callbacks for plug-ins to extend. Compiler objects can also be read through Compilation.

Create a custom plugin
  • The plug-in must be a function or an object containing an apply method in order to access the Compiler object.

  • The compiler and compilation objects passed to each plug-in are the same application, so modification is not recommended.

  • Asynchronous events need to be completed after the plug-in processes the task and calls the callback function to notify webpack to enter the next process, otherwise it will get stuck.

class MyPlugin {
    
    
    // Webpack 会调用 MyPlugin 实例的 apply 方法给插件实例传入 compiler 对象
  apply (compiler) {
    
    
    // 找到合适的事件钩子,实现自己的插件功能
    compiler.hooks.emit.tap('MyPlugin', compilation => {
    
    
        // compilation: 当前打包构建流程的上下文
        console.log(compilation);
        
        // do something...
    })
  }
}

When the emit event occurs, it means that the conversion and assembly of the source file has been completed. The resources, code blocks, modules, and dependencies that will eventually be output can be read, and the contents of the output resources can be modified.

The difference between loaders and plugins

  • The loader runs before the project is packaged;
  • Plugins run during the compilation period of the entire project;

Loader is a file loader, which operates files. Converting file A to file B through loader is a simple file conversion process. For example, convert A.less to B.css

Plugins work based on the event mechanism, monitor certain nodes in the webpack packaging process, and perform a wide range of tasks.

mode

By selecting one of development, production or none

Plug-in overwrite file

Here is a simple example of a plugin that converts all JavaScript code into CoffeeScript code when Webpack processes the file:

const Tapable = require('tapable');  
const coffee = require('coffee-script');  
  
class CoffeeScriptPlugin {
    
      
  constructor(options) {
    
      
    this.options = options || {
    
    };  
  }  
  
  apply(compiler) {
    
      
    compiler.hooks.emit.tapAsync('CoffeeScriptPlugin', (compilation, callback) => {
    
      
      Object.keys(compilation.assets).forEach((data) => {
    
      
        if (/\.js$/.test(data)) {
    
      
          const content = compilation.assets[data].source();  
          const coffeeScript = coffee.compile(content, {
    
    bare: true});  
          compilation.assets[data] = {
    
      
            source: () => coffeeScript,  
            size: () => coffeeScript.length,  
          };  
        }  
      });  
      callback();  
    });  
  }  
}  
  
module.exports = CoffeeScriptPlugin;

In this example, we first create a new class CoffeeScriptPlugin, which inherits from Tapable. Then, we registered a hook function in the apply method that is executed during the emit phase. In this hook function, we iterate through all resources. If the name of the resource ends with .js, we use CoffeeScript to compile the content of this resource, and then replace the original content with the compiled content. Finally, we call the callback function to notify Webpack to continue executing the next stage of the task.

A project uses multiple webpack plug-ins at the same time. What is the execution order of the plug-ins?

Webpack's plug-in system is implemented based on the Tapable library, which provides a pluggable interface for plug-ins. Therefore, the specific plug-in execution order depends on the plug-in registration order and triggering timing in the Webpack event stream.

Plug-ins are usually declared in the form of an array in the Webpack configuration file (i.e., webpack.config.js file). The plug-ins in the array are executed in order. For example:

module.exports = {
    
      
  //...  
  plugins: [  
    new HtmlWebpackPlugin(),  
    new CleanWebpackPlugin(),  
    //...  
  ],  
};

In the above example, the HtmlWebpackPlugin plugin is executed first and then the CleanWebpackPlugin plugin is executed.

However, this is only part of the truth. There are many life cycle hooks in the compilation process of Webpack, such as 'compilation', 'optimize', 'emit', etc. Plugins may be bound to one or more hooks. This means that the execution of plugins may be distributed throughout Webpack's compilation cycle, depending on which hooks they choose to "bind" to.

If two plugins are bound to the same hook, the plugin declared first in webpack.config.js will be executed first. However, if one plugin is bound to an early hook (e.g. 'compilation') and another plugin is bound to a later hook (e.g. 'emit'), then even plugins declared later in webpack.config.js will will be executed first because the 'compilation' phase precedes the 'emit' phase.

In summary, the execution order of Webpack plug-ins mainly depends on two factors: the order in which they are declared in the webpack.config.js file, and the order in which their bound hooks are triggered in the Webpack compilation cycle.

Common configuration

/* 未使用脚手架打包 
  //开发环境
  webpack '输入文件' -o '输出文件' --mode=development
  //生产环境
  webpack '输入文件' -o '输出文件' --mode=production      
*/
 
const {
    
     resolve } = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsWebpackPlugin  = require('optimize-css-assets-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
 
/* 
  ## 懒加载
  ## import动态导入能将导入的文件单独打包,跟多入口文件效果类似
  webpackChunkName: 'test'
  import('./test')
    .then(res => {
      // 成功引入后执行的步骤
    })
    .catch(err => {
      console.log('文件加载失败~')
    })
*/
 
  // ## 预加载
  // import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then()
  // ## 懒加载
  // import(/* webpackChunkName: 'test' */'./test').then()
 
module.exports = {
    
    
  // 单入口打包(打包成一个chunk)
  entry: './src/index.js',
  /*
  另外的写法:
    // 单文件入口(打包成一个chunk),add.js加到index.js上,仅用于HMR HTML文件热更新
    entry: ['./src.index.js', './src/add.js'],
    // 多入口打包(打包成多个chunk,也可以进行代码分割)
    entry: {
      index: './src.index.js',
      add: './src/add.js'
    },
    // 多入口加文件合并(打包成多个chunk)
    entry: {
      index: ['./src.index.js', './src/count.js'],
      add: './src/add.js'
    },
  */
 
  output: {
    
    
    // 文件名称(指定名称+目录)
    /* 
      ## hash 每次打包都会生成一个唯一的hash值
      ## chunkhash: 根据输出的不同的chunk生成不同的chunk值,
      ## contenthash: 根据 不同的文件生成不同的hash值(推荐)
    */
    filename: 'js/[name].[contenthash: 8].js',
    // 输出所有文件的公共目录
    path: resolve(__dirname, 'build'),
    // 所有资源的引入公共路径前缀,相当于跨域中的前缀
    publicPath: '/',
    // 非入口chunk的名称,不设置都会走filename的方式命名,例如import('../xxx.js')导入的文件
    chunkFilename: '[name]_chunk.js',
    // 打包后要引用其中的文件,通过library暴露一个对象,达到调用的目的,一般结合dll使用
    library: '[name]',
    // 暴露的对象名添加到哪个地方去,window/global/commomjs
    libraryTarget: 'window'
  },
 
  module: {
    
    
    rules: [
      /* 检查js文件格式 */
      {
    
    
        // 在package.json中配置eslintConfig
        test: /\.js$/,
        include: resolve(__dirname, 'src'),
        exclude: /node_modules/,
        // 多个loader
        loader: 'eslint-loader',
        // 优先执行
        enforce: 'pre',
        // 具体的配置选项
        options: {
    
    
          // 自动修复
          fix: true,
          // 指定错误报告的格式规范
          formatter: require('eslint-friendly-formatter')
        }
      },
      /* 处理HTML文件中引入的图片 */
      {
    
    
        test: /\.html$/,
        include: resolve(__dirname, 'src'),
        exclude: /node_modules/,
        loader: 'html-withimg-loader',
 
      },
      /* 打包图片和其他资源 */
      {
    
    
        exclude: /\.(css|html|js|json)$/,
        loader: 'file-loader',
        options: {
    
    
          name: '[hash: 10].[ext]',
          outputPath: 'static/media/'
        }
      },
      {
    
    
        // 以下配置对每个检查的文件只会生效一个
        oneOf: [
          /* 打包图片资源 */
          {
    
    
            test: /\.(jpg|png|gif|bmp|jpeg)$/,
            include: resolve(__dirname, 'src'),
            exclude: /node_modules/,
            loader: 'url-loader',
            options: {
    
    
              // 图片大小限制,小于8kb使用base64处理
              limit: 8 * 1024,
              // 关闭url-loader es6模块化,使用commonJs解析
              esModule: false,
              // 图片重命名
              name: '[hash: 10].[ext]',
              // 指定打包输出路径
              outputPath: 'static/imgs/'
            }
          },
          /* 打包css资源 */
          {
    
    
            test: /\.css$/,
            // 指定检查的文件路径
            include: resolve(__dirname, 'src'),
            // 排除不需要检查的文件路径
            exclude: /node_modules/,
            // 多个loader
            use: [
              MiniCssExtractPlugin.loader,
              'css-loader',
              // css兼容性处理,配合package.json中的browswerlist使用
              {
    
    
                loader: 'postcss-loader',
                options: {
    
    
                  execute: true,
                  postcssOptions: {
    
    
                    plugins: [
                      [
                        'postcss-preset-env'
                      ]
                    ]
                  }
                }
              }
            ]
          },
          {
    
    
            test: /\.less$/,
            // 指定检查的文件路径
            include: resolve(__dirname, 'src'),
            // 排除不需要检查的文件路径
            exclude: /node_modules/,
            // 多个loader
            use: [
              MiniCssExtractPlugin.loader,
              'css-loader',
              // css兼容性处理
              {
    
    
                loader: 'postcss-loader',
                options: {
    
    
                  execute: true,
                  postcssOptions: {
    
    
                    plugins: [
                      [
                        'postcss-preset-env'
                      ]
                    ]
                  }
                }
              },
              'less-loader'
            ]
          },
          {
    
    
            test: /\.scss$/,
            // 指定检查的文件路径
            include: resolve(__dirname, 'src'),
            // 排除不需要检查的文件路径
            exclude: /node_modules/,
            // 多个loader
            use: [
              MiniCssExtractPlugin.loader,
              'css-loader',
              // css兼容性处理
              {
    
    
                loader: 'postcss-loader',
                options: {
    
    
                  execute: true,
                  postcssOptions: {
    
    
                    plugins: [
                      [
                        'postcss-preset-env'
                      ]
                    ]
                  }
                }
              },
              'sass-loader'
            ]
          },
          /* js兼容性处理 */
          {
    
    
            test: /\.js$/,
            include: resolve(__dirname, 'src'),
            exclude: /node_modules/,
            use: [
              /* 
                开启多进程打包
                多进程需启动(约600ms),只有打包时间长的时候适用
                {
                  loader: 'thread-loader',
                  options: {
                    workers: 2  //开启进程2个
                  }
                }
               */
              'thread-loader',
              {
    
    
                loader: 'babel-loader',
                options: {
    
    
                  presets: [
                    [
                      '@babel/preset-env',
                      {
    
    
                        // 按需加载
                        useBuiltIns: "usage", // or "entry"
                        // 指定core-js版本
                        corejs: {
    
    
                          version: 3
                        },
                        // 指定兼容到哪个版本的浏览器
                        targets: {
    
    
                          chrome: '90',
                          firefox: '60',
                          ie: '9'
                        }
                      }
                    ]
                  ],
                  // 开启babel缓存
                  cacheDirectory: true
                }
              }
            ]
          }
        ]
      }
    ]
  },
 
  plugins: [
    /* 创建并复制index.html文件 */
    new HtmlWebpackPlugin({
    
    
      // 引入项目的根HTML文件
      template: './src/index.html',
      minify: {
    
    
        // 移除空格
        collapseWhitespace: true,
        // 移除注释
        removeComments: true
      }
    }),
    /* 抽离css成单独文件 */
    new MiniCssExtractPlugin({
    
    
      filename: 'css/[contenthash: 10].css'
    }),
    /* 压缩css文件 */
    new OptimizeCssAssetsWebpackPlugin(),
    /* 告诉webpack,根据mainfest映射,哪些库不用再打包 */
    new webpack.DllReferencePlugin({
    
    
      manifest: resolve(__dirname, 'dll/mainfest.json')
    }),
    // 配合dll, 引入dll中已经压缩的库
    new AddAssetHtmlWebpackPlugin({
    
    
      filepath: resolve(__dirname, 'dll/jquery.js')
    })
  ],
 
  // 解析模块的规则
  resolve: {
    
    
    // 配置解析模块的路径别名,例如 src别名是@
    alias: {
    
    
      $css: resolve(__dirname, 'src/css'),
      $assets: resolve(__dirname, 'src/assets')
    },
    // 配置省略文件路径的后缀名,文件引入可以省略后缀名
    extensions: ['.js', '.json'],
    // 告诉 webpack 解析模块是去找哪个目录,不配置默认会逐层向上找
    modules: [resolve(__dirname, './node_modules'), 'node_modules']
  },
 
  devServer: {
    
    
    // 运行代码的目录
    contentBase: resolve(__dirname, 'build'),
    // 监视contentBase目录下的所有文件,一旦文件变化就会reload
    watchContentBase: true,
    // 监视配置
    watchOptions: {
    
    
      // 忽略文件
      ignored: /node_modules/
    },
    // 启动gzip压缩
    compress: true,
    // 端口号
    port: 8888,
    // 指定域名
    host: 'localhost',
    // 自动打开浏览器
    open: true,
    // 开启HMR功能
    hot: true,
    // 不显示启动服务日志信息
    clientLogLevel: 'none',
    // 除基本启动信息,其他内容不显示
    quiet: true,
    // 如果出错不要全屏提示
    overlay: false,
    // 服务器代理 --> 解决开发环境下跨域问题,与vue相似
    proxy: {
    
    
      // 一旦遇到/api,就转到target这个路径下,并且路径重写,去掉/api
      '/api': {
    
    
        target: 'http://localhost:8080',
        // 路径重写
        pathRewrite: {
    
    
          '^/api': ''
        }
      }
    }
  },
 
  // 将node_modules中的代码单独打包成一个chunk输出,单/多入口都适用
  optimization: {
    
    
    /* 代码分割 */
    splitChunks: {
    
    
      chunks: 'all',
      // 分割的chunk最小为30kb
      minSize: 30 * 1024,
      // 无最大限制
      maxSize: 0,
      // 要提取的chunks最少被引用1次
      minChunks: 1,
      // 按需加载时并行加载的文件的最大数量
      maxAsyncRequests: 5,
      // 入口js文件最大并行请求数量
      maxInitialRequests: 3,
      // 名称连接符
      automaticNameDelimiter: '~',
      // 可以使用命名规则
      name: true,
      // 分割chunk的组
      cacheGroups: {
    
    
        // node_modules文件会被打包到vendors组的chunk中 --> vendors~xxx.js
        // 满足上边的公共规则
        vendors: {
    
    
          test: /[\\/]node_modules[\\/]/,
          // 优先级
          priority: -10
        },
        default: {
    
    
          minChunks: 2,
          priority: -20,
          // 如果当前要打包的模块,和之前已经提取的模块是同一个,就不在重新打包
          reuseExistingChunk: true
        }
      }
    },
    // 将当前模块记录其他模块的hash值单独打包成一个文件,
    // 解决被引用文件修改,hash值改变,引用文件跟着重新打包的问题(缓存失效)
    runtimeChunk: {
    
    
      name: entrypoint => `runtime-${
      
      entrypoint.name}`
    },
    // 配置生产环境的压缩方案: js和css
    minimizer: [
      new TerserWebpackPlugin({
    
    
        // 开启缓存
        cache: true,
        // 开启多进程打包
        parallel: true,
        // 启动source-map
        sourceMap: true
      })
    ]
  },
 
  devtool: source-map,
 
  externals: {
    
    
    // 忽略库名 -- 忽略包名
    jquery: 'jQuery'  // 忽略打包jQuery
  },
  // 指定模式: 开发/生产(production)
  /* 
    ## tree shaking:去除无用代码
    ## 前提: 1. 必须使用ES6模块化    2.开启production环境
    ## package.json中配置"sideEffects": ["*.css","*.less"]   -->不将设置的文件类型tree shaking
  */
  mode: 'development'
}

webpack.dll.js

const {
    
     resolve } = require("path");
const webpack = require('webpack')
/* 
  使用dll技术对某些第三方库进行单独打包
  webpack --config webpack.dll.js
*/
module.exports = {
    
    
  entry: {
    
    
    // 最终打包生成的[name]  -->jquery
    // ['jquery']  --> 要打包的库是jQuery
    jquery: ['jquery']
  },
  output: {
    
    
    filename: '[name].js',
    path: resolve(__dirname, 'dll'),
    library: '[name]_[hash: 8]'
  },
  plugins: [
    // 打包生成一个mainfest.json文件 ,提供与要打包文件的映射关系
    new webpack.DllPlugin({
    
    
      name: '[name]_[hash]', // 映射库的暴露的内容名称
      path: resolve(__dirname, 'dll/mainfest.json') // 输出文件路径
    })
  ]
}

Appendix: The basic data structures of compiler and compilation are the same

Complete object:
const a = {
    
    
  _backCompat: true,
  hooks: {
    
    },
  name: undefined,
  startTime: undefined,
  endTime: undefined,
  compiler: {
    
    },
  resolverFactory: {
    
    },
  inputFileSystem: {
    
    },
  fileSystemInfo: {
    
    },
  valueCacheVersions: Map(16) {
    
    
    'webpack/DefinePlugin DC_APP_DOMAIN_MCP' => '"https://xx.xxx.com"',
    ...
  },
  requestShortener: {
    
    },
  compilerPath: '',
  logger: {
    
    
  },
  options: {
    
    },
  outputOptions: {
    
    },
  bail: false,
  profile: false,
  params: {
    
    
    normalModuleFactory: NormalModuleFactory {
    
    
      hooks: [Object],
      resolverFactory: [ResolverFactory],
      ruleSet: [Object],
      context: '/Users/zhangyu/web/yongliu/sub-test-ddd/src',
      fs: [CachedInputFileSystem],
      _globalParserOptions: [Object],
      _globalGeneratorOptions: {
    
    },
      parserCache: [Map],
      generatorCache: [Map],
      _restoredUnsafeCacheEntries: Set(0) {
    
    },
      _parseResourceWithoutFragment: [Function (anonymous)]
    },
    contextModuleFactory: ContextModuleFactory {
    
    
      hooks: [Object],
      resolverFactory: [ResolverFactory]
    }
  },
  mainTemplate: MainTemplate {
    
    },
  chunkTemplate: ChunkTemplate {
    
    },
  runtimeTemplate: RuntimeTemplate {
    
    },
  moduleTemplates: {
    
    },
  moduleMemCaches: undefined,
  moduleMemCaches2: undefined,
  moduleGraph: {
    
    },
  chunkGraph: {
    
    },
  codeGenerationResults: {
    
    },
  processDependenciesQueue: {
    
    },
  addModuleQueue: AsyncQueue {
    
    },
  factorizeQueue: AsyncQueue {
    
    },
  buildQueue: AsyncQueue {
    
    },
  rebuildQueue: AsyncQueue {
    
    },
  creatingModuleDuringBuild: {
    
     },
  entries: Map(9) {
    
    
    'app' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    },
    'pages/index/index' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    },
    'components/loading-page/index' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    },
    'pages/use-chart/index' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    },
    'subpackage-echarts/ec-canvas/ec-canvas' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    },
    'subpackage-echarts/index/index' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    },
    './app.scss__assets_chunk_name__' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    },
    './pages/index/index.scss__assets_chunk_name__' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    },
    './components/loading-page/index.scss__assets_chunk_name__' => {
    
    
      dependencies: [Array],
      includeDependencies: [],
      options: [Object]
    }
  },
  globalEntry: {
    
    
    dependencies: [],
    includeDependencies: [],
    options: {
    
     name: undefined }
  },
  entrypoints: Map(9) {
    
    
    'app' => Entrypoint {
    
    
      groupDebugId: 5000,
      options: [Object],
      _children: [SortableSet [Set]],
      _parents: [SortableSet [Set]],
      _asyncEntrypoints: [SortableSet [Set]],
      _blocks: [SortableSet [Set]],
      chunks: [Array],
      origins: [Array],
      _modulePreOrderIndices: [Map],
      _modulePostOrderIndices: [Map],
      index: 0,
      _runtimeChunk: [Chunk],
      _entrypointChunk: [Chunk],
      _initial: true
    },
    'pages/index/index' => Entrypoint {
    
    
      groupDebugId: 5001,
      options: [Object],
      _children: [SortableSet [Set]],
      _parents: [SortableSet [Set]],
      _asyncEntrypoints: [SortableSet [Set]],
      _blocks: [SortableSet [Set]],
      chunks: [Array],
      origins: [Array],
      _modulePreOrderIndices: [Map],
      _modulePostOrderIndices: [Map],
      index: 1,
      _runtimeChunk: [Chunk],
      _entrypointChunk: [Chunk],
      _initial: true
    }
  },
  asyncEntrypoints: [],
  chunks: Set(8) {
    
    
    Chunk {
    
    
      id: 3,
      ids: [Array],
      debugId: 1000,
      name: 'app',
      idNameHints: [SortableSet [Set]],
      preventIntegration: false,
      filenameTemplate: undefined,
      cssFilenameTemplate: undefined,
      _groups: [SortableSet [Set]],
      runtime: 'runtime',
      files: [SetDeprecatedArray [Set]],
      auxiliaryFiles: Set(0) {
    
    },
      rendered: true,
      hash: '4cdafb006e29619975268c54d16ace97',
      contentHash: [Object: null prototype],
      renderedHash: '4cdafb006e2961997526',
      chunkReason: undefined,
      extraAsync: false
    },
    Chunk {
    
    
      id: 6,
      ids: [Array],
      debugId: 1001,
      name: 'pages/index/index',
      idNameHints: [SortableSet [Set]],
      preventIntegration: false,
      filenameTemplate: undefined,
      cssFilenameTemplate: undefined,
      _groups: [SortableSet [Set]],
      runtime: 'runtime',
      files: [SetDeprecatedArray [Set]],
      auxiliaryFiles: Set(0) {
    
    },
      rendered: true,
      hash: '2df8c7afeffa5b8fa0439233e61f494c',
      contentHash: [Object: null prototype],
      renderedHash: '2df8c7afeffa5b8fa043',
      chunkReason: undefined,
      extraAsync: false
    }
  },
  chunkGroups: [
    Entrypoint {
    
    
      groupDebugId: 5000,
      options: [Object],
      _children: [SortableSet [Set]],
      _parents: [SortableSet [Set]],
      _asyncEntrypoints: [SortableSet [Set]],
      _blocks: [SortableSet [Set]],
      chunks: [Array],
      origins: [Array],
      _modulePreOrderIndices: [Map],
      _modulePostOrderIndices: [Map],
      index: 0,
      _runtimeChunk: [Chunk],
      _entrypointChunk: [Chunk],
      _initial: true
    },
    Entrypoint {
    
    
      groupDebugId: 5001,
      options: [Object],
      _children: [SortableSet [Set]],
      _parents: [SortableSet [Set]],
      _asyncEntrypoints: [SortableSet [Set]],
      _blocks: [SortableSet [Set]],
      chunks: [Array],
      origins: [Array],
      _modulePreOrderIndices: [Map],
      _modulePostOrderIndices: [Map],
      index: 1,
      _runtimeChunk: [Chunk],
      _entrypointChunk: [Chunk],
      _initial: true
    },
  ],
  namedChunkGroups: Map(9) {
    
    },
  namedChunks: Map(11) {
    
    },
  modules: Set(41) {
    
    },
  _modules: Map(41) {
    
    },
  records: {
    
    },
  additionalChunkAssets: [],
  assets: {
    
    
    'app.wxss': RawSource {
    
    
      _valueIsBuffer: true,
      _value: <Buffer >,
      _valueAsBuffer: <Buffer >,
      _valueAsString: undefined
    },
    'pages/index/index.wxss': RawSource {
    
    
      _valueIsBuffer: true,
      _value: <Buffer >,
      _valueAsBuffer: <Buffer >,
      _valueAsString: undefined
    },
    'app.js': CachedSource {
    
    
      _source: [ConcatSource],
      _cachedSourceType: undefined,
      _cachedSource: undefined,
      _cachedBuffer: undefined,
      _cachedSize: undefined,
      _cachedMaps: Map(0) {
    
    },
      _cachedHashUpdate: undefined
    },
    'pages/index/index.js': CachedSource {
    
    
      _source: [ConcatSource],
      _cachedSourceType: undefined,
      _cachedSource: undefined,
      _cachedBuffer: undefined,
      _cachedSize: undefined,
      _cachedMaps: Map(0) {
    
    },
      _cachedHashUpdate: undefined
    },
    'runtime.js': CachedSource {
    
    
      _source: [ConcatSource],
      _cachedSourceType: undefined,
      _cachedSource: undefined,
      _cachedBuffer: undefined,
      _cachedSize: undefined,
      _cachedMaps: Map(0) {
    
    },
      _cachedHashUpdate: undefined
    },
    'common.js': CachedSource {
    
    
      _source: [ConcatSource],
      _cachedSourceType: undefined,
      _cachedSource: undefined,
      _cachedBuffer: undefined,
      _cachedSize: undefined,
      _cachedMaps: Map(0) {
    
    },
      _cachedHashUpdate: undefined
    }
  },
  assetsInfo: Map(27) {
    
    
    'app.wxss' => {
    
     sourceFilename: 'app.scss' },
    'components/loading-page/index.wxss' => {
    
     sourceFilename: 'components/loading-page/index.scss' },
    'pages/index/index.wxss' => {
    
     sourceFilename: 'pages/index/index.scss' },
    'app.js' => {
    
     javascriptModule: false },
    'pages/index/index.js' => {
    
     javascriptModule: false },
    'components/loading-page/index.js' => {
    
     javascriptModule: false },
    'pages/use-chart/index.js' => {
    
     javascriptModule: false },
    'subpackage-echarts/ec-canvas/ec-canvas.js' => {
    
     javascriptModule: false },
    'subpackage-echarts/index/index.js' => {
    
     javascriptModule: false },
    'runtime.js' => {
    
     javascriptModule: false },
    'common.js' => {
    
     javascriptModule: false },
    'app.json' => {
    
     copied: true, sourceFilename: 'app.json' },
    'sitemap.json' => {
    
     copied: true, sourceFilename: 'sitemap.json' },
    'pages/use-chart/index.json' => {
    
     copied: true, sourceFilename: 'pages/use-chart/index.json' },
    'pages/use-chart/index.wxml' => {
    
     copied: true, sourceFilename: 'pages/use-chart/index.wxml' },
    'pages/use-chart/index.wxss' => {
    
     copied: true, sourceFilename: 'pages/use-chart/index.wxss' },
    'pages/index/index.json' => {
    
     copied: true, sourceFilename: 'pages/index/index.json' },
    'pages/index/index.wxml' => {
    
     copied: true, sourceFilename: 'pages/index/index.wxml' },
    'subpackage-echarts/ec-canvas/ec-canvas.json' => {
    
    
      copied: true,
      sourceFilename: 'subpackage-echarts/ec-canvas/ec-canvas.json'
    },
  },
  _assetsRelatedIn: Map(0) {
    
    },
  errors: [],
  warnings: [
  ],
  children: [],
  logging: Map(9) {
    
    
  },
  dependencyFactories: Map(30) {
    
    
  },
  childrenCounters: {
    
    },
  usedChunkIds: null,
  usedModuleIds: null,
  needAdditionalPass: false,
  _restoredUnsafeCacheModuleEntries: Set(0) {
    
    },
  _restoredUnsafeCacheEntries: Map(0) {
    
    },
  builtModules: WeakSet {
    
     <items unknown> },
  codeGeneratedModules: WeakSet {
    
     <items unknown> },
  buildTimeExecutedModules: WeakSet {
    
     <items unknown> },
  _rebuildingModules: Map(0) {
    
    },
  emittedAssets: Set(0) {
    
    },
  comparedForEmitAssets: Set(0) {
    
    },
  fileDependencies: LazySet {
    
    
  },
  contextDependencies: LazySet {
    
    
  },
  missingDependencies: LazySet {
    
    
    
  },
  buildDependencies: LazySet {
    
    
  },
  compilationDependencies: {
    
     add: [Function: deprecated] },
  fullHash: 'af34423fe7957198c3b73910476385cd',
  hash: 'af34423fe7957198c3b7'
}
options object
{
    
    
    amd: undefined,
    bail: undefined,
    cache: {
    
    
      type: 'filesystem',
      allowCollectingMemory: false,
      maxMemoryGenerations: Infinity,
      maxAge: 5184000000,
      profile: false,
      buildDependencies: [Object],
      cacheDirectory: '/Users/zhangyu/web/yongliu/sub-test-ddd/node_modules/.cache/webpack',
      cacheLocation: '/Users/zhangyu/web/yongliu/sub-test-ddd/node_modules/.cache/webpack/default-none',
      hashAlgorithm: 'md4',
      compression: false,
      idleTimeout: 60000,
      idleTimeoutForInitialStore: 5000,
      idleTimeoutAfterLargeChanges: 1000,
      name: 'default-none',
      store: 'pack',
      version: '',
      memoryCacheUnaffected: false
    },
    context: '/Users/zhangyu/web/yongliu/sub-test-ddd/src',
    dependencies: undefined,
    devServer: undefined,
    devtool: false,
    entry: {
    
     main: [Object] },
    experiments: {
    
    
      buildHttp: undefined,
      lazyCompilation: undefined,
      css: undefined,
      futureDefaults: false,
      backCompat: true,
      topLevelAwait: false,
      syncWebAssembly: false,
      asyncWebAssembly: false,
      outputModule: false,
      layers: false,
      cacheUnaffected: false
    },
    externals: undefined,
    externalsPresets: {
    
    
      web: true,
      node: false,
      nwjs: false,
      electron: false,
      electronMain: false,
      electronPreload: false,
      electronRenderer: false
    },
    externalsType: 'var',
    ignoreWarnings: undefined,
    infrastructureLogging: {
    
    
      stream: [WriteStream],
      level: 'info',
      debug: false,
      colors: true,
      appendOnly: false
    },
    loader: {
    
     target: 'web' },
    mode: 'none',
    module: {
    
    
      noParse: undefined,
      unsafeCache: [Function (anonymous)],
      parser: [Object],
      generator: {
    
    },
      defaultRules: [Array],
      rules: [Array]
    },
    name: undefined,
    node: {
    
     global: true, __filename: 'mock', __dirname: 'mock' },
    optimization: {
    
    
      splitChunks: [Object],
      runtimeChunk: [Object],
      emitOnErrors: true,
      removeAvailableModules: false,
      removeEmptyChunks: true,
      mergeDuplicateChunks: true,
      flagIncludedChunks: false,
      moduleIds: 'natural',
      chunkIds: 'natural',
      sideEffects: 'flag',
      providedExports: true,
      usedExports: false,
      innerGraph: false,
      mangleExports: false,
      concatenateModules: false,
      checkWasmTypes: false,
      mangleWasmImports: false,
      portableRecords: false,
      realContentHash: false,
      minimize: false,
      minimizer: [Array],
      nodeEnv: false
    },
    output: {
    
    
      assetModuleFilename: '[hash][ext][query]',
      asyncChunks: true,
      charset: true,
      chunkFilename: '[name].js',
      chunkFormat: 'array-push',
      chunkLoading: 'jsonp',
      chunkLoadingGlobal: 'webpackChunk',
      chunkLoadTimeout: 120000,
      cssFilename: '[name].css',
      cssChunkFilename: '[name].css',
      clean: undefined,
      compareBeforeEmit: true,
      crossOriginLoading: false,
      devtoolFallbackModuleFilenameTemplate: undefined,
      devtoolModuleFilenameTemplate: undefined,
      devtoolNamespace: '',
      environment: [Object],
      enabledChunkLoadingTypes: [Array],
      enabledLibraryTypes: [],
      enabledWasmLoadingTypes: [Array],
      filename: '[name].js',
      globalObject: 'wx',
      hashDigest: 'hex',
      hashDigestLength: 20,
      hashFunction: 'md4',
      hashSalt: undefined,
      hotUpdateChunkFilename: '[id].[fullhash].hot-update.js',
      hotUpdateGlobal: 'webpackHotUpdate',
      hotUpdateMainFilename: '[runtime].[fullhash].hot-update.json',
      iife: true,
      importFunctionName: 'import',
      importMetaName: 'import.meta',
      scriptType: false,
      library: undefined,
      module: false,
      path: '/Users/zhangyu/web/yongliu/sub-test-ddd/weapp',
      pathinfo: false,
      publicPath: '/Users/zhangyu/web/yongliu/sub-test-ddd/weapp',
      sourceMapFilename: '[file].map[query]',
      sourcePrefix: undefined,
      strictModuleExceptionHandling: false,
      trustedTypes: undefined,
      uniqueName: '',
      wasmLoading: 'fetch',
      webassemblyModuleFilename: '[hash].module.wasm',
      workerChunkLoading: 'import-scripts',
      workerWasmLoading: 'fetch'
    },
    parallelism: 100,
    performance: false,
    plugins: [
      [CLIPlugin],
      [CleanWebpackPlugin],
      [CopyPlugin],
      [MinaWebpackPlugin],
      MinaRuntimeWebpackPlugin {
    
    },
      [DefinePlugin]
    ],
    profile: false,
    recordsInputPath: false,
    recordsOutputPath: false,
    resolve: {
    
    
      byDependency: [Object],
      cache: true,
      modules: [Array],
      conditionNames: [Array],
      mainFiles: [Array],
      extensions: [Array],
      aliasFields: [],
      exportsFields: [Array],
      roots: [Array],
      mainFields: [Array],
      alias: [Object]
    },
    resolveLoader: {
    
    
      cache: true,
      conditionNames: [Array],
      exportsFields: [Array],
      mainFields: [Array],
      extensions: [Array],
      mainFiles: [Array]
    },
    snapshot: {
    
    
      resolveBuildDependencies: [Object],
      buildDependencies: [Object],
      resolve: [Object],
      module: [Object],
      immutablePaths: [],
      managedPaths: [Array]
    },
    stats: {
    
     preset: 'normal', colors: true },
    target: 'web',
    watch: true,
    watchOptions: {
    
    }
  }
outputOptions
{
    
    
    assetModuleFilename: '[hash][ext][query]',
    asyncChunks: true,
    charset: true,
    chunkFilename: '[name].js',
    chunkFormat: 'array-push',
    chunkLoading: 'jsonp',
    chunkLoadingGlobal: 'webpackChunk',
    chunkLoadTimeout: 120000,
    cssFilename: '[name].css',
    cssChunkFilename: '[name].css',
    clean: undefined,
    compareBeforeEmit: true,
    crossOriginLoading: false,
    devtoolFallbackModuleFilenameTemplate: undefined,
    devtoolModuleFilenameTemplate: undefined,
    devtoolNamespace: '',
    environment: {
    
    
      arrowFunction: true,
      const: true,
      destructuring: true,
      forOf: true,
      bigIntLiteral: undefined,
      dynamicImport: undefined,
      module: undefined
    },
    enabledChunkLoadingTypes: [ 'jsonp', 'import-scripts' ],
    enabledLibraryTypes: [],
    enabledWasmLoadingTypes: [ 'fetch' ],
    filename: '[name].js',
    globalObject: 'wx',
    hashDigest: 'hex',
    hashDigestLength: 20,
    hashFunction: 'md4',
    hashSalt: undefined,
    hotUpdateChunkFilename: '[id].[fullhash].hot-update.js',
    hotUpdateGlobal: 'webpackHotUpdate',
    hotUpdateMainFilename: '[runtime].[fullhash].hot-update.json',
    iife: true,
    importFunctionName: 'import',
    importMetaName: 'import.meta',
    scriptType: false,
    library: undefined,
    module: false,
    path: '/Users/zhangyu/web/yongliu/sub-test-ddd/weapp',
    pathinfo: false,
    publicPath: '/Users/zhangyu/web/yongliu/sub-test-ddd/weapp',
    sourceMapFilename: '[file].map[query]',
    sourcePrefix: undefined,
    strictModuleExceptionHandling: false,
    trustedTypes: undefined,
    uniqueName: '',
    wasmLoading: 'fetch',
    webassemblyModuleFilename: '[hash].module.wasm',
    workerChunkLoading: 'import-scripts',
    workerWasmLoading: 'fetch'
  }

Guess you like

Origin blog.csdn.net/weixin_43972437/article/details/132855948