前言
一直以来都在使用基于各种脚手架创建的项目进行开发,很多webpack的配置这些脚手架都已经帮我们封装好了。一般情况下,脚手架提供的能力已经足够我们使用了,有些不适用的地方看看文档改一下配置也能满足。最近一直挺好奇脚手架这个“黑盒”内部的webpack配置是怎么做的,于是就想自己搭一套相关的配置,学习一下。
文章不会过多介绍webpack相关的各种配置原理,只是简单记录整个过程,希望能对大家有所帮助。
话不多说,我们开始吧。
正式开始
在开始之前请确保我们已经安装了node和npm。推荐使用
nvm
来安装和管理node版本,本次我使用的node版本是14.20.0
一、初始化空项目
新建一个空白文件夹,然后执行yarn
的初始化命令。
mkdir vue3
cd vue3
yarn init -y
执行完我们就得到了一个只有package.json
文件的空项目。
二、安装webpack
依赖
接下来我们就要安装webpack相关的依赖了。在终端执行
yarn add webpack webpack-cli -D
安装的时候发现速度非常慢,我们可以在项目下新增一个.npmrc
文件,指定下npm镜像源
安装好以后,
package.json
文件的devDependencies
下就会有我们刚刚安装好的依赖和对应的版本号
三、增加webpack
配置文件,完善基本配置
在项目根目录下新建一个webpack.config.js
文件,写一点基本的配置。
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[contenthash:8].js',
}
}
在根目录下新建src
文件夹,新建一个index.js
文件,写点基本的代码
console.log('hello world');
在package.json
文件增加scripts
字段,配置build
命令
{
"name": "vue3",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
}
}
在终端执行yarn build
,然后就能看到生成的打包好的文件啦
这个时候我们发现生成的文件里面有很多注释之类的代码,文件体积很大,我们需要修改webpack配置的
mode
为production
。
这个mode
我们在开发的时候希望是development
,在打包的时候是production
,我们可以在scripts
里指定,这样就不需要每次手动修改了
修改package.json
文件
"scripts": {
"build": "NODE_ENV=production webpack"
}
然后,修改webpack.config.js
文件
// ...
module.exports = {
mode: process.env.NODE_ENV,
// ...
}
再次执行yarn build
,这个时候生成的代码就很干净了
四、使用clean-webpack-plugin
,清理旧的打包文件
上一步最后,我们发现dist
目录下有两个main.xxx.js
文件,这是因为我们打包了两次,所以生成了两个。我们希望每次打包都自动删掉上次生成的文件,不要有额外的文件干扰我们。
要实现这个功能,我们只需要安装一个webpack的插件即可。
在终端下执行yarn add clean-webpack-plugin -D
,然后在webpack.config.js
文件里引入这个插件
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
// ...
plugins: [
new CleanWebpackPlugin(),
],
}
再次执行yarn build
,这个时候我们发现dist
目录下就只有刚刚打包好的这个文件了。
五、增加index.html
入口文件
经过上面的步骤,我们已经可以打包基本的js文件了。接下来,我们需要新增一个index.html文件,让它引入我们的js文件,在浏览器里显示我们需要的内容。
在项目根目录下新增一个template
目录,新增一个html文件。
安装
html-webpack-plugin
插件,它能帮助我们自动引入打包生成好的js、css等文件到html文件中。
在终端执行yarn add html-webpack-plugin -D
,然后在webpack.config.js
文件里引入它
// ...
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
plugins: [
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
template: './template/index.html',
}),
],
}
再次执行yarn build
,我们发现dist
目录下多了个index.html
文件,在浏览器打开它,发现控制台输出了hello world
注意:这里的
在浏览器打开html文件
需要以web server
的方式打开,而不是以file
的方式打开。以file
的方式打开,使用的是文件协议,在浏览器里的url是以file
开头的
如果是以web server
的方式打开,浏览器里的url应该是以http(s)
开头的。
六、使用webpack-dev-server
进行本地调试
上面提到我们需要以http server
的方式打开我们的html文件,为了更好的本地开发体验,我们可以使用webpack-dev-server
来进行本地的开发调试。
打开终端,执行yarn add webpack-dev-server -D
,安装所需依赖。
修改package.json
文件,增加dev
命令
"scripts": {
"dev": "NODE_ENV=development webpack serve",
"build": "NODE_ENV=production webpack"
}
我们可以修改下webpack-dev-server
的配置,让它自动帮我们打开浏览器,并且增加source map
的配置,提升本地开发体验。打开webpack.config.js
文件,配置devtool
和devServer
// ...
module.exports = {
// ...
devtool: 'eval-source-map',
devServer: {
open: true,
}
}
执行yarn dev
,在浏览器里自动打开了http://localhost:8080
这个页面,打开控制台,我们发现他输出了hello world
,这就是我们在index.js
里写的代码
七、使用vue
来编写前端代码
经过上面的几步,我们的项目已经有了一个基本的雏形了,可以本地开发,也可以打包。接下来我们就要使用vue
来编写前端代码,实现各种炫酷的界面和功能了。
打开终端,依次执行yarn add vue
,yarn add vue-loader -D
在src
目录下新建一个app.vue
文件,写一点基础的代码
<template>
<div>hello vue</div>
</template>
<script>
export default {
name: "app"
}
</script>
<style scoped>
</style>
在index.js
里引入vue
来渲染这个组件。(别忘了在index.html
里加上id
为root
的元素)
import { createApp } from 'vue';
import App from './app';
const app = createApp(App);
app.mount('#root');
然后,我们需要在webpack.config.js
里增加module.rules
来支持解析vue
文件
// ...
module.exports = {
// ...
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
}
],
},
}
执行yarn dev
,我们发现页面报错了
根据报错信息,我们发现是
webpack
没找到app.vue
这个文件,这是因为我们没写文件的后缀,而webpack默认只会以.js .json .wasm
这三个后缀来找,所以找不到app.vue
这个文件。
要解决这个问题,我们需要修改下
resolve.extensions
的配置
打开webpack.config.js
文件,新增resolve
相关的配置
// ...
module.exports = {
// ...
resolve: {
extensions: ['...', '.vue'],
},
}
再次执行yarn dev
,还是报错
这里报了两个错误,我们先看第二个错误,他的意思很明显,我们需要在
webpack.config.js
里引入VueLoaderPlugin
,我们在vue-loader
的官方文档查找VueLoaderPlugin
这个关键词,可以找到相关的说明。因为我们的vue-loader
版本高于14
,所以我们要手动引入这个插件
按照官方文档的说明进行配置,修改完配置后,我们重新执行
yarn dev
,发现项目启动成功了。页面上显示出了hello vue
,但是浏览器的控制台报了一个warning
(第一个warning是我安装的浏览器插件导致的,可以忽略)
点进去这个链接,我们发现需要通过
webpack
的DefinePlugin
来注入这两个变量
修改
webpack.config.js
,增加DefinePlugin
配置
// ...
const { DefinePlugin } = require('webpack');
module.exports = {
// ...
plugins: [
// ...
new DefinePlugin({
__VUE_OPTIONS_API__: 'true',
__VUE_PROD_DEVTOOLS__: 'false',
}),
],
}
再次yarn dev
启动项目,warning就消失啦
八、编写样式美化界面
前端的世界必然离不开css,我们的项目已经可以使用vue
来编写界面了,接下来就要用css
来美化它们了,让我们编写css的配置来实现一个五彩斑斓的黑的效果吧。
安装相关loader
,在终端执行yarn add css-loader style-loader -D
;修改webpack.config.js
的module.rules
// ...
module.exports = {
// ...
module: {
rules: [
{
test: /.vue$/,
loader: 'vue-loader',
},
{
test: /.css$/,
use: [
'style-loader',
'css-loader',
],
},
],
},
}
在app.vue
里随便写点样式
<template>
<div class="container">hello vue</div>
</template>
<script>
export default {
name: "app"
}
</script>
<style scoped>
.container {
color: #38f;
font-size: 24px;
}
</style>
重新yarn dev
,页面上就有了样式效果了。
一般情况下,我们都会用
sass
或者less
这样的语言来写样式,这里以sass
为例
执行yarn add sass sass-loader -D
安装相应的依赖,再改下webpack.config.js
配置
module.rules
// ...
module.exports = {
// ...
module: {
rules: [
{
test: /.vue$/,
loader: 'vue-loader',
},
{
test: /.s?css$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
],
},
],
},
}
我们把app.vue
的style
标签的lang
属性设置成scss
<style lang="scss" scoped>
.container {
color: #38f;
font-size: 24px;
}
</style>
重新yarn dev
,页面显示正常,完美!
九、使用mini-css-extract-plugin
抽离css代码
上一步我们成功完成了css
相关的配置,我们使用了style-loader
来帮助我们引入我们编写的样式,它会把我们的css
代码以style
标签的方式插入到index.html
文件的head
里
当我们的代码越来越多的时候,所有的
css
代码全部在index.html
里会让这个文件非常大,很臃肿。这个时候我们可以用mini-css-extract-plugin
来帮我们把这些css
代码抽离成单独的文件。
打开终端,执行yarn add mini-css-extract-plugin -D
,修改webpack.config.js
,用MiniCssExtractPlugin.loader
替换掉style-loader
// ...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /.s?css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css'
}),
],
}
再次执行yarn dev
,打开浏览器控制台,这个时候我们的css
代码就是通过单独的css
文件来引入的了
十、引入ant-design-vue
组件库
一般我们都会引入一些业界成熟的组件库,具体使用哪一个就凭大家的喜好,这里我们来引入ant-design-vue
,具体的引入方式大家参考官方文档,这里就不再赘述了。
十一、使用webpack asset module
处理静态资源
除了代码以外,我们的项目里还会需要引入各种静态资源,例如图片、字体等,接下来我们就编写对应的配置来处理这类资源。
在webpack v4
版本我们通常需要借助file-loader
、url-loader
来实现,而webpack v5
已经内置了这些能力,不再需要借助第三方的loader
了,具体可以查看官方文档
修改webpack.config.js
// ...
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /.jpe?g|png|gif|webp$/,
type: 'asset',
generator: {
filename: 'assets/image/[hash:8][ext]'
}
},
{
test: /\.eot|woff|woff2|ttf|svg|otf$/,
type: 'asset',
generator: {
filename: 'assets/font/[hash:8][ext]',
}
},
]
},
};
十二、编写splitChunks
配置,合理拆分代码
经过上面的步骤,我们的项目已经具备基本的开发、调试、打包能力了,但是还有一点小小的问题可以优化一下。
打开浏览器的控制台,切换到network
,我们可以发现,现在生成的产物只有一个js
文件和一个css
文件,而且这个js
文件的体积非常大,这是因为我们项目里引用的依赖例如vue
、ant-design-vue
的代码也在这个文件里。
一般而言,我们引用的第三方依赖的版本都是不会经常变化的,而我们如果把第三方依赖和我们的业务代码生成到一个文件里,那么每次业务代码改变,生成的
hash
就变了,浏览器会重新加载整个文件,对这些第三方依赖而言,其实是被重复加载了。
所以,为了不重复加载这些依赖,提高网页性能,常见的做法是把它们单独拆出来,生成单独的文件,这样就能利用浏览器缓存的能力
为了实现上面的功能,我们只需修改webpack
的splitChunks
的配置即可
// ...
module.exports = {
// ...
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\/]node_modules[\/]/,
// filename: 'chunks/vendor.js',
reuseExistingChunk: true,
name: (module) => {
const regExp = /[\/]node_modules[\/](.*?)[\/]/g;
if (/javascript/ig.test(module.type)) {
const packageName = module.context.match(/[\/]node_modules[\/](.*?)([\/]|$)/)[1];
return `npm.${packageName.replace('@', '')}`;
}
const identifier = module.identifier();
const packageName = identifier.match(regExp).pop().replace(/node_modules|[\/]/ig, '');
return `npm.${packageName.replace('@', '')}`;
}
}
}
}
}
}
上面代码的大致意思就是对于node_modules
下面的模块,我们会拿到它的包名,然后加上npm.
的前缀,例如ant-design-vue
,最后的名字就是npm.ant-design-vue.[contenthash:8].js
这样的格式。通过这样的方式,我们就能把它们分离出来。想要进一步了解splitChunks
的内容,大家可以参考官方文档
再次执行yarn dev
,打开浏览器控制台的network
部分,看看我们配置的效果吧
结尾
以上就是本文的全部内容了,其实还有很多可以完善的地方,例如eslint
、unit test
、commitlint
、mock
等,本次就先讲到这里,预知后事如何,请听下回分解~
喜欢的话,就点赞收藏吧~
大家觉得有不对的地方也欢迎在评论区留言~