Skip to content

webpack

Basic

manifest

(function(modules) {
 //webpackJsonp被挂载到全局了
  window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
    var moduleId, result;
    for (moduleId in moreModules) {
      if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
     // 存储moudleId   
     modules[moduleId] = moreModules[moduleId];
      }
    }
    if (executeModules) {
      for (i = 0; i < executeModules.length; i++) {
        result = __webpack_require__(executeModules[i]);
      }
    }
    return result;
  };
  var installedModules = {};

  function __webpack_require__(moduleId) {
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports;
    }
    var module = installedModules[moduleId] = {
      exports: {}
    };
    // 执行。加载后也会有缓存。
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    return module.exports;
  }
})([]);

可以看到 webpack 内部是一个IIFE。webpack 打包后的文件,就是通过一个个函数隔离 module 的作用域,以达到不互相污染的目的。

Module: an upgraded version of a file. There are entry modules(Each module can be considered as he root module in a tree of modules. -> ModuleGraph.) and normal modules.

A module, once created and built, contains a lot of meaningful information besides the raw source code, such as: the loaders used, its dependencies, its exports(if any), its hash and much more

Chunk: encapsulates one or module modules. The first chunks are those which defined on the Entry.

splitChunk

cacheGroupFoo: {
    // The number of chunks the module must appear in
    minChunks: 3,
    // Number of bytes put in a chunk(i.e. the sum of the number of bytes for each constituent module)
    // For example, if a chunk contains 2 modules, `x` and `w`, then `nrBytesChunk = nrBytes(x) + nrBytes(w)`.
    minSize: 10,
    // Which modules are to be considered
    modulePathPattern: /node_modules/
}

chunks = multiple modules AKA. module belong to chunks

Based on what we've seen above, a new chunk will be created if all these conditions are met simultaneously:

  • the module must belong to at least 3 chunks
  • the minimum number of bytes of a chunk must be at least 10
  • the modules that would lead to new chunks being created must come from the node_modules folder

default option

optimization: {
  splitChunks: {
    cacheGroups: {
      defaultVendors: {
        idHint: "vendors",
        reuseExistingChunk: true,
        test: NODE_MODULES_REGEXP,
        priority: -10
        },
      // default: false, // or disabling default cache group
      default: {
        idHint: "",
        reuseExistingChunk: true,
        minChunks: 2,
        priority: -20
        },
    }
  },
},

the latter cache group has a greater priority and this plays an important role when a module belongs to multiple cache groups.

As a side note, a cache group inherits some options if they are not specified in the cache group itself.

chunks: 'initial/async' Async means modules that imported by import('')

ref

babel

万能大法

options: {
          presets: [
            ['@babel/preset-env', { loose: true, modules: 'cjs' }],
            ['@babel/preset-react']
          ],
          plugins: [
            [
              'import',
              {
                libraryName: 'antd',
                libraryDirectory: 'es',
                style: 'css'
              }
            ]
          ]
        }

注意有些使用 antd 的场景,仅引入了 antd 组件,但是没有显性引入 import 'antd/dist/antd.css'; 那就肯定是原有配置了 babel-plugin-import,因为它不仅 handle 了 js 的引入,还 handle 了对应 css 的引入。

v5

Single Entry

const path = require('path');
const webpack = require('webpack');
var pkg = require('./package.json');

module.exports = {
  mode: 'development',
  entry: './client/index.js',
  output: {
    path: path.resolve(__dirname, 'static2'),
    filename: 'bundle.js'
  },
  resolve: {
    alias: {
      client: path.resolve(__dirname, 'client/'),
    },
  },
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: [/(node_modules\/(?!_?(nodeMouldesToBeProcessed)))/],
        loader: 'babel-loader',
        options: {
          presets: [['@babel/preset-env', { 
            loose: true, 
            // modules: 'cjs' // if there're some mixed use of cjs and esmodule
          }], '@babel/preset-react']
        }
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.s[ac]ss$/i,
        use: ['style-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.less$/i,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        test: /.(gif|jpg|jpeg|png|woff|woff2|eot|ttf|svg)$/,
        type: 'asset/resource'
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.version': JSON.stringify(pkg.version),
    })
  ],
  devtool: 'cheap-source-map',
  devServer: {
    static: path.join(__dirname, 'client'),
    compress: true,
    port: 9000,
    hot: true,
    proxy: {
      '/api': 'http://localhost:3000'
    },
    client: {
      overlay: {
        warnings: false,
        errors: true
      }
    }
  }
};

devServer: use webpack serve to trigger. static means where to locate index.html and other static files.

  • webpack-dev-server 的 index.html 是怎么注入的?其实不存在注入,而是通过 html-webpack-plugin 在内存中生成 html,再访问这个 html,自然就有了。
  • static 是什么意思?简单说来,就是 webpack-dev-server 开了一个 static-middleware 的路由作为 backup。

周边

  • https://www.npmjs.com/package/tapable