深度解析webpack5以及打包实践攻略,看完这篇带你玩转高级自定义打包

1.webpack5对比webpack4做了哪些优化

Webpack 5 对比Webpack 4 存在一些重要的优化。Webpack 5 在性能、构建速度、Tree Shaking 等方面都有所改进:

  1. 性能改进

    • Webpack 5 在构建速度和性能方面有所提升。这主要是通过改进缓存策略、优化构建算法以及增强的持久化缓存等方式实现的。这意味着更快的构建时间和更高的整体性能。
  2. 支持Tree Shaking

    • 在 Webpack 5 中,Tree Shaking(树摇)机制得到了改进,这意味着它更有效地识别和删除未使用的代码,以减小最终构建的文件大小。
  3. 对ES6模块和JSON模块的优化

    • Webpack 5 对于 ES6 模块和 JSON 模块的处理更加智能和优化,从而提高了构建速度。
  4. 默认持久化缓存

    • Webpack 5 默认启用了持久化缓存,这意味着构建过程中的中间结果会被缓存,以便在后续的构建中重复使用,进而加快构建速度。
  5. 改进的 Tree Shaking 算法

    • Webpack 5 中对 Tree Shaking 算法进行了改进,使其更加精确和高效,从而能够更好地识别和删除未使用的代码。
  6. 内置的模块类型优化

    • Webpack 5 提供了一种新的模块类型------module.type,可以通过配置文件进行设置,以便更好地与不同的目标环境进行兼容和优化。

2.webpack5的核心原理

Webpack 5 的核心原理涉及了模块化、依赖分析、打包优化等多个方面。下面是Webpack 5 的核心原理的概述:

  1. 模块化

    • Webpack 5 将项目中的各个文件视为模块,这些模块可以是 JavaScript 文件、CSS 文件、图片、字体等各种资源。它使用模块化的思想来管理这些文件,使得项目的各个部分可以相互依赖、独立开发和测试。
  2. 依赖分析

    • 在构建过程中,Webpack 5 会对项目中的模块进行依赖分析,即分析模块之间的依赖关系。通过识别模块之间的 import、require 等语句,Webpack 能够确定模块之间的依赖关系,从而构建出一个依赖关系图,这也是 Webpack 5 能够正确地打包项目中所有依赖的基础。
  3. 打包优化

    • Webpack 5 会根据依赖关系图进行打包优化。这包括但不限于:
      • Tree Shaking:删除项目中未使用的代码,以减小打包后的文件大小。
      • 代码分割:将项目代码拆分为多个块,按需加载,从而提高页面加载速度。
      • 持久化缓存:通过缓存构建过程中的中间结果,减少重复工作,提高构建速度。
      • 多线程构建:利用多线程或者多进程来并行处理模块,加快构建速度。
      • 模块类型优化:根据目标环境,优化模块类型,提高兼容性和执行效率。
      • 自动刷新:在开发过程中,Webpack 5 会监视文件的变化,并实时更新构建结果,提供热更新功能。
  4. 插件系统

    • Webpack 5 提供了丰富的插件系统,允许开发者通过插件来扩展和定制 Webpack 的功能。通过插件系统,开发者可以在打包过程的各个阶段介入,实现自定义的功能,比如代码压缩、资源优化、文件拷贝等。
  5. 编译器和解析器

    • Webpack 5 内部包含了编译器和解析器,用于将项目中的源代码转换为可执行的 JavaScript 代码。编译器负责将各种类型的模块转换为标准的 JavaScript 代码,解析器负责解析 JavaScript 代码中的语法,构建 AST(抽象语法树),以便后续的依赖分析和打包优化。

    Webpack 5 的核心原理包括模块化、依赖分析、打包优化、插件系统以及编译器和解析器等多个方面,它通过这些机制来实现对项目代码的打包和优化,从而提供了高效、灵活的前端构建解决方案。

3.webpack5实践-常用API

在webpack配置文件webpack.config.js中,下面介绍一些必需要掌握的api:

1. entry(入口)

Webpack 5 的入口配置指定了打包的起始点。可以是一个单一的入口或多个入口。下面举例单一入口代码:

javascript 复制代码
module.exports = {
  entry: './src/index.js'
};

搞懂了后,后面我再继续探索多入口,由浅入深,举一反三,加油!!!

2. output(输出)

output 配置项指定了打包后的文件输出的位置和文件名等信息。

javascript 复制代码
module.exports = {
  output: {
    filename: 'bundle.js', //打包后生成js文件名
    path: path.resolve(__dirname, 'dist')。 //js文件在dist目录里头
  }
};

3. devServer(开发服务器)

devServer 配置项用于配置开发服务器,提供了许多有用的功能,如自动刷新、热模块替换等。

javascript 复制代码
module.exports = {
  devServer: {
    contentBase: './dist', //项目打包后生成文件的目录名
    port: 8080, //本地运行的端口号
    hot: true。//是否开启热更新
  }
};

4. mode(模式)

mode 配置项指定了当前构建的环境,可选值有 'development':开发模式、'production' :生产环境和 'none' 。

javascript 复制代码
module.exports = {
  mode: 'development' //
};

5. module(模块)

module 配置项用于配置不同类型模块的处理规则,例如配置 loader。

javascript 复制代码
module.exports = {
  module: {
    rules: [
        {
          //.js文件loader
          test: /\.js$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true,
              cacheCompression: false
            }
          }
        },
        {
          //.vue文件loader
          test: /\.vue$/,
          use: 'vue-loader'
        },
        {
          //.css文件loader
          test: /\.css$/,
          use: [isProduction ? MiniCssExtractPlugin.loader : 'vue-style-loader', 'css-loader']
        },
        { //图片
          test: /\.(png|svg|jpg|jpeg|gif|bmp|ico)$/,
          type: 'asset/resource',
          generator:{ 
              filename: 'image/[contenthash:10].[ext]',
          }, 
        },
        { //视频或者文件在这里配置
          test: /\.(mp4|ttf)$/,
          use: {
            loader: 'file-loader',
            options: {
              name: 'video/[contenthash:10].[ext]',
            },
          },
        },
      ]
  }
};

6. resolve(解析)

resolve 配置项用于配置模块解析的规则。

javascript 复制代码
module.exports = {
  resolve: {
    extensions: ['.js', '.jsx','vue'],
    alias: {
      '@': path.resolve(__dirname, 'src/')
    }
  }
};

7. optimization(优化)

optimization 配置项用于配置打包优化相关的选项,可以用第三方插件对js文件进行分包和压缩,减少包的体积。

javascript 复制代码
const ESBuildPlugin = require('esbuild-webpack-plugin').default;

module.exports = {
  optimization: {
      minimizer: [new ESBuildPlugin()],
      splitChunks: {
        cacheGroups: {
          defaultVendors: {
            name: 'chunk-vendors',
            test: /[\\/]node_modules[\\/]/,
            priority: -10,
            chunks: 'initial'
          },
          common: {
            name: 'chunk-common',
            minChunks: 2,
            priority: -20,
            chunks: 'initial',
            reuseExistingChunk: true
          }
        }
      }
    },
};

8. plugins(插件)

plugins 配置项用于配置各种 webpack 插件。

javascript 复制代码
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {VueLoaderPlugin} = require('vue-loader');
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const path = require('path');
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
  plugins: [
      new VueLoaderPlugin(), //在 webpack 中,需要使用 vue-loader 来处理 Vue.js 单文件组件。VueLoaderPlugin 插件的作用是向 webpack 中添加必要的 loader 配置,以确保 vue-loader 能够正确地解析和加载 Vue.js 单文件组件。同理,用react框架的也可以用同样的方式配置react的loader
      new HtmlWebpackPlugin({  //  webpack 中生成 HTML 文件的插件
        template: 'index.html',//自动创建一个 HTML 文件
        minify: {
          collapseWhitespace: true, //去掉空格
          removeComments: true, //删除注释
          removeAttributeQuotes: true, //删除双引号
          removeEmptyAttributes: true, //删除声明了但是没赋值的属性 let a;
          minifyCSS: true, //压缩css
          minifyJS: true, //压缩js
          minifyURLs: true,//是否对 HTML 文件中的 URL 进行最小化处理
          removeTagWhitespace: true,//是否移除 HTML 标签之间的空白字符
      },
        favicon: path.resolve('favicon.ico') //配置icon图标
      }),
      isProduction ?new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash:8].css',   //生成css文件路径和名字
        chunkFilename: 'css/[name].[contenthash:8].chunk.css', //生成css的chunkFilename				文件路径和名
      }): null,//将 CSS 提取为独立文件的插件
      new webpack.DefinePlugin({
        __VUE_OPTIONS_API__: false,
        __VUE_PROD_DEVTOOLS__: false,
      }),//定义全局常量的插件。它允许你在编译时创建全局常量,这些常量在编译过程中会被替换为实际的值。这在配置 webpack 打包过程中经常用于传递环境变量或者其他常量。
      new CleanWebpackPlugin(), //每次打包前清理旧的编译文件
  ].filter(Boolean)
};

以上是 Webpack 5 中一些常用配置项的用法,它们可以组合使用项目的需求,搞懂以后,基本上一些中小型项目的框架搭建和打包可以轻松玩转。

4.高级自定义玩转webpack5

如果,简单的webpack5框架无法满足你项目的业务需求,下面我们可以配置一些高级玩法,比如, 配置多入口文件,搭载多页面应用,多页面应用利于SEO,在上述代码文件webpack.config.js的基础上,新增文件webpack.util.js配置自定义入口,

javascript 复制代码
const glob = require('glob');
const HtmlWebpackPlugin = require('html-webpack-plugin');

function setEntry() {
  const files = glob.sync('./src/pages/**/index.js') //多文件入口的路径
  const entry = {}
  files.forEach(file => {
    const ret = file.match(/^\.\/src\/pages\/(\S*)\/index\.js$/)
    if (ret) {
      entry[ret[1]] = {
        import: file,
        dependOn: 'vue_vendors',
      }
    }
  })
   // 拆分vue依赖
   entry['vue_vendors'] = {
    import: ['vue'],
    filename: 'commom/[name].js'
  }
  return entry
}
function getTemplate() {
    const files = glob.sync(`./src/index.html`)
    return files[0]
}
  
function setHtmlPlugin() {
    const files = glob.sync('./src/pages/**/index.js')
    const options = []
    files.forEach(file => {
      const ret = file.match(/^\.\/src\/pages\/(\S*)\/index\.js$/)
      if (ret) {
        const name = ret[1]
        if(name === 'home'){
          options.push(new HtmlWebpackPlugin({
            filename: 'index.html',
            template: getTemplate(),
            title: name,
            minify: {
              collapseWhitespace: false,
              removeComments: true, 
            },
            chunks: ['vue_vendors',name]
          }))
        }
        options.push(new HtmlWebpackPlugin({
          filename: `${name}.html`,
          template: getTemplate(),
          title: name,
          minify: {
            collapseWhitespace: false,
            removeComments: true, 
          },
          chunks: ['vue_vendors',name]
        }))
      }
    })
    return options
}
module.exports = {
  setEntry,
  setHtmlPlugin
}

然后再webpack.config.js文件中引入webpack.util.js文件的方法

javascript 复制代码
const { setEntry,setHtmlPlugin } = require('./webpack.util.js')
module.exports = () => {
	return {
	...
	entry: setEntry,//引入自定义入口文件的方法
	plugins: [
      ...setHtmlPlugin(), //引入自定义设置html的方法
      //plugins中的剩余代码同上
    ].filter(Boolean)
    }
}

此外,如果需要自定义区分生产环境和开发环境,也可以新增两个不同的webpack配置文件,区分两个不同的环境,这种情况一般在大型项目中比较常用,举个简单的例子:

  • 在开发环境webpack.dev.js
javascript 复制代码
const config = require('./webpack.config.js')
module.exports = Object.assign({}, config, {
    mode: "development",
    devtool: 'inline-source-map',
    devServer: {
        open: true, 
        hot: true, 
        port: 8000, 
        static: "./public", 
        historyApiFallback: true,
        //proxy: {
          // '/': {
          //   target: 'http://127.0.0.1',
          //   pathRewrite:{'^/':'/'},
          //   secure: false,
          //   changeOrigin: true,
          // },
        //}
    },
    ...
})
  • 在生产环境webpack.prod.js中配置
javascript 复制代码
const config = require('./webpack.config.js')
module.exports = Object.assign({}, config, {
    mode: "production",
    devtool: false,
    ...
})

最后,在package.json文件中分别设置两个不同环境的启动方式:

javascript 复制代码
{
 "name": "webpack5",
 "version": "1.0.0",
 "description": "搭建webpack5框架",
 "main": "webpack.config.js",
 "scripts": {
    "build": "webpack --config webpack.prod.js --mode production", //生产环境
    "start": "webpack serve --config ./webpack.dev.js --mode development", //开发环境
    "test": "echo \"Error: no test specified\" && exit 1" //暂无测试环境,可根据自己的业务配置
  },
  "keywords": [],
  "author": "高级架构师",
  "license": "ISC",
  "dependencies": {
    "clean-webpack-plugin": "^4.0.0",
    "element-plus": "^2.4.2",
    "esbuild-webpack-plugin": "^1.1.0",
    "vue": "3.2.26",
  },
  "devDependencies": {
    "@babel/core": "^7.23.3",
    "@babel/plugin-transform-runtime": "^7.23.4",
    "@babel/preset-env": "^7.23.3",
    "babel-loader": "^9.1.3",
    "html-webpack-plugin": "^5.5.3",
    "mini-css-extract-plugin": "^2.7.6",
    "vue-loader": "^17.3.1",
    "vue-style-loader": "^4.1.3",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1"
  }
}

我们想启动开发环境:npm run dev,线上环境:npm run build

最后也是本文最重要的,码字不易,我会持续输出前端技术干货,欢迎点赞关注加收藏,你的鼓励是我持之以恒码字的动力,感谢!!!

相关推荐
桂月二二21 分钟前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062062 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb2 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角2 小时前
CSS 颜色
前端·css
浪浪山小白兔3 小时前
HTML5 新表单属性详解
前端·html·html5
lee5763 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579653 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
limit for me4 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者4 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
qq_392794484 小时前
前端缓存策略:强缓存与协商缓存深度剖析
前端·缓存