版本要求

node版本需要18及以上,否则下载最新的webpack一些包,运行起来会出问题

npm版本一般都是跟随node

建议

最好是可以利用nvm来对你电脑的node版本进行管理

如何查看版本

  1. 调出来你的cmd工具

    按键:Win+R

  2. 查看node版本

    1
    node -v

    image-20240517160158000

    得到版本为V 18.18.2

  3. 查看npm版本

    1
    npm -v

    image-20240517160244635

    得到版本为V 9.8.1

一、新建项目

新建一个项目,并在编辑器里面打开,这里用的是Webstorm,项目名字是WebpackCreateVue


二、初始化项目

打开终端, 运行下面这段命令,会给我们的项目初始化,生成一个package.json文件

1
npm init -y

image-20240517161006850


package.json是什么

package.json 文件是一个重要的文件,存在于 Node.js 应用或前端项目(通常用到了 Node.js 工具链,如使用 npm/yarn 进行包管理的项目)的根目录中

它用于存储项目的元数据和配置信息

这个文件是用 JSON 格式编写的,提供了一种标准化的方式来组织项目信息和管理项目的依赖

主要作用包括但不限于:

  1. 项目元数据

    定义项目的名称、版本、描述、作者、许可证等信息

    这对于项目的标识和分发非常重要

  2. 依赖管理

    列出了项目所需的各种依赖包及其版本号

    这使得项目在不同环境中的部署变得容易和一致,因为 npmyarn 这样的包管理器可以自动安装正确版本的依赖

  3. 脚本

    定义一系列脚本命令,如启动项目、编译构建、测试等

    这使得项目相关的任务可以轻松执行,增强了开发效率

  4. 配置信息

    可以包含项目配置信息,如构建系统、测试框架和其他工具的配置

    这些配置通常在开发过程中经常需要修改或参考

  5. 私有标记

    如果 package.json 中包含 "private": true 字段,可以防止不小心将私有仓库发布到 npm

例如,一个典型的 package.json 文件可能看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "my-awesome-project",
"version": "1.0.0",
"description": "A description of the project.",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Your Name",
"license": "ISC",
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}

在这个例子中,你可以看到项目名称、版本、描述、主入口文件、脚本、作者、许可证以及依赖和开发依赖等信息

通过这些信息,开发者和工具可以了解如何处理和运行项目


三、搭建项目

这一步将要实现目标就是:

  1. webpack区分打包环境
  2. 给项目添加vue
  3. 给项目添加css预处理器
  4. 把项目跑起来

3.1-Webpack基础包

执行下面这段命令,我们就可以启动webpack项目了,这些包在使用Webpack进行项目构建时常用到的

1
npm install webpack-dev-server webpack webpack-cli webpack-merge --save-dev

这时候我们看到到项目里面多出来了一个目录node_modules,一个文件package-lock.jsonpackage.json里面多出来了一个devDependencies

多出来一个目录node_modules是干什么的

node_modules目录在JavaScriptNode.js项目中扮演着非常重要的角色

当你使用npm(Node Package Manager)yarn等包管理工具安装包(libraries)或依赖(dependencies)时,这些安装的包都会被放置在node_modules目录下

以下是node_modules的一些详细解释:

  1. 依赖存放地

    项目所需的所有第三方包和它们的依赖都会被下载并存放在这个目录里

    这些依赖可能是你直接安装的,也可能是你安装的包所依赖的其他包

  2. 项目与依赖隔离

    通过将所有依赖放在单独的目录中,node_modules帮助项目保持组织性,同时确保了项目的根目录清爽、有序

    这也使得依赖管理更为集中和简单

  3. 模块解析

    当你在项目中require或从ES6模块中import模块时,Node.js会默认在node_modules目录中查找这些模块

    这是因为Node.js的模块解析算法会检查这个目录来寻找安装的包

  4. 便于版本控制和部署

    node_modules通常不会被提交到版本控制系统(如Git)中,因为依赖可以通过package.json文件中记录的信息重新安装

    这样做可以避免不必要的文件被提交,减小仓库大小,并确保每个环境(开发、测试、生产)都使用确切相同版本的依赖

  5. 本地化依赖

    node_modules目录的存在确保了项目的依赖是本地化的,这意味着不同的项目可以使用不同版本的相同依赖而互不干扰

    这对于处理依赖之间的潜在冲突、实现版本控制非常有帮助

node_modules是项目的基石之一,它存储项目所需的所有外部代码,使得开发者不需要手动复制或链接到全局安装的库

这个机制极大地简化了JavaScriptNode.js的开发流程,同时提高了项目的可移植性和易管理性

多出来一个文件package-lock.json是干什么的

package-lock.json是一个由npm自动生成的文件,它在几个方面对Node.js项目非常重要:

  1. 锁定依赖版本

    此文件确保每次安装依赖时,无论安装环境或时间如何,都会得到相同版本的依赖

    package-lock.json详细记录了项目所使用的每个依赖包的确切版本,包括嵌套依赖(即依赖的依赖)

  2. 确保一致性

    每当您或您的团队成员运行npm install时,package-lock.json文件都会让安装过程参考这个文件中记载的具体版本,这就确保了每个人的开发环境都是一致的,无论何时进行安装

  3. 加快安装过程

    因为package-lock.json记录了整个依赖树的详细信息,所以npm可以利用这些信息来跳过部分依赖计算和版本解决步骤,从而加快安装过程

  4. 安全性

    package-lock.json可以为依赖关系树中的每一个包提供更详细的来源信息,包括包的来源地址和哈希校验码

    如果安装的包的哈希码与package-lock.json不一致,npm会警告用户,这能够在一定程度上预防修改或损坏的依赖包对项目的破坏

虽然package-lock.json不需要手动编辑,但它应该和项目一起被提交到版本控制系统(Git仓库)中

这样确保了所有参与项目的开发者以及部署环境可以使用同样版本的依赖,保持环境之间的一致性

devDependencies和dependencies区别是什么

package.json文件中,dependenciesdevDependencies是两种不同类型的依赖声明,它们在Node.js项目中具有不同的用途和重要性:

  1. dependencies:

    • 这些是项目运行时所必需的依赖。无论是在生产环境还是其他环境,只要你的应用正在运行,这里列出的模块就是必需的
    • 例如,如果你的项目是一个web服务,那么像express这样的包就应该列在dependencies
    • 当你运行npm install <package_name>(没有指定任何范围标志)时,包会默认被添加到dependencies
  2. devDependencies:

    • 这些依赖仅在开发过程中需要,比如编译工具、测试框架或文档生成工具

      它们不是项目运行时必须的,只是在开发过程中为了测试、构建或编译你的项目而需要

    • 举例来说,如果你使用Jest来测试你的项目,那么jest应该被列为一个开发依赖

    • 通过运行npm install <package_name> --save-dev来安装并将一个包添加为devDependencies

主要区别在于它们的使用场景:dependencies是项目运行所需的依赖,而devDependencies是仅在开发过程中需要的依赖

在进行包管理时正确区分这两种依赖类型,对于确保项目的依赖清单既准确又高效尤为重要

webpack-dev-server webpack webpack-cli webpack-merge这4个包是干什么的

下面我将逐一解释它们各自的作用:

  • webpack-dev-server

    这是一个轻量级的服务器,它可以提供静态文件服务,同时具备热更新(hot reloading)功能

    当你修改了代码后,它能自动重新加载显示在浏览器上的页面或组件,从而大大提高开发效率

  • webpack:

    Webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler)

    它会分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式以供浏览器使用

  • webpack-cli:

    这个包提供了可以在命令行中使用的webpack命令,让你能够通过命令行方式来运行webpack的打包、构建等任务

  • webpack-merge:

    在实际开发过程中,我们常常需要针对不同的环境(如开发环境、生产环境)进行不同的配置,webpack-merge可以帮助我们轻松合并这些配置

    这意味着你可以有一个基本的webpack配置文件,并根据不同的需求,将与环境相关的配置合并进来

为什么创建Webpack项目需要这些包:

  • webpack是核心包,负责整个项目的模块打包和构建
  • webpack-cli允许我们通过命令行接口来使用Webpack,为开发者提供了操作Webpack的便利方式
  • webpack-dev-server提供了一个开发服务器,带有热更新特性,极大地提高了开发效率
  • webpack-merge是为了更灵活地控制不同环境下的配置需求


3.2-配置文件

项目内创建webpackConfig目录,用来保存和webpack相关的配置文件,和项目文件分离出来

image-20240517172236108

webpack.common.js公共配置文件

配置模块解析规则 resolve
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 引入Node.js的path模块
* 该模块提供了一系列处理文件路径的函数。
*/
const path = require('path')


module.exports = {
// 配置模块解析规则
resolve: {
// 后缀名自动补全,当引入模块时,可以不写具体的后缀名,这里指定了可用的后缀名列表
extensions: [
'.js', '.vue', '.css', 'less'
],
// 配置别名,方便在import时使用简写,提高编码效率
alias: {
// 使用'@'作为简写,指向项目的src目录
'@': path.resolve(__dirname, '../src'),
// 'cmp'别名指向组件目录,方便直接引入组件
'cmp': path.resolve(__dirname, '../src/components'),
// 'api'别名指向API接口目录,便于调用接口
'api': path.resolve(__dirname, '../src/api')
}
},
}
extensions的作用

在Webpack的配置文件中,resolve.extensions 数组用于指定哪些文件扩展名可以省略不写

当你尝试通过 importrequire 语句导入一个模块,而没有指定文件扩展名时,Webpack将按照 resolve.extensions 数组中指定的顺序尝试解析文件扩展名

此功能的好处是,当你引入模块时可以不必每次都写上文件的扩展名,从而使得导入语句更简洁。这在一个大型项目中能显著提高开发效率

以一个Vue 3项目为例,Vue 3通常会使用 .vue文件,同时也可能会包含JavaScript .js 文件或是 TypeScript .ts 文件

假设你的文件结构如下,并且希望在导入一些文件时不必指定扩展名,只要你写入了上面的resolve.extensions配置

1
2
3
4
src
├── components
│ └── MyComponent.vue
└── main.js

main.js文件中,你可以像这样导入MyComponent.vue组件,而不需要指定文件扩展名:

1
import MyComponent from './components/MyComponent'

由于.vueresolve.extensions数组中列出,Webpack会自动解析MyComponent./components/MyComponent.vue

正确使用这个配置可以简化模块导入语句,减少冗余,提升开发体验

alias的作用

在 Webpack 的配置文件中,resolve.alias 配置项允许你为模块路径设置一个或多个别名(alias),这使得在导入模块时可以使用这些简短、易懂的别名,而不是长且复杂的相对路径或绝对路径

这个功能对于提高代码的可读性和减少在大型项目中导入模块时路径查找的复杂性非常有帮助

使用 resolve.alias 可以让你在引入模块时更加方便

对于频繁访问的深层目录,你不再需要写出繁琐的相对路径,从而使代码更加清晰

假设你的 Vue 3 项目结构如下:

1
2
3
4
5
6
7
project-root/
├─ src/
│ ├─ components/
│ ├─ views/
│ ├─ utils/
│ └─ App.vue
└─ ...

在没有设置别名的情况下,如果你想从位于 views 目录下的某个组件中导入位于 utils 目录下的某个工具函数,你可能需要写出类似这样的导入语句:

1
import { someUtilityFunction } from '../../utils/someUtilityFunction';

这种相对路径不仅难以阅读,而且当文件结构变动时,路径很可能会被破坏,需要手动更新路径

通过使用 resolve.alias,我们可以为 utils 目录设置一个别名

配置后,在项目中就可以使用别名来代替长路径了:

1
import { someUtilityFunction } from '@utils/someUtilityFunction';

同理,@ 别名被设置为 src/ 目录的路径,因此你可以更方便地从项目的任何地方引用 src 目录下的文件

使用 resolve.alias 使得模块导入语句更短、清晰,并且当项目目录结构发生变化时,你只需要更新 webpack.config.js 中的相应别名配置,而不需要去每个文件中修改路径,极大提高了维护效率


配置入口文件entry
1
2
3
4
5
6
module.exports = {
... other code ...
// 配置入口文件
entry: path.resolve(__dirname, '../src/main.js'),
... other code ...
}
entry是什么

在Webpack的配置中,entry 属性用于定义入口点(或入口点集),指示Webpack从哪个文件开始构建依赖图

依赖图用于确定哪些模块和库是项目中需要被打包的

简单来说,entry 是Webpack开始构建打包过程的起点

entry 的值可以是一个字符串、一个数组,或是一个对象

对于简单的单页面应用(SPA),通常使用字符串形式直接指向一个文件

对于更复杂的设置(例如,多页面应用或需要多个入口点的场景),则可以使用对象形式,以便为每个入口指定一个名称及其对应的起始文件

Vue里面的main.js可以干什么

对于 Vue.js 项目,main.js 通常是最为常见的入口文件

在这个文件中,你会创建 Vue 实例,并指定该实例挂载(mount)到页面的哪个元素上

此外,main.js 也用于执行一些全局性的配置或初始化任务,比如:

  • 导入 Vue 框架本身
  • 导入 App 组件,这是应用的根组件
  • 配置路由(Vue Router)
  • 配置状态管理(Vuex),如果项目中使用了
  • 引入和使用全局样式文件
  • 配置全局插件、混入(mixins)或自定义指令等

这表示Webpack将从 src/main.js 文件开始构建依赖图,并进一步分析该文件内部引用的其他模块和库,以决定哪些资源需要被打包

main.js 中,通常会有如下的几项关键任务:

  1. 创建和挂载根 Vue 实例

    Vue 应用由一个通过 new Vue() 创建的根 Vue 实例,以及通过 .vue 文件定义的可嵌套的组件树构成

    main.js` 文件负责创建这个实例并将其挂载到 DOM 上

    1
    2
    3
    4
    5
    6
    import Vue from 'vue';
    import App from './App.vue';

    new Vue({
    render: h => h(App),
    }).$mount('#app');
  2. 全局配置

    在这个阶段,可能会设置Vue的一些全局配置项,比如关闭生产模式下的提示:

    1
    Vue.config.productionTip = false;
  3. 插件和依赖的引入

    如果你的 Vue 项目中使用了 Vue Router、Vuex 或其他 Vue 插件,这些插件通常会在 main.js 中引入并配置

    这确保了这些插件在 Vue 应用的任何地方都可用


配置输出选项output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module.exports = {
... other code ...
// 配置输出选项
output: {
// 指定输出的文件名,[chunkhash:8]表示使用8位的块哈希值作为文件名的一部分
filename: '[name].[chunkhash:8].js',
// 指定输出文件的路径
path: path.resolve(__dirname, '../dist'),
// 启用异步块加载
asyncChunks: true,
// 设置资源的公共路径,对于在页面中引用的静态资源,都将以此路径为基础
publicPath: '/',
// 清除上一次打包构建出来的文件
clean: true
},
... other code ...
}

在Webpack配置中,output 属性告诉Webpack如何写出它所创建的bundles(打包后的文件),以及在哪里写出它们

这个属性定义了打包过程生成的文件的输出方式和位置

它的配置对于确定你打包后的资源如何分发和使用至关重要


定义模块的规则配置module
1
2
3
4
5
6
7
8
9
10
11
module.exports = {
... other code ...
// 定义模块的规则配置
module: {
rules: [
// 这里是模块规则的数组,用于配置不同类型的文件如何被处理
// 每个规则包括测试表达式(test)、加载器(loader)和选项(options)等
]
},
... other code ...
}

写好之后进行下一步操作,后续随着配置增加,会给这个rules数组添加新东西

module可以干什么

module 属性用于决定如何处理项目中的不同类型的模块

Webpack 本身只能理解 JavaScript,如果你要导入 CSS、图片、字体文件,或者其他Web资源,就需要对这些资源使用不同的加载器(loader)

加载器可以预处理文件,使你能够将任何静态资源当作模块导入

在Webpack中,加载器可以转换文件,或者是作为其他打包或加载过程的中间步骤

你可以使用加载器告诉Webpack如何去给特定的文件赋予正确的加载器


插件配置数组plugins
1
2
3
4
5
6
7
8
9
module.exports = {
... other code ...
// 插件配置数组
plugins: [
// 这里放置项目使用的插件列表
// 插件可以执行各种任务,如自动优化和压缩代码、注入环境变量等
]
... other code ...
}

写好之后进行下一步操作,后续随着配置增加,会给这个数组添加新东西

plugins可以干什么

plugins 属性用于处理Webpack打包构建过程中的各种任务,扩展Webpack的功能

它们会在构建过程的不同阶段执行,能够完成各种各样的任务,比如打包优化、资源管理、注入环境变量等

Webpack插件是一个具有 apply 方法的JavaScript对象

apply 方法会被Webpack compiler调用,并且在整个编译生命周期都可以访问compiler对象


webpack.dev.js开发环境配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* 合并基础的webpack配置文件与开发环境的特定配置。
*
* @module exports
* @param {Object} base - 来自webpack.common.js的基础配置对象。
* @returns {Object} 返回一个合并后的webpack配置对象,专用于开发环境。
*/

const { merge } = require("webpack-merge") // 引入webpack合并配置的工具
const base = require("./webpack.common.js") // 引入基础的webpack配置文件

module.exports = merge(base, {
mode: 'development', // 设置为开发模式
devtool: "source-map", // 启用source-map,便于调试
devServer: {
compress: true, // 启用gzip压缩
port: 3000, // 设置监听的端口号
hot: true, // 启用热更新
open: true, // 自动打开浏览器
historyApiFallback: true, // 使得HTML5 History API可以正常工作
client: {
progress: true, // 显示编译进度
logging: 'error', // 仅输出错误日志
overlay: {
errors: true, // 在浏览器上覆盖错误警告
warnings: true // 在浏览器上覆盖警告
}
},
proxy: {
// 设置对"/apis"开头的请求的代理
"/apis": {
target: "your-target-url", // 目标服务器URL
pathRewrite: {"^/apis": "" }, // 将请求路径中的"/apis"移除
changeOrigin: true, // 设置请求的origin为目标服务器的origin
secure: false // 目标服务器地址是否为https,false表示不是
}
}
}
})

这段代码使用 webpack-merge 工具来合并基础的Webpack配置和开发环境特定的配置,生成一个适用于开发环境的Webpack配置对象

  1. 引入了 “webpack-merge“ 模块的 “merge“ 函数

    webpack-merge 是一个可以简化多个Webpack配置合并的工具

  2. 引入了基础的Webpack配置文件 “webpack.common.js

    这个文件包含适用于开发和生产环境的通用配置

  3. 使用 “module.exports“ 导出了合并后的Webpack配置对象

    我们通过调用 “merge“ 函数并传递基础配置(”base“)及开发特定配置实现配置的合并

    合并的配置包括:

    • mode: 'development':设置Webpack的模式为开发模式。这会启用一些默认的Webpack优化,方便开发者进行调试
    • devtool: "source-map":启用source-map,这有助于调试代码,因为它可以让你看到原始代码而不是转换后的代码
    • devServer:配置了Webpack的开发服务器(webpack-dev-server)的相关选项,提升开发体验
      • compress: true: 启用gzip压缩,加快文件传输速率
      • port: 3000: 开发服务器监听的端口号设为3000
      • hot: true: 启用热替换功能(HMR),无需完全刷新浏览器就可以更新模块
      • open: true: 在开发服务器启动时自动打开浏览器
      • historyApiFallback: true: 当使用HTML5 History API时,任意的404响应都可能需要被替换为index.html
      • client: 配置客户端执行期间的选项,如进度展示和日志级别
        • progress: true: 在客户端(浏览器)显示编译进度
        • logging: 'error': 仅在客户端记录错误日志
        • overlay: 在发生错误或警告时,通过覆盖层在浏览器上直接显示
    • proxy: 配置了一个代理,用于在开发过程中跨域请求API
      • 对于以”/apis”开头的请求,请求会被代理到指定的 “target“ URL
      • pathRewrite 用于重写URL路径,这里把路径中的”/apis”移除
      • changeOrigin: 设置为true来伪装请求的源头,使目标服务器认为请求是从自己的域名发起的
      • secure: false: 如果目标服务器不是HTTPS,这个选项要设置为false


webpack.pros.js生产环境配置文件

1
2
3
4
5
6
7
8
9
10
11
const path = require('path')
const { merge } = require("webpack-merge")
const base = require("./webpack.common.js")


module.exports = merge(base, {
mode: 'production',
plugins: [

]
})


为什么webpack的配置文件要用module.exports

使用 module.exports 来导出 Webpack 的配置文件是因为Webpack配置文件本质上是一个Node.js模块

Node.js中,module.exportsCommonJS 规范的一部分,用于指定一个模块导出的内容,使其可以被其他模块通过 require() 函数导入和使用

Webpack 本身是一个运行在 Node.js 环境中的模块打包工具,它的配置文件 webpack.config.js 就是一个普通的 Node.js 模块

当你运行 webpack 命令时,Webpack 会通过 require() 来加载这个配置文件,然后读取其中用 module.exports 导出的配置对象

这些配置包含了入口文件、输出路径、加载器(loaders)、插件(plugins)和其他配置项

使用 module.exports 的好处之一是它支持更加灵活和复杂的配置逻辑

由于 webpack.config.js 是一个普通的 Node.js 模块,你不仅可以导出一个对象,还可以在模块中使用 JavaScript 代码来生成配置

这意味着你可以根据不同的环境变量来动态地更改配置,或者根据需要编写和组合多个配置对象


修改script启动项目命令

运行这段命令,安装cross-env包,用于设置跨平台环境变量,通常用于设置NODE_ENV等环境变量

1
npm install cross-env --save-dev

然后修改package.json文件的script

1
2
3
4
"scripts": {
"dev": "cross-env NODE_ENV=development webpack serve --config ./webpackConfig/webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config ./webpackConfig/webpack.prod.js"
},
  1. dev脚本

    1
    "dev": "cross-env NODE_ENV=development webpack serve --config config/webpack.dev.js",
    • cross-env

      这是一个跨平台的环境变量设置工具

      确保无论在什么操作系统上(例如Windows,Linux,或macOS),都能以一致的方式设置和使用环境变量

      在这里,它被用来设置NODE_ENV环境变量的值为development

    • NODE_ENV=development

      设置环境变量NODE_ENV的值为development,通常这个设置被用来通知脚本运行在开发环境中

      很多工具和框架,如Webpack和Babel,会根据这个值调整它们的行为,例如启用更适合开发的配置(更详细的错误消息,源代码映射等)

    • webpack serve

      这是启动Webpack的开发服务器webpack-dev-server的命令

      webpack-dev-server`提供一个简单的web服务器和能够实时重新加载(live reloading)的能力

    • —config config/webpack.dev.js:

      这个参数告诉Webpack使用特定的配置文件启动

      在这个例子里,使用的是config/webpack.dev.js文件

      该文件应该包含了开发环境特定的Webpack配置

  2. build脚本

    1
    "build": "cross-env NODE_ENV=production webpack --config ./config/webpack.prod.js"
    • cross-env NODE_ENV=production

      类似于dev脚本,但这里设置的环境变量NODE_ENV的值为production,意味着接下来的操作是为生产环境准备的

      在生产环境中,通常需要代码压缩、优化等操作,以确保应用运行高效、安全

    • webpack

      这是启动Webpack的构建过程的命令

      webpack serve不同,这个命令是用于生成生产环境下使用的打包文件,并不启动一个开发服务器

    • —config ./config/webpack.prod.js

      类似于dev脚本,但这里使用的是针对生产环境优化的Webpack配置文件:webpack.prod.js


3.3-Vue系列

安装Vue3全家桶

1
npm install vue vue-router pinia

这时候会发现package.json文件的dependencies多出来3个npm

image-20240520114428180

这时候我们的Vue3已经安装好了,我们直接创建项目文件去测试打包

新建src文件

这个目录是我们Vue项目的主要存放地方,所有Vue的东西都是包含在这里面的

新建assets

这个目录主要存放我们的资源:图片、字体、css

新建apis

这个目录主要存放我们的接口,分成不同的模块js文件去存放对应的接口

新建utils

这个目录主要存放我们的一些公共函数

新建hooks

这个目录主要存放我们的一些hooks函数

新建components

这个目录主要存放我们的公共组件

新建store

这个目录是要存放公共状态管理,是pinia的使用入口

新建views

这个目录存放项目的Vue主要页面

新建main.js

这个文件是Webpack的项目入口,也是Vue的实例创建文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
* @Description: Vue入口文件
* @Author: 5t5
* @Time: 2024/5/17 17:04
*/
// 创建Vue
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)

// 引入Pinia
import store from './store/store'
app.use(store)

// 引入Router
import router from './router/router'
app.use(router)


app.mount('#app')

到此为止的目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
├─node_modules     
├─src
│ ├─apis // 项目接口
│ ├─assets // css、图片、字体资源
│ │ ├─css
│ │ ├─fonts
│ │ └─images
│ ├─components // 公共组件
│ ├─directive // 自定义指令
│ ├─hooks // hooks函数
│ ├─router // 路由管理
│ ├─store // Pinia状态管理
│ │ └─modules
│ ├─utils // 公共工具函数
│ └─views // 项目页面
│ ├─Home
│ └─Login
└─webpackConfig // webpack公共、开发、生产配置

指定html文件

在项目的根目录下面新建一个index.html文件,内容如下

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Webpack Create Vue3</title>
</head>
<body>
<div id="app"></div>
</body>
</html>

<div id="app"></div>这一段千万不能变,因为上面我们的main.js里面挂载到#app这个节点上面

所以如果这里的id改变的话,main.js里面的也要改变

接着运行这段命令,安装一下html-webpack-plugin

1
npm install html-webpack-plugin --save-dev

这个插件可以帮助我们将打包好的文件都引入到index.html里面,不再需要我们自己手动去引入

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
... other code ...
// 插件配置数组
plugins: [
// 这里放置项目使用的插件列表
// 插件可以执行各种任务,如自动优化和压缩代码、注入环境变量等

new HtmlWebpackPlugin({
template: './index.html',
filename: './index.html',
title: 'Vue3 + webpack -> Web App',
minify: {
collapseWhitespace: true, // 去掉空格
removeComments: true // 去掉注释
}
}),
]
... other code ...
}
html-webpack-plugin可以干什么

html-webpack-plugin 是一个用于处理 HTML 文件的 Webpack 插件,它非常的实用并且在 Webpack 项目中被广泛使用

它的主要功能包括:

  1. 生成一个新的 HTML 文件

    一旦插件被加入到 webpack 配置中,运行 webpack 打包后会在 output 指定的目录下生成一个新的 HTML 文件

  2. 自动引入打包生成的 JavaScriptCSS 文件

    生成的 HTML 文件会自动包含 webpack 打包生成的所有 JavaScriptCSS 文件的引用。插件会自动添加 scriptlink 标签

  3. 可以使用模板

    你可以自定义一个 HTML 文件作为模板

    插件会以此模板为基础来生成最终的 HTML 文件

    模板文件可以包含一些特殊的占位符,插件在生成 HTML 文件时会自动对这些占位符进行替换

    例如,你可以在模板的 title 标签中使用 <%= htmlWebpackPlugin.options.title %>,这样就可以在 webpack 配置中通过 html-webpack-pluginoptions 自定义你的 title

这个插件非常适合用来生成单页应用程序(SPA)的 HTML 文件

因为在这种应用程序中,通常只需要一个包含所有 JavaScriptCSS 引用的 HTML 文件

另外,你也可以在多页面应用程序(MPA)使用此插件,每个页面实例化一个插件的实例

它与 webpack-dev-serverhot module replacement 功能 (HMR) 无缝集成,使开发过程更为流畅

让webpack可以识别Vue

webpack是一个智能识别js文件的打包器,想要识别vue,就需要vue相关的加载器

1
npm install vue-loader @vue/compiler-sfc --save-dev

vue-loader@vue/compiler-sfc 是 Vue.js 单文件组件(Single File Components, SFC)的处理工具

它们在将 .vue 文件转换为 JavaScript 模块的过程中起到了核心作用

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Vue-loader配置
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [
// 这里是模块规则的数组,用于配置不同类型的文件如何被处理
// 每个规则包括测试表达式(test)、加载器(loader)和选项(options)等
{
// 匹配.vue文件
test: /\.vue$/,
// 使用vue-loader处理
loader: 'vue-loader'
},
]
},
// 插件配置数组
plugins: [
// 这里放置项目使用的插件列表
// 插件可以执行各种任务,如自动优化和压缩代码、注入环境变量等

// VueLoaderPlugin是一个Vue.js的加载器插件,它自动处理Vue组件的加载
new VueLoaderPlugin(),

]

... other code ...
}
@vue/compiler-sfc可以干什么
  • @vue/compiler-sfc 是 Vue 3 的一个官方库,主要用于编译 Vue 3 的单文件组件
  • 它包含 Vue 3 的 SFC 编译逻辑,并负责将组件模板编译为渲染函数
  • 使用这个库可以解析 .vue 文件的 <template><script><style> 以及其他自定义块,并编译模板成为渲染函数
  • @vue/compiler-sfc 通常和 vue-loader 一同工作,在 webpack 构建流程中协同工作,进行源码到最终 JavaScript 代码的转换
vue-loader可以干什么
  • vue-loader

    一个 webpack 的 loader,它允许你以一种名为单文件组件(SFCs)的格式编写 Vue 组件

    SFCs 通常保存在扩展名为 .vue 的文件中

  • .vue 文件是一个自定义的文件类型,它允许开发者将一个组件的模板、脚本和样式封装在单个文件中

  • 在构建过程中,vue-loader 会解析文件,抽取每个语言块(template、script、style 等),并需要相应的 loader 来处理它们,例如 vue-template-compiler 用于模板编译、css-loader 用于处理 CSS、babel-loader 用于处理 JavaScript 等


测试运行

控制台输入npm run dev

这时候编辑器会自动在打包好以后给你在浏览器打开端口3000的地址

image-20240520161359316


控制台警告

打开控制台会发现

[!WARNING]

Feature flags VUE_OPTIONS_API, VUE_PROD_DEVTOOLS, VUE_PROD_HYDRATION_MISMATCH_DETAILS are not explicitly defined. You are running the esm-bundler build of Vue, which expects these compile-time feature flags to be globally injected via the bundler config in order to get better tree-shaking in the production bundle.

这是因为你正在使用 Vue 的 ESM Bundler 构建,但没有在你的构建配置中显式地定义这些 Vue 的特性标志(Feature flag)

这些特性标志在 Vue 3 中用于启用或禁用 Vue 的一些特性

  • __VUE_OPTIONS_API__

    是否启用 Options API,如果你仅使用 Composition API,可以将其设置为 false,以减小最终的构建大小

  • __VUE_PROD_DEVTOOLS__

    是否在生产环境中启用 Vue Devtools,如果不需要,可以设置为 false 来优化应用性能

  • __VUE_PROD_HYDRATION_MISMATCH_DETAILS__

    对于服务器端渲染 (SSR) 的应用,是否应在生产环境中公开 hydration 不匹配细节,为了避免关键的信息泄露,可以设置为 false

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
const webpack = require('webpack')

module.exports = {
// ...
plugins: [
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false,
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
}),
]
}


3.4-样式系列

在前端工程化里面,常用的预编译的css就是lessscsssass,这里我们选用less来作为项目的预编译器

1
npm install css-loader style-loader less-loader less --save-dev

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Vue-loader配置
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [
// 这里是模块规则的数组,用于配置不同类型的文件如何被处理
// 每个规则包括测试表达式(test)、加载器(loader)和选项(options)等

{
// 匹配.css文件
test: /\.css$/,
use: [
// 将CSS样式插入到DOM中
"style-loader",
// 处理CSS文件,支持模块化、压缩等
"css-loader"
]
},

{
// 匹配.less文件
test: /\.less$/,
use: [
// 将CSS样式插入到DOM中
"style-loader",
// 处理CSS文件,支持模块化、压缩等
"css-loader",
// 编译LESS到CSS
"less-loader"
]
}

]
},

... other code ...
}
为什么样式的use需要这么写
  1. 处理顺序

    webpack 使用 loaders 时遵循从右到左(或从下到上)的处理顺序

    也就是说,在 .less 文件的处理链中,less-loader 首先工作,将 LESS 代码编译成 CSS

    然后 css-loader 处理得到的 CSS 代码,支持模块化等特性

    最后 style-loader 将最终的 CSS 代码插入到 DOM

    对于 .css 文件,由于不需要编译,所以不用 less-loader

  2. 功能划分

    每个 loader 都有自己的责任范围。style-loader 负责样式的加载到 DOMcss-loader 负责处理 CSS 文件中的依赖(如@importurl()等),less-loader 负责将 LESS 编译成 CSS

    这样的设计使得 webpack 配置更加灵活和模块化

css预编译是什么

CSS 预编译器是一种用于扩展 CSS 语言的工具,它允许开发者使用更动态、更丰富的语法来书写样式,然后再将这些代码编译成标准的 CSS 文件,以便浏览器可以解析

CSS 预编译器添加了许多编程特性,比如变量、嵌套规则、混入(Mixins)、函数等,这些特性使得编写 CSS 更加高效和可维护

  • Sass(SCSS)

    提供了很多高级功能,如变量,嵌套和混合等

    Sass 的语法是符合 CSS3 标准的,因此它看起来就像是增强了的 CSS 代码

  • LESS

    与 Sass 类似,也提供了变量,嵌套,混合以及其他高级功能,主要差异在于语法和一些功能的实现

  • Stylus

    提供了强大的功能和极其灵活的语法,与其他预处理器相比,它有着更加丰富的选择和高度的自定义

使用 CSS 预处理器的好处包括:

  1. 更轻松地维护大型样式表:通过嵌套规则,可以更清晰地表示元素之间的层级关系
  2. 代码的复用:使用混合(mixins),可以将一组属性从一个规则集引入到另一个规则集
  3. 更快的开发速度:可以定义具有有参数的混合,以及使用循环构建复杂的样式网络
  4. 更丰富的表现力:使用函数和条件语句可以更灵活地控制样式
  5. 代码组织:允许分割 CSS 到多个文件中,可以有助于组织和管理样式代码

这些预处理器通常需要使用特定的构建工具(如 webpackGulp)来编译为浏览器可解析的标准 CSS 文件

在现代 web 开发流程中,这些工具通常会集成在自动化构建系统中,以优化开发流程


四、优化项目

4.1-Javascript代码兼容

运行命令安装npm

1
npm install --save-dev babel-loader @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/plugin-proposal-class-properties

通过合并这些工具,你可以编写使用最新JavaScript语法(ES6/ES7及以上)的代码,然后将其转译为更广泛兼容的JavaScript版本(通常是ES5),以确保你的应用或网站可以在旧版浏览器和环境中运行

这对于前端项目来说是非常重要的,因为这意味着开发者可以利用最新的语言特性来编写更简洁、更易于维护的代码,同时又不牺牲兼容性

项目目录下新建.babelrc的配置文件并写入

1
2
3
4
{
"presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties"]
}

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [

{
test: /\.js$/,
use: [
'babel-loader'
],
exclude: /node_modules/,
},

]
}

... other code ...
}
babel-loader干什么的

这是一个Webpack的loader,用于在Webpack构建过程中调用Babel转译器

它允许Webpack处理JavaScript代码,将其通过Babel转换成浏览器兼容的版本

@babel/plugin-transform-runtime干什么的

这个插件优化了Babel转译过程中的辅助代码

使用这个插件后,可以减少编译后代码的冗余(比如,避免多个文件重复包含同一辅助函数),并能够使用@babel/runtime包来重复使用Babel转译的辅助代码

@babel/plugin-proposal-class-properties干什么的

这个Babel插件使你能在JavaScript类中使用静态属性和实例属性的声明语法

此特性曾是草案提案的一部分,在未来版本的JavaScript正式标准中得到支持之前,这个插件可以让你在当前的JavaScript代码中使用这些特性

@babel/core干什么的

Babel的核心功能包含在这个包中

它提供了Babel转译器的核心API,用于转译JavaScript代码

没有它,Babel的其他插件或预设都无法运行

@babel/preset-env干什么的

一个Babel预设(preset)是一系列插件的集合,旨在支持特定的语言特性

@babel/preset-env是一个智能预设,它能够根据你的目标环境(如特定版本的浏览器或Node.js)自动确定需要转译的JavaScript特性

它可以让你使用最新的JavaScript,而不用担心兼容性问题

@babel/preset-env根据browserslist配置,只包含所需的Babel插件和polyfills来转译新的JavaScript语法,从而为你的目标环境量身定制输出


4.2-Css代码兼容

运行命令安装npm

1
npm install postcss-loader postcss-flexbugs-fixes postcss-preset-env postcss-normalize autoprefixer postcss-nested --save-dev

user-select是一个很特殊的属性, 因为针对不同的浏览器要对它做不同的适配

这个写法兼容了这个属性

项目目录下创建.browserslistrc文件添加下面代码

用于指明想要支持的浏览器版本

1
2
3
last 1 version
> 1%
IE 10

项目目录下创建postcss.config.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const flexbugsFixes = require('postcss-flexbugs-fixes')
const presetEnv = require('postcss-preset-env')
const normalize = require('postcss-normalize')
const nested = require('postcss-nested')

// 导出一个配置对象,用于PostCSS的处理
module.exports = {
// 标识这个配置是为PostCSS准备的
ident: 'postcss',
// 使用的插件列表
plugins: [
flexbugsFixes,
presetEnv({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
normalize(),
nested
],
sourceMap: true
}

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [

{
// 匹配.css文件的规则配置
test: /\.css$/,
use: [
// 根据开发环境选择使用style-loader或将CSS提取到单独的文件中
IsDev ? "style-loader" : MiniCssExtractPlugin.loader,
// 对CSS文件进行处理,支持模块化、压缩等操作
"css-loader",
"postcss-loader"
]
},

{
// 匹配.less文件的规则配置
test: /\.less$/,
use: [
// 同上,根据开发环境选择合适的CSS加载器
IsDev ? "style-loader" : MiniCssExtractPlugin.loader,
// 处理CSS文件,支持模块化、压缩等
"css-loader",
"postcss-loader",
// 将LESS编译为CSS
"less-loader"
]
}

]
}

... other code ...
}
postcss-loader可以干什么

用于在Webpack中集成PostCSS

它允许你使用PostCSS来处理CSS文件,通常与其他PostCSS插件配合使用

postcss-flexbugs-fixes可以干什么

一个PostCSS插件,用于尝试修复一些常见的flexbox的bug

postcss-preset-env可以干什么

这个插件包含了一组现代的CSS特性,使开发者可以使用未来CSS标准的语法,并且会根据浏览器的兼容情况自动做出适当的转换

postcss-normalize可以干什么

根据browserslist配置和CSS规则自动引入适当的normalize.css内容,以确保不同浏览器之间的一致性

autoprefixer可以干什么

一个自动添加浏览器前缀的PostCSS插件,使开发者编写的CSS规则兼容多种浏览器

postcss-nested可以干什么

允许你在写CSS时使用嵌套语法,类似于Sass和Less之类的预处理器提供的功能


4.3-压缩Javascript代码

在开发环境中,通常更关注的是构建速度和增量构建的效率,以便快速预览和测试更改

因此,开发环境下一般不会开启压缩这样的耗时步骤

相对的,生产环境打包时的目标是减少应用的加载时间和网络传输成本,所以会使用terser-webpack-plugin这样的压缩工具来移除JavaScript代码中的所有多余空格、注释、未使用的代码等,以实现代码的最小化

1
npm install terser-webpack-plugin --save-dev

修改webpack.prod.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 压缩代码
const TerserPlugin = require('terser-webpack-plugin')


module.exports = merge(base, {
... other code ...

optimization: {
minimize: true, // 开启代码压缩
minimizer: [
new TerserPlugin({ // 使用TerserPlugin作为压缩工具
terserOptions: {
mangle: { // 代码混淆相关选项
safari10: true, // 处理Safari 10/11的bug,避免在这些老版本Safari浏览器中出现的“删除”bug(删除let和const变量会抛出错误)
},
compress: { // 代码压缩相关选项
// 下面的选项都是用来指定terser在压缩过程中是否应用某些转换
arrows: false, // 不转换箭头函数为ES5函数表达式
collapse_vars: false, // 不折叠具有单一使用的变量
comparisons: false, // 不进行优化比较操作
computed_props: false, // 不优化计算属性
hoist_funs: false, // 不提升函数声明
hoist_props: false, // 不提升对象属性
hoist_vars: false, // 变量提升关闭 (var 声明会被提升至函数作用域的顶部)
inline: false, // 不内联函数
loops: false, // 不优化循环
negate_iife: false, // 不否定立即执行的函数表达式
properties: false, // 不优化属性访问
reduce_funcs: false, // 不内联仅用一次的函数
reduce_vars: false, // 不减少非常量变量的引用
switches: false, // 不移除switch的分支
toplevel: false, // 不删除顶级函数和变量定义
typeofs: false, // 不进行typeofs优化

// 以下选项开启了一些常见的压缩优化策略
booleans: true, // 优化布尔表达式
if_return: true, // 优化if-return和if-continue
sequences: true, // 使用逗号运算符合并多个语句到一个表达式
unused: true, // 删除未使用的变量/function
conditionals: true, // 优化if-s和条件表达式
dead_code: true, // 移除不可到达的代码
evaluate: true, // 计算常量表达式
warnings: false, // 关闭Terser的警告信息,使构建输出更干净
drop_console: true, // 删除所有的console语句,可以减少最终输出的文件大小,对于生产环境是推荐的
pure_funcs: ['console.log'], // 移除代码中的console.log调用
// 与drop_console相似,但是提供了更细致的控制,可以指定只删除某些特定的console方法
}
},
parallel: true, // 并行压缩以提升构建速度
extractComments: false, // 不把注释提取到一个单独的文件中,即去掉所有注释
})
]
}

... other code ...
})
TerserPlugin解析
  1. optimization配置

    • minimize

      设置为true,表示启用代码压缩

      这是生产环境构建时常用的设置,旨在减小最终生成文件的大小,以提高加载速度和执行效率

    • minimizer

      这是一个数组,允许为压缩过程指定一个或多个压缩插件

      在此配置中,使用了TerserPlugin作为压缩工具

  2. TerserPlugin配置

    • parallel

      设置为true,启用并行压缩

      这意味着将同时使用多个子进程来进行代码压缩,可以显著加快构建速度

    • extractComments

      设置为false,表示不将注释抽取到单独的文件中,即去除代码中的所有注释

      这有助于进一步减小文件体积

  3. terserOptions配置

    • mangle配置

      • safari10

        设置为true可避免在Safari 10/11上发生的一个已知问题,即在这些早期版本的Safari浏览器中,错误地删除letconst声明可能会导致脚本错误

    • compress配置

      • arrows、collapse_vars、comparisons、computed_props、hoist_funs、hoist_props、hoist_vars、inline、loops、negate_iife、properties、reduce_funcs、reduce_vars、switches、toplevel、typeofs

        这些选项被设置为false,意味着在压缩过程中不应用这些特定的代码转换

        这些设置保证了代码转换的精细控制,避免可能导致代码运行出现问题的激进优化策略

      • booleans、if_return、sequences、unused、conditionals、dead_code、evaluate

        这些选项被设置为true,允许Terser应用这些常见的压缩优化策略,如优化布尔表达式、if-返回模式、无用代码的剔除等,以达到减少代码体积和提高执行效率的目的

      • warnings

        设置为false以在压缩过程中不显示警告信息,使构建输出更干净

      • drop_console

        设置为true以删除所有的console语句

        这有助于在生产环境中减少文件大小,提升运行性能

      • pure_funcs

        设置为['console.log'],指示Terser删除所有console.log调用

        这是一种比drop_console更细粒度的控制方式,允许保留如console.errorconsole.warn等可能对调试有用的console调用

terser-webpack-plugin是干什么的

terser-webpack-plugin是一个用于Webpack的插件

它的主要作用是在Webpack构建过程中压缩和优化JavaScript代码

这个插件使用Terser作为其压缩引擎,Terser是一个专为ES6+代码设计的JavaScript解析器和压缩器

通过去除代码中的所有不必要的字符(例如空格和注释)以及执行代码转换优化(如缩短变量名和删除未使用的代码),它能够减小JavaScript文件的大小,从而加快页面加载速度和提高应用程序的性能

terser-webpack-plugin插件的主要特性包括:

  1. 删除未使用的代码(Dead code elimination)

    删除那些已经写在代码中但实际上从未被执行或使用的部分

  2. 压缩代码

    通过各种转换(如变量名缩短和优化逻辑表达式)来减少代码体积

  3. 删除调试语句

    例如,可以配置插件来删除所有console.log语句

  4. 支持ES6+语法

    能够压缩和优化ES6+语法的代码

  5. 多线程压缩

    支持并行压缩,可以利用多核CPU加速代码的压缩过程

  6. 自定义压缩选项

    用户可以通过自定义terserOptions来控制具体的压缩行为

  7. 条件性注释的提取

    可以配置插件提取和保留特定的注释(例如版权声明)

在使用Webpack进行现代JavaScript应用程序的构建过程中,压缩和优化代码是一个重要步骤

terser-webpack-plugin提供了一个高效且灵活的方式来实现这一步骤,它可以帮助开发者缩短构建时间和减小最终生成文件的大小,改善用户体验


4.4-压缩Css代码

运行以下代码安装对应的npm

1
npm install css-minimizer-webpack-plugin mini-css-extract-plugin -D

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Css提取分离
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

// 是否开发环境
const IsDev = process.env.NODE_ENV === 'development'

module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [

{
// 匹配.css文件的规则配置
test: /\.css$/,
use: [
// 根据开发环境选择使用style-loader或将CSS提取到单独的文件中
IsDev ? "style-loader" : MiniCssExtractPlugin.loader,
// 对CSS文件进行处理,支持模块化、压缩等操作
"css-loader"
]
},

{
// 匹配.less文件的规则配置
test: /\.less$/,
use: [
// 同上,根据开发环境选择合适的CSS加载器
IsDev ? "style-loader" : MiniCssExtractPlugin.loader,
// 处理CSS文件,支持模块化、压缩等
"css-loader",
// 将LESS编译为CSS
"less-loader"
]
},

]
},
// 插件配置数组
plugins: [

new MiniCssExtractPlugin({
filename:'[name]_[chunkhash:8].css'
})

],

... other code ...
}

修改webpack.prod.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 压缩Css代码
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')

module.exports = merge(base, {
... other code ...

optimization: {
minimize: true, // 开启代码压缩
minimizer: [
// 使用css-minimizer-webpack-plugin插件实例进行CSS优化
new CssMinimizerWebpackPlugin({
// 启用并行处理,提高构建性能,特别是在有大量CSS文件需要被压缩的情况下
parallel: true,

// minimizerOptions用于传递选项到cssnano,它是css-minimizer-webpack-plugin背后的CSS压缩工具
minimizerOptions: {
// 'default'预设意味着使用cssnano的默认压缩选项,
// 这是一个适用于大多数场景的平衡配置,它既压缩了代码,也考虑了性能和兼容性
preset: 'default'
},
}),
]
}

... other code ...
})
css-minimizer-webpack-plugin是干什么的

mini-css-extract-plugin是一个用于将CSS从JavaScript文件中提取到独立的CSS文件中的插件

这对于那些想要将CSS代码分离出来,以便单独缓存和加载的项目非常实用

它的主要特点包括:

  • 分离CSS

    允许你将CSS从JavaScript中提取成单独的文件

    这意味着CSS可以独立于JavaScript被浏览器加载和缓存,也就是说可以无需执行JavaScript就预先加载CSS

  • 异步加载

    支持加载非关键CSS,并异步加载次要的CSS文件,从而提升页面的渲染速度

  • 缓存优化

    由于CSS文件是独立的,这有助于客户端更高效地缓存它们,只有在文件发生变动时才需要重新下载

mini-css-extract-plugin是干什么的

css-minimizer-webpack-plugin 是一个用于压缩和优化CSS资源的插件

它利用了各种CSS压缩器,如cssnano,以最小化CSS文件的大小

这对于生产环境特别有用,因为它可以减少CSS资源的加载时间,从而提高网页加载速度并提升用户体验

它的主要特点包括:

  • 压缩CSS文件

    它可以减少CSS文件的大小,通过移除空格、注释、不必要的后缀等

  • 支持Source Maps

    它可以生成Source Maps,帮助开发人员在开发工具中跟踪CSS源代码

  • 使用PostCSS

    它通常使用PostCSS生态中的工具进行CSS处理


4.5-自动引入Element Plus组件

项目使用的UI框架以Element Plus为例子,需要运行以下命令安装

1
npm install element-plus @element-plus/icons-vue --save

并且安装对应的自动导入的webpack插件

1
npm install -D unplugin-vue-components unplugin-auto-import unplugin-icons

这3个npm包截止目前2024年5月20日为止,最新的版本都是有问题的,运行的时候webpack会报错,类似

1
2
3
TypeError: IconsResolver is not a function
TypeError: Components is not a function
TypeError: AutoImport is not a function

所以为了解决这个问题,回退一下版本就可以了

1
2
3
4
5
"devDependencies": {
"unplugin-auto-import": "^0.16.1",
"unplugin-icons": "^0.14.1",
"unplugin-vue-components": "^0.25.0",
}

最后修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Element Plus
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
const IconsResolver = require('unplugin-icons/resolver')
const Icons = require('unplugin-icons/webpack')

module.exports = {
... other code ...

// 插件配置数组
plugins: [

/**
* 配置自动导入组件的功能
* 使用ElementPlusResolver以便自动解析并导入Element Plus组件库中的组件。
* 这样做旨在避免手动导入组件,从而提高开发效率。
*/
AutoImport({
resolvers: [
ElementPlusResolver()
]
}),
/**
* 注册组件的配置
* 通过使用ElementPlusResolver,自动注册Element Plus组件库中的所有组件。
* 使得这些组件在应用中可以直接使用,简化了组件注册流程。
*/
Components({
resolvers: [
ElementPlusResolver(),
IconsResolver({
// 修改Icon组件前缀,不设置则默认为i,禁用则设置为false
prefix: 'icon',
// 仅启用名为'ep'的图标集合
enabledCollections: ['ep'],
})
]
}),

// 配置图标插件,自动安装所需的图标库
Icons({
autoInstall: true // 自动安装图标库
}),

]

... other code ...
}


4.6-运行进度展示

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const webpack = require("webpack")

module.exports = {
... other code ...

// 插件配置数组
plugins: [

new webpack.ProgressPlugin(), // 运行进度

]

... other code ...
}

这样子可以帮助我们清晰的知道webpack的打包进度

image-20240520173808174


4.7-Css的Tree-Shaking

运行下面的命令安装npm

1
npm install purgecss-webpack-plugin glob -D

purgecss-webpack-pluginglob是两个Node.js的包

它们通常在使用Webpack进行前端项目构建时用于优化CSS

修改webpack.prod.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Css Tree-Shaking优化
const glob = require('glob')
const { PurgeCSSPlugin } = require('purgecss-webpack-plugin')

module.exports = {
... other code ...

// 插件配置数组
plugins: [

new PurgeCSSPlugin({
// paths是一个配置项,该项接受一个文件路径数组。
// 这些路径指向你的项目中的HTML文件或者模板,以及可能包含CSS类的JavaScript组件文件。
paths: glob.sync([
// path.join(__dirname, './public/index.html')生成了指向项目中的index.html文件的绝对路径。
// __dirname是Node.js中的一个全局变量,它返回当前正在执行的脚本所在的目录。
path.join(__dirname, '../index.html'),

// path.join(__dirname, './src/**/*')生成了一个glob模式,这个模式匹配src目录及其所有子目录下的所有文件。
// './src/**/*' 是一个使用glob语法的模式字符串,表示src目录下的任意深度的所有文件。
// ** 是一个glob星号,匹配任意数量的目录和子目录。
// * 是一个glob星号,匹配任意数量的字符,除了路径分隔符(如/)。
path.join(__dirname, '../src/**/*'),
],
// nodir选项设置为true,意味着返回的匹配结果中不包含目录路径,只有文件路径。
// 这确保PurgeCSSPlugin只会接收到文件路径,而不是目录路径,因为插件需要文件内容来确定哪些CSS类是被使用的。
{nodir: true}),
})

]

... other code ...
}
purgecss-webpack-plugin是干什么的

purgecss-webpack-plugin是Webpack的一个插件,用于从你的最终CSS文件中删除未使用的样式,从而减小CSS文件的大小,加快加载速度

在构建过程中,特别是在生产环境中,移除那些在HTML文件或者JSX/模板组件中没有用到的CSS规则可以显著减少文件大小,从而提高性能

使用purgecss-webpack-plugin通常涉及在webpack配置中引入并配置该插件,指定它应该检查的文件路径(例如HTML模板、JS/JSX文件等),以便于分析哪些CSS类被实际使用了。

glob是干什么的

glob是一个小而强大的Node.js库,提供了一种根据所提供的模式匹配对文件进行搜索的方式,模式匹配通常被称作 “globbing”

glob的功能不仅限于Node.js脚本中使用,它也经常与其他工具和插件一起用于前端项目中,比如与purgecss-webpack-plugin一起使用来指定需要分析的文件集合

在与purgecss-webpack-plugin一起使用时,glob可以帮助定义要清除未使用CSS的文件路径的模式(比如:”src/*/.html”表示项目src目录下的所有HTML文件),这使得purgecss-webpack-plugin能够有效地识别和移除所有未使用的CSS样式


4.8-删除上一次打包残留的dist文件

运行下面的命令安装npm

1
npm install clean-webpack-plugin -D

修改webpack.prod.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 清除上次打包的残留
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
... other code ...

// 插件配置数组
plugins: [

new CleanWebpackPlugin({
// cleanStaleWebpackAssets: 当值为true时,插件将会在构建完成后,
// 清理Webpack在上一次构建时生成,但这一次构建未再次生成的文件资产(assets)。
// 这是一个用于控制是否应该清理在重新构建时不再使用的旧文件的布尔值。
// 默认情况下,这个值是true——每次只有新产生的文件会被保留,
// 所有的旧文件会在下一次构建完成之后被删除。
cleanStaleWebpackAssets: true,

// cleanOnceBeforeBuildPatterns: 这个选项允许你定义一个模式数组(patterns array),
// 插件会在Webpack构建前根据这些模式清理文件和目录。
// 不同的模式可以匹配不同的文件或目录,以供清理。
// 在此例中,它使用glob模式,以确保Webpack在构建之前清理指定目录。
// path.resolve(__dirname, "../dist") 用于生成“dist”目录的绝对路径。
// 通常 "__dirname" 是Node.js中的一个全局变量,
// 它返回代表当前执行脚本所在的目录的路径。
// 通过 ".." 返回到上一级目录,再与 "dist" 连接起来形成清理路径,
// 确保不管在哪个工作目录下执行Webpack,指定的“dist”文件夹路径都是正确的。
cleanOnceBeforeBuildPatterns: [ path.resolve(__dirname, "../dist") ]
}),

]

... other code ...
}
clean-webpack-plugin可以干什么

CleanWebpackPlugin是一个在每次构建前自动清理/删除Webpack的output.path目录中的所有文件的插件

这个插件确保你的输出目录只包含用当前配置和源代码生成的文件,从而避免了构建残留文件的积累

使用CleanWebpackPlugin的主要好处包括:

  1. 保持输出目录的清洁

    在新的构建过程中自动删除过时的文件,保证你的发布目录始终只包含最新的输出资源

  2. 减少手动干预

    自动处理文件删除,减少了需要手动清理输出目录的情况,特别是在频繁构建的开发过程中

  3. 避免潜在的构建错误

    有时候,旧的文件和新生成的文件冲突会引发意外的问题

    通过清除旧文件,可以减少这种问题的发生

  4. 简化部署过程

    确保你部署的只是新生成的文件,而不是一堆已经过时的资源


4.9-图片资源处理

webpack5不需要安装额外的loader来处理,直接写就可以

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [

{
// 处理图像文件的规则配置
test: /\.(png|jpe?g|gif|webp|avif)(\?.*)?$/, // 匹配多种图像文件格式
type: "asset", // 将图像文件作为资产处理
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 图片大小小于10KB将会被转成base64
},
},
generator: {
filename: "static/images/[hash:8][ext]", // 输出文件的命名规则,在images目录下,使用8位哈希值加原始扩展名
}
}

]
}

... other code ...
}


4.10-压缩图片

运行命令安装npm

1
npm install image-minimizer-webpack-plugin imagemin imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [

{
// 处理图像文件的规则配置
test: /\.(png|jpe?g|gif|webp|avif)(\?.*)?$/, // 匹配多种图像文件格式
type: "asset", // 将图像文件作为资产处理
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 图片大小小于10KB将会被转成base64
},
},
generator: {
filename: "images/[hash:8][ext]", // 输出文件的命名规则,在images目录下,使用8位哈希值加原始扩展名
}
}

]
}

... other code ...
}

图片压缩是一个计算密集型的过程,尤其是当你有大量图片需要处理时

这可能是导致你的打包过程变慢的原因

有一些方法可以尝试优化这一过程:

  1. 仅在生产构建中启用图片压缩

    你可以通过设置只在生产模式下启用这个插件来减少开发时的构建延迟

  2. 并行处理

    如果可能的话,试着并行化图片的处理过程

    ImageMinimizerPlugin有一个parallel选项,可以显著加快处理速度,特别是在多核CPU上

  3. 限制压缩的图片数量

    如果你的项目中有些图片不需要优化,可以配置规则来排除这些文件,从而减少处理时间

  4. 预先压缩

    对于一些不经常变化的图片,可以考虑在添加到项目之前就手动压缩它们,避免在每次构建过程中重复压缩

image-minimizer-webpack-plugin是干什么的

这是一个Webpack插件,它允许你通过多种imagemin插件来优化构建过程中的图片

它的主要角色是作为图片压缩任务的协调者,调用不同的imagemin插件来处理不同格式的图片

imagemin是干什么的

这是一个用于优化图片的模块

它本身不对图片进行优化,而是依赖于一系列插件来处理特定格式的图片

imagemin-gifsicle是干什么的

用于优化GIF格式图片

它可以减少GIF文件的大小,而不会影响到动画效果或质量

imagemin-jpegtran是干什么的

用于优化JPEG/JPG格式图片

它主要进行无损压缩,意味着图片质量不会降低

imagemin-optipng是干什么的

用于优化PNG格式图片

它可以进行无损压缩,也可以通过调整优化级别来达到更高的压缩率,但可能会影响图片质量

imagemin-svgo是干什么的

针对SVG格式图片的优化工具

SVGO可以去除SVG文件中的不必要的信息,比如编辑器元数据、注释、隐藏的元素等,从而减小文件大小


4.11-公共代码提取

一些概念了解:

  • module

    简单来说就是你通过import语句引入的代码,一个js文件就是一个module

  • chunk

    chunk是webpack根据功能拆分出来的,包含三种情况:

    • 你的项目入口(entry)
    • 通过import()动态引入的代码
    • 通过splitChunks拆分出来的代码(公共代码)
      chunk包含着module,可能是一对多也可能是一对一。
  • bundle

    bundle是webpack打包之后的各个文件,一般就是和chunk是一对一的关系

    bundle就是对chunk进行编译压缩打包等处理之后的产出

    • 通过splitChunks拆分出来的chunk不能算作bundle
    • bundle只指入口entry和import()动态导入生成的chunk (这样的bundle和chunk才是一对一的关系)
      • 一个entry对应一个chunk
      • 一个import()动态导入对应一个chunk

修改webpack.prod.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
module.exports = {
... other code ...

// 定义模块的规则配置
optimization: {
// splitChunks 用于控制如何拆分代码块
splitChunks: {
chunks: "all", // 对所有类型的chunks进行拆分(包括动态和非动态模块)
minSize: 20000, // 新chunk的最小体积为20KB
maxAsyncRequests: 6, // 每个异步加载的模块最多能被拆分成6个chunks
maxInitialRequests: 6, // 入口点的最大并行请求数量
enforceSizeThreshold: 50000, // 忽视其他限制,强制拆分体积为50KB的chunks
// cacheGroups 用于定义如何共享模块/合并chunks
cacheGroups: {
libs: { // 针对从node_modules中导入的模块
name: "chunk-libs",
test: /[\\/]node_modules[\\/]/, // 指定是node_modules下的模块
priority: 10, // 优先级
chunks: "initial" // 仅对入口块进行处理
},
echarts: { // 针对ECharts的单独拆分
name: "chunk-echarts",
test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 20 // 优先级高于libs
},
elementPlus: { // Element Plus 单独拆包
name: "chunk-elementPlus",
test: /[\\/]node_modules[\\/]element-plus[\\/]/, // 更新匹配 Element Plus 的路径
priority: 20 // 权重要大于 libs
},
src: { // 对src目录下的文件进行拆分
name: "chunk-src",
test: /[\\/]src[\\/]/,
chunks: 'all',
priority: 10 // 优先级等于libs,但因为特定配置可能在实际中优先级表现不同
},
commons: { // 针对公共模块的拆分
name: `chunk-commons`,
minChunks: 2, // 最小引用次数
priority: 0, // 低优先级
reuseExistingChunk: true // 如果一个模块已经被打包过,则复用它而不是再次打包
}
}
}
}

... other code ...
}
splitChunks是干什么的

splitChunks 是一个 Webpack 的配置选项,用于优化输出包的大小和加载性能

它的主要目的是从你的代码中自动提取和分割出通用的依赖模块、第三方库或者自定义的重复代码块到独立的文件(chunks)中

这样做的好处有很多:

  1. 减少重复

    通过将公共的代码分割成独立的chunks,多个入口或懒加载的模块可以共享相同的依赖,避免在每个bundle中重复打包相同的代码

  2. 缓存优化

    分割出来的公共代码块通常变化较少,因此通过浏览器缓存可以减少加载时间

  3. 并行加载

    将大的代码块拆分成更小的块可以并行加载,提高加载速度

  4. 按需加载

    对于路由懒加载的场景,splitChunks可以帮助实现更细粒度的代码分割,按需加载资源,进一步减少首屏加载时间

Webpack中的splitChunks配置提供了多种细粒度的控制选项,包括但不限于:

  • chunks

    指定哪些类型的块应该被拆分

    可以是initial(只对入口文件处理)、async(只对异步加载的模块处理)和all(全部块)

  • minSize

    生成块的最小大小。如果拆分后的块小于此值,则不会被拆分

  • maxAsyncRequests

    按需加载时并行请求的最大数量

  • maxInitialRequests

    入口点的最大并行请求数量

  • name

    拆分块的名称。可以是固定的字符串或者函数返回值

  • cacheGroups

    缓存组可以继承和/或覆盖splitChunks中的任何选项

    通过cacheGroups,可以实现更细粒度的拆分策略,比如将React和Vue等框架代码拆分到独立的文件


4.12-分割代码按需加载

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
... other code ...

// 配置输出选项
output: {
// 指定输出的文件名,[chunkhash:8]表示使用8位的块哈希值作为文件名的一部分
filename: '[name].[chunkhash:8].js',
// 指定输出文件的路径
path: path.resolve(__dirname, '../dist'),
// 启用异步块加载
asyncChunks: true,
// 设置资源的公共路径,对于在页面中引用的静态资源,都将以此路径为基础
publicPath: '/',
// 清除上一次打包构建出来的文件
clean: true,
// 用于指定非入口(non-initial) chunk 文件的名称,这通常是用于懒加载模块时Webpack按需加载的块
chunkFilename: '[name].js'
}

... other code ...
}

chunkFilename 用于指定非入口(non-initial) chunk 文件的名称,这通常是用于懒加载模块时Webpack按需加载的块

这意味着,这些异步加载的块将以它们各自的 chunk 名称命名,不包含哈希值

在实际应用中,它有助于区分主bundle文件和异步加载的chunk文件


4.13-查看编译速度

运行命令安装npm包

1
npm install speed-measure-webpack-plugin -D

新建一个webpack.analysis.js文件

这个文件不会输出dist文件,只是进行webpack的分析

执行编译速度分析一般都是针对需要极致性能的生产环境,所以开发环境就不配置分析了

修改webpack.analysis.js文件

1
2
3
4
5
6
7
8
9
10
11
const { merge } = require("webpack-merge")
const prodConfig = require("./webpack.prod.js")
// 构建速度分析
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin")
const smp = new SpeedMeasurePlugin()

module.exports = smp.wrap(
merge(prodConfig, {

})
)
speed-measure-webpack-plugin可以干什么

speed-measure-webpack-plugin(简称 SMP)是一个用于测量各个插件和加载器(loaders)在Webpack构建过程中的速度的webpack插件

它对于优化构建时间非常有用,因为它可以帮助你明确地看到构建过程中每一步的耗时,从而识别出哪些部分可能需要优化

  • 性能监测

    它会显示Webpack构建过程中每个插件和loader的处理时间,帮助你理解构建时间被怎样花费的

  • 优化指导

    通过准确的性能数据,你可以优先对耗时最长的部分进行优化,以提高构建速度

  • 配置简单

    集成到现有的Webpack配置中非常简单,只需要几行代码即可启动和运行


4.14-多进程

运行命令安装npm包

1
npm install thread-loader -D
thread-loader可以干什么

thread-loader 是一个Webpack的加载器,它可以将资源文件的加载和处理工作分配到一个独立的worker线程池中去执行

这样做可以显著提高构建速度,特别是在处理大量和耗时的任务时(如大型项目中的Babel转译),因为这允许你利用多核CPU的能力来并行处理任务

  • 并行处理

    在多个worker线程中并行处理模块,使得资源文件的转译和加载更加快速

  • 提高构建效率

    通过减少主线程的负载,使得Webpack的构建过程更加高效

  • 可配置的

    你可以控制线程的数量,优化构建性能和资源的使用

修改webpack.common.js文件

thread-loader放在其他比较耗时的加载器之前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [

{
test: /\.js$/,
use: [
'thread-loader', // 在这里添加`thread-loader`
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
],
exclude: /node_modules/,
},

]
}

... other code ...
}


4.15-精简终端输出

如果觉得控制台的输出很多,很乱,你可以进行精简

修改webpack.dev.js文件

1
2
3
4
5
module.exports = {
// ...
stats: 'errors-only'
// ...
};


4.16-字体资源处理

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
module.exports = {
... other code ...

// 定义模块的规则配置
module: {
rules: [

{
test:/.(woff2?|eot|ttf|otf)$/, // 匹配字体图标文件
type: "asset", // type选择asset
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 小于10kb转base64位
}
},
generator:{
filename:'static/fonts/[hash:8][ext]', // 文件输出目录和命名
},
}

]
}

... other code ...
}


4.18-打包生成gz

运行命令安装npm包

1
npm install compression-webpack-plugin -D

修改webpack.prod.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 生成压缩gzip
const CompressionPlugin = require('compression-webpack-plugin')

module.exports = {
... other code ...

// 插件配置数组
plugins: [

new CompressionPlugin({
filename: '[path][base].gz', // 文件命名
algorithm: 'gzip', // 压缩格式,默认是gzip
test: /.(js|css)$/, // 只生成css,js压缩文件
threshold: 10240, // 只有大小大于该值的资源会被处理。默认值是 10k
minRatio: 0.8 // 压缩率,默认值是 0.8
})

]

... other code ...
}


4.19-打包分析

运行命令安装npm包

1
npm install webpack-bundle-analyzer -D

修改webpack.analysis.js文件

1
2
3
4
5
6
7
8
// 引入分析打包结果插件
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

module.exports = smp.wrap(merge(prodConfig, {
plugins: [
new BundleAnalyzerPlugin() // 配置分析打包结果插件
]
}))


4.20-开启缓存

开启持久化缓存(Webpack5 新特性),缓存生成的 webpack 模块和 chunk,来改善构建速度

首次构建耗时增加 15% 左右,但是二次构建耗时减少 90% 左右

修改webpack.dev.js文件

1
2
3
4
5
module.exports = merge(base, {
cache: {
type: 'filesystem'
}
})


4.21-编译过程美化

运行命令安装npm包

1
npm install @nuxt/friendly-errors-webpack-plugin --save-dev

这个插件可以帮助我们优化构建过程的webpack在终端的输出,可以直接体验

修改webpack.dev.js文件

1
2
3
4
5
6
7
8
// 编译过程终端美化
const FriendlyErrorsWebpackPlugin = require('@nuxt/friendly-errors-webpack-plugin')

module.exports = merge(base, {
plugins: [
new FriendlyErrorsWebpackPlugin()
]
})


4.22-进度条美化

运行命令安装npm包

1
npm i -D webpackbar

觉得webpack提供的默认进度条不是很好看,可以下载这个包

并替换掉new webpack.ProgressPlugin()

修改webpack.common.js文件

1
2
3
4
5
6
7
8
9
10
module.exports = merge(base, {
plugins: [
// 进度条插件:用于显示webpack构建的进度
new WebpackBar({
color: "#85d", // 默认green,进度条颜色支持HEX
basic: false, // 默认true,启用一个简单的日志报告器
profile:false, // 默认false,启用探查器。
}),
]
})


4.23-Eslint配置代码规范

运行命令安装npm包

为什么安装8.57.0的版本呢?因为9的版本实在是太难用了,跟以前的配置完全不一样

1
npm install eslint@8.57.0 eslint-plugin-vue --save-dev

ESLint 是一款非常流行的JavaScript和JSX代码检测工具

主要原因在于它可以帮助开发者保持代码质量并确保代码风格的一致性

以下是使用ESLint的一些主要理由:

  1. 提高代码质量

    ESLint可以检测代码中的错误,比如未使用的变量、循环中错误的逻辑判断、语法错误等,这些都是在代码审查中可能漏检的错误

    通过自动检测,可以在代码提交前发现并修正它们,从而避免了潜在的运行时错误

  2. 保持代码风格一致性

    在团队开发过程中,不同的开发者可能有不同的代码编写习惯,这可能会导致项目中出现不一致的代码风格

    ESLint 通过强制执行一套预定的规则(如缩进、分号使用、变量命名规范等),帮助团队成员保持代码的一致性,使得代码更易于读写和维护

  3. 促进团队协作

    当团队成员使用ESLint,并遵循相同的代码规范时,会减少代码审查时的摩擦和误解

    这不仅可以提高开发效率,也能促进团队间的沟通和协作

  4. 自定义和灵活性

    ESLint提供了大量的内建规则,并且允许开发者自定义规则,这意味着你可以根据自己或团队的需求调整规则

    此外,你还可以使用社区提供的配置集合,如airbnbgoogle等,或者集成到现有的构建系统中

  5. 减少审查时间和成本

    自动检测代码中的问题可以显著减少人工代码审查所需的时间和精力

    开发者可以集中精力解决更复杂的问题,而非一些基础的编码规范问题

  6. 促进学习和指导

    对于新手开发者来说,ESLint不仅可以指出代码中的错误,还可以提供错误修正的建议,这对于学习JavaScript语言和提升编码技能非常有帮助

项目目录下新建.eslintignore文件,用于排除应用eslint规则的文件或目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 忽略 node_modules 目录
node_modules/

# 忽略构建输出目录
/dist/

# 忽略配置目录
webpackConfig/

# 忽略特定文件
.babelrc
.browserslistrc
.gitignore
package.json
package-lock.json
#src/someFileToIgnore.js

# 忽略某个目录中的所有文件
src/assets
#src/someDirectoryToIgnore/

# 忽略所有的配置文件
**/*.config.js

项目目录下新建.eslintrc.js,具体代码可以直接看源码,如果想要个性化规则可以去翻阅Eslint文档

如果想在终端里面测试所有项目的话,可以在package.json里面的script配置"eslint": "eslint ./src"

这样子就可以直接运行检查项目src目录下面的所有文件了

如果想要在运行webpack的时候发现,可以下载npm包

1
npm i eslint-webpack-plugin -D

因为是开发环境才会有eslint规范,所以直接修改webpack.dev.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 终端检查代码
const ESLintPlugin = require('eslint-webpack-plugin')

module.exports = merge(base, {

plugins: [
new ESLintPlugin({
//运行的时候自动帮你修复错误
fix: true,
exclude: 'node_modules',
extensions: ['js', 'vue']
})
]
})

eslint可以干什么

ESLint是一个插件化的JavaScript代码检查工具

它可以识别和报告模式中的问题,并且能被配置为在代码中自动修复某些简单的问题

其主要用途是提高代码质量和保持代码风格的一致性

eslint-plugin-vue可以干什么

ESLint的一个插件,提供了针对Vue.js模板的特定规则

这允许ESLint检查.vue文件中<template>部分的代码

eslint-webpack-plugin可以干什么

eslint-webpack-plugin 是一个 Webpack 插件,用于在 Webpack 构建过程中运行 ESLint 检查

这意味着你可以在编译代码时自动进行代码质量检查,而不需要单独运行 ESLint 命令


4.24-配置husky

运行命令安装npm包

1
npm i husky lint-staged -D

修改package.json文件,在script下面添加

1
2
3
4
5
6
7
8
9
"scripts": {
"prepare": "husky install",
"pre-check": "npx lint-staged"
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix"
]
},

生成.husky目录

1
npx husky install

在该目录下新建文件pre-commit,并写入

1
2
3
4
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm run pre-check

这时候运行代码提交操作的时候就会使用eslint检测你的代码规范了

husky可以干什么

用于在 Git 钩子(hooks)上运行脚本,常用于在提交代码前进行代码检查、测试等任务

lint-staged可以干什么

在 Git 暂存文件(staged files)上运行 linters,确保只有通过检查的代码才能被提交


4.25-commit信息规范化

运行命令安装npm包

1
npm i @commitlint/config-conventional @commitlint/cli -D

在项目目录下创建commitlint.config.js文件, 并写入代码,具体代码看源代码

在该目录下新建文件commit-msg,并写入

1
2
3
4
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit "$1"

这时候运行代码提交操作的时候就会使用commitlint.config.js检测你提交的信息规范了

@commitlint/cli可以干什么

命令行工具,用于检查提交消息是否符合指定的规则

@commitlint/config-conventional可以干什么

提供一组符合 “Conventional Commits” 规范的默认提交消息规则配置


4.26-commit提交辅助备注信息

运行命令安装npm包

1
npm i -D commitizen cz-conventional-changelog

项目目录下新建.czrc文件,下入以下代码

1
{"path":"cz-conventional-changelog"}

修改package.json文件

1
2
3
4
5
6
7
8
"scripts":{
"commit": "git-cz"
},
"config":{
"commitizen":{
"path":"node_modules/cz-conventional-changelog"
}
}

这时候可以在git add .命令之后使用npm run commit就可以帮助我们规范commit的提交

如果你还想要自定义commit的规范,那么我们可以这么操作

1
npm i -D commitlint-config-cz cz-customizable

在根目录下面新建.cz-config.js,写入代码看源代码

这时候我们就可以发现我们.cz-config.js里面配置的都会在命令行里

commitizen可以干什么

用于帮助开发者编写符合规范的提交消息

它提供了一个交互式的命令行界面,引导用户填写提交信息,从而确保提交消息符合预定的格式和规则

cz-conventional-changelog可以干什么

commitizen 的一个适配器,使用 “Conventional Commits” 规范来格式化提交消息

它定义了一组标准的提交类型(如 featfixchore 等),帮助生成一致的提交历史记录

commitlint-config-cz可以干什么

commitlint 的一个配置扩展,旨在与 commitizencz-conventional-changelog 兼容

它提供了一组预定义的提交消息规则,确保提交消息符合 “Conventional Commits” 规范

cz-customizable可以干什么

commitizen 的一个可定制适配器,允许用户根据自己的需求自定义提交消息的提示和格式

你可以配置提交类型、范围、详细描述等,从而适应不同的项目需求


五、推送远程

5.1-添加.gitignore 文件

.gitignore 文件用于指定 Git 版本控制要忽略的未跟踪文件和目录

在一个 Vue.js 项目中,有多种文件和目录通常应该被添加到 .gitignore 文件中,特别是当开发工具是 WebStorm (ws)Visual Studio Code (vs)

.gitignore 文件应该根据项目需求和团队约定进行自定义

正式使用时还需要根据实际情况来调整和增减规则

写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 依赖
/node_modules

# 打包输出
/dist

# 环境变量文件
.env
.env.local
.env.*.local

# 开发工具目录
.idea
.vscode

# 日志文件
*.log

# 源映射
*.map

# MacOS系统文件
.DS_Store

# Windows系统文件
Thumbs.db
ehthumbs.db
Desktop.ini

六、文档、源代码

掘金大佬文档

配置 | webpack 中文文档 (docschina.org)