webpack高级配置Code Split 代码分割 多入口 单入口

打包代码时会将所有 js 文件打包到一个文件中,体积太大了。我们如果只要渲染首页,就应该只加载首页的 js 文件,其他文件不应该加载。

所以我们需要将打包生成的文件进行代码分割,生成多个 js 文件,渲染哪个页面就只加载某个 js 文件,这样加载的资源就少,速度就更快。

代码分割(Code Split)主要做了两件事:

1.  分割文件:将打包生成的文件进行分割,生成多个 js 文件。
2.  按需加载:需要哪个文件就加载哪个文件。

新建文件

├── public
├── src
|   ├── app.js
|   └── main.js
├── package.json
└── webpack.config.js 

webpack.config.js 配置

const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  // 单入口
  // entry: './src/main.js',
  // 多入口
  entry:{
    main: './src/main.js',
    app: './src/app.js',
  },
  output: {
    path: path.resolve(__dirname, "dist"),
    // [name]是webpack命名规则,使用chunk的name作为输出的文件名。
    // 什么是chunk?打包的资源就是chunk,输出出去叫bundle。
    // chunk的name是啥呢? 
	//比如: entry中xxx: "./src/xxx.js", name就是xxx。注意是前面的xxx,和文件名无关。
    // 为什么需要这样命名呢?如果还是之前写法main.js,那么打包生成两个js文件都会叫做main.js会发生覆盖。(实际上会直接报错的)
    filename: "[name].js",
    // clear: true,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template:path.resolve(__dirname,"public/index.html"),
    }),
  ],
  mode: "production",
};

下载依賴

npm init -y  生成 package.json

npm i webpack webpack-cli html-webpack-plugin -D   生成node包  html-webpack-plugin 插件

打包 npx  webpack

多入口使用同一段代码 优化  // 代码分割配置 splitChunks

const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  // 单入口
  // entry: './src/main.js',
  // 多入口
  entry:{
    main: './src/main.js',
    app: './src/app.js',
  },
  output: {
    path: path.resolve(__dirname, "dist"),
    // [name]是webpack命名规则,使用chunk的name作为输出的文件名。
    // 什么是chunk?打包的资源就是chunk,输出出去叫bundle。
    // chunk的name是啥呢? 
	//比如: entry中xxx: "./src/xxx.js", name就是xxx。注意是前面的xxx,和文件名无关。
    // 为什么需要这样命名呢?如果还是之前写法main.js,那么打包生成两个js文件都会叫做main.js会发生覆盖。(实际上会直接报错的)
    filename: "[name].js",
    // clear: true,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template:path.resolve(__dirname,"public/index.html"),
    }),
  ],
  mode: "production",
  optimization: {
      // 代码分割配置
      splitChunks: {
        chunks: "all", // 对所有模块都进行分割
        // 以下是默认值
        // minSize: 20000, // 分割代码最小的大小
        // minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
        // minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
        // maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
        // maxInitialRequests: 30, // 入口js文件最大并行请求数量
        // enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
        // cacheGroups: { // 组,哪些模块要打包到一个组
        //   defaultVendors: { // 组名
        //     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
        //     priority: -10, // 权重(越大越高)
        //     reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
        //   },
        //   default: { // 其`他没有写的配置会使用上面的默认值
        //     minChunks: 2, // 这里的minChunks权重更大
        //     priority: -20,
        //     reuseExistingChunk: true,
        //   },
        // },
        // 修改配置
        cacheGroups: {
          // 组,哪些模块要打包到一个组
          // defaultVendors: { // 组名
          //   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
          //   priority: -10, // 权重(越大越高)
          //   reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
          // },
          default: {
            // 其他没有写的配置会使用上面的默认值
            minSize: 0, // 我们定义的文件体积太小了,所以要改打包的最小文件体积
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true,
          },
        },
      },
    },
};

 按需加载动态导入

如果有一些初始加载用不上的资源 就不需要一上来就加载 

1. 修改文件

- main.js

```js
import { sum } from './math.js';
// import count from "./count.js";

console.log("hello main");
console.log(sum(1,2,3));
// document.getElementById('btn').onclick=function(){
// 	console.log(count(2,1));
// };

document.getElementById('btn').onclick=function(){
	  // 动态导入 --> 实现按需加载
	  // 即使只被引用了一次,也会代码分割
	import('./count').then(
	(res)=>{
	  console.log('模块动态加载成功',res);
	})
	.catch((err)=>{
		console.log('模块加载失败',err);
	})
};


```

- app.js

```js
console.log("hello app");
```

- public/index.html

```html


  
    
    
    
    Code Split
  
  
    

hello webpack

``` ```count.js export default function count(x,y){ return x-y; }

单入口

开发时我们可能是单页面应用(SPA),只有一个入口(单入口)。那么我们需要这样配置:

js/math.js

export function mul(...args){
	 return args.reduce((p,c)=>p+c,0);
}
import count  from "./js/count.js";
import sum from "./js/sum.js";
//要想webpack打包资源必须引入该资源
import "./css/iconfont.css";
import "./css/index.css";
import "./less/index.less";
import "./sass/index.sass";
import "./sass/test1.scss";
import "./styl/index.styl";
const result=count(2,1);
console.log(result);
console.log(sum(1,2,3,4));

document.getElementById("btn").onclick=function(){
	  // eslint会对动态导入语法报错,需要修改eslint配置文件
	  // webpackChunkName: "math":这是webpack动态导入模块命名的方式
	import(/*webpackChunkName: "math"*/"./js/math").then(({mul})=>{
		 console.log(mul(3,3));
	});
}


if(module.hot){
	
	//判断是否支持热模块 替换功能
	module.hot.accept("./js/count.js");
	module.hot.accept("./js/sum.js");
}

 eslint会对动态导入语法报错,需要修改eslint配置文件

module.exports = {
  // 继承 Eslint 规则
  extends: ["eslint:recommended"],
  env: {
    node: true, // 启用node中全局变量
    browser: true, // 启用浏览器中全局变量
  },
  parserOptions: {
    ecmaVersion: 6, //es6
    sourceType: "module", //es module
  },
  rules: {
    "no-var": 2, // 不能使用 var 定义变量
  },
  plugins:["import"],//解決动态导入语法报错
};

打包生成带数字文件名 修改文件名 精准定位 文件  原单入口   webpack.prod.js 配置

module.exports = {
...
  output: {
    path: path.resolve(__dirname, "../dist"), // 生产模式需要输出
    filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
	chunkFilename:'static/js/[name].js', //打包输出的其他文件命名
    clean: true,
  },
....
}

CodeSplit 统一命名  图片 JS  样式 命名

const os = require("os");
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");

// cpu核数
const threads = os.cpus().length;

// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
  return [
    MiniCssExtractPlugin.loader,
    "css-loader",
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    preProcessor,
  ].filter(Boolean);
};

module.exports = {
  entry: "./src/main.js", //相对路径
  output: {
	  //所有文件输出路径
	  //__dirname node.js 的变量,代表当前文件夹的目录
    path: path.resolve(__dirname, "../dist"), // 绝对路径
	// 入口文件打包输出文件名
    filename: "static/js/[name].js", 
	//打包输出的其他文件命名
	chunkFilename:'static/js/[name].chunk.js', 
	//图片 字体等通过type:asset处理资源命名
	assetModuleFilename:"static/media/[hash:8][ext][query]",
	//自动清空上次打包内容
	//原理:在打包前,将path整个目录清空,再进行打包
    clean: true,
  },
  module: {
    rules: [
      {
        oneOf: [
          {
            // 用来匹配 .css 结尾的文件
            test: /\.css$/,
            // use 数组里面 Loader 执行顺序是从右到左
            use: getStyleLoaders(),
          },
          {
            test: /\.less$/,
            use: getStyleLoaders("less-loader"),
          },
          {
            test: /\.s[ac]ss$/,
            use: getStyleLoaders("sass-loader"),
          },
          {
            test: /\.styl$/,
            use: getStyleLoaders("stylus-loader"),
          },
          {
            test: /\.(png|jpe?g|gif|svg)$/,
            type: "asset",
            parser: {
              dataUrlCondition: {
                maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
              },
            },
            // generator: {
            //   // 将图片文件输出到 static/imgs 目录中
            //   // 将图片文件命名 [hash:8][ext][query]
            //   // [hash:8]: hash值取8位
            //   // [ext]: 使用之前的文件扩展名
            //   // [query]: 添加之前的query参数
            //   filename: "static/imgs/[hash:8][ext][query]",
            // },
          },
          {
            test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
            type: "asset/resource",
			//复用
            // generator: {
            //   filename: "static/media/[hash:8][ext][query]",
            // },
          },
          {
            test: /\.js$/,
            // exclude: /node_modules/, // 排除node_modules代码不编译
            include: path.resolve(__dirname, "../src"), // 也可以用包含
            use: [
              {
                loader: "thread-loader", // 开启多进程
                options: {
                  workers: threads, // 数量
                },
              },
              {
                loader: "babel-loader",
                options: {
                  cacheDirectory: true, // 开启babel编译缓存
                  cacheCompression: false, // 缓存文件不要压缩
                  plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
                },
              },
            ],
          },
        ],
      },
    ],
  },
  plugins: [
    new ESLintWebpackPlugin({
      // 指定检查文件的根目录
      context: path.resolve(__dirname, "../src"),
      exclude: "node_modules", // 默认值
      cache: true, // 开启缓存
      // 缓存目录
      cacheLocation: path.resolve(
        __dirname,
        "../node_modules/.cache/.eslintcache"
      ),
      threads, // 开启多进程
    }),
    new HtmlWebpackPlugin({
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    // 提取css成单独文件
    new MiniCssExtractPlugin({
      // 定义输出文件名和目录
      filename: "static/css/[name].css",
	  chunkFilename:"static/css/[name].chunk.css", //动态导入的CSS命名
    }),
    // css压缩
    // new CssMinimizerPlugin(),
  ],
  optimization: {
    minimizer: [
      // css压缩也可以写到optimization.minimizer里面,效果一样的
      new CssMinimizerPlugin(),
      // 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
      new TerserPlugin({
        parallel: threads, // 开启多进程
      }),
      // 压缩图片
      new ImageMinimizerPlugin({
        minimizer: {
          implementation: ImageMinimizerPlugin.imageminGenerate,
          options: {
            plugins: [
              ["gifsicle", { interlaced: true }],
              ["jpegtran", { progressive: true }],
              ["optipng", { optimizationLevel: 5 }],
              [
                "svgo",
                {
                  plugins: [
                    "preset-default",
                    "prefixIds",
                    {
                      name: "sortAttrs",
                      params: {
                        xmlnsOrder: "alphabetical",
                      },
                    },
                  ],
                },
              ],
            ],
          },
        },
      }),
    ],
    // 代码分割配置
    splitChunks: {
      chunks: "all", // 对所有模块都进行分割
      // 其他内容用默认配置即可
    },
  },
  // devServer: {
  //   host: "localhost", // 启动服务器域名
  //   port: "3000", // 启动服务器端口号
  //   open: true, // 是否自动打开浏览器
  // },
  mode: "production",
  devtool: "source-map",
};

你可能感兴趣的:(webpack,webpack,vue.js,javascript)