赞
踩
本次项目属于练手项目,使用的是 vue-cli 新建的新手引导页面,项目本身没有特别复杂的逻辑,而且这里也不涉及到 Vue 的学习,只是会通过逐步分解完成使用 webpack 对项目完成最终的打包。
本次会使用到的 插件(plugins) 和 加载器(loaders) 有:
webpack & webpack-cli
vue-loader & vue-template-compiler
style-loader & less & less-loader
这个根据具体的项目需求可以修改,这里使用了 LESS,所以需要额外搭配 less & less-loader
只用 css 的可以只使用 style-loader
file-loader & url-loader
这里也存在二选一的关系,url-loader 起到的是优化的作用,它的 fallback 是 file-loader,所以使用 url-loader 必须安装 file-loader
反之只用 file-loader 可以不用安装 url-loader
htmlWebpackPlugin
解决了 HTML 文件,也就是入口文件的迁徙和模板问题
clean-webpack-plugin
自动清除之前编译好的文件
copy-webpack-plugin
满足了迁徙其他静态文件的需求
结构如下,需要编译的文件有 vue, less 和 JavaScript,需要压缩的文件有打包后的 JavaScript 和 HTML 文件。
注*:这个项目是一个使用 vue-cli 创建的初始项目,只不过移除了脚手架中自动打包的部分。
这一部分主要是实现一些基础功能,这个项目已经是一个初始化好了的 node 项目,否则需要使用 init
命令去进行初始化。
D:\\vue-app-base>npm i webpack webpack-cli -D
i
是 install 的缩写,-D
是 --save-dev
的缩写,这样就将 webpack 和 webpack-cli 以开发依赖安装好了。
查看 package.json
文件,就会发现 devDependiencies 已经更新:
- {
- "devDependencies": {
- "webpack": "^5.41.0",
- "webpack-cli": "^4.7.2"
- }
- }
这时候可以新添一条脚本命令让 npm 去运行 webpack:
- {
- "script": {
- "build": "webpack"
- }
- }
这个时候尝试在命令行运行 npm run build
会得出大量的报错结果,但是这可以证明命令可以正常被运行。
- D:\\vue-app-base>npm run build
-
- > vue-app-base@0.1.0 build D:\\vue-app-base
- > webpack
-
- assets by status 0 bytes [cached] 1 asset
-
- WARNING in configuration
- The 'mode' option has not been set, webpack will fallback to 'production' for this value.
- Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
- You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
-
- ERROR in main
- Module not found: Error: Can't resolve './src' in 'D:\\vue-app-base
- # 省去大量报错信息
- webpack 5.41.0 compiled with 1 error and 1 warning in 163 ms
最后在根目录下新建 webpack.config.js
作为 webpack 的入口,并且套入模板,对打包模式、入口和出口文件进行配置。
webpack 的配置文件可以导出一个对象,通过导出对象的属性就可以完成相应的配置选项。
- // npm原有的模块
- const path = require('path');
-
- module.exports = {
- // 入口文件
- entry: './src/main.js',
- // 导出的部分
- output: {
- // 导出的文件名
- filename: 'bundle.js',
- // 导出的文件名会放置的路径
- path: path.resolve(__dirname, 'dist/'),
- },
- };
这个时候再去运行 npm run build
,会得出下面的结果:
- D:\\vue-app-base>npm run build
-
- > vue-app-base@0.1.0 build D:\\vue-app-base
- > webpack
-
- assets by status 4.16 KiB [cached] 1 asset
- runtime modules 718 bytes 3 modules
- cacheable modules 770 bytes
- ./src/main.js 169 bytes [built] [code generated]
- ./src/App.vue 537 bytes [built] [code generated] [1 error]
- ./src/style.less 64 bytes [built] [code generated] [1 error]
- # 省略掉一堆报错信息
- webpack 5.41.0 compiled with 4 errors and 1 warning in 216 ms
这次调出了 4 个 errors 和 1 个 warning,这是件好事儿,至少把所有的报错消息一个个的列了出来,这样也有可以开始 debug 的点了。最怕的不是报错信息多,而是报错信息没有头绪,不知道从哪开始。
webpack 给出了项目中的几个问题,分别是:
这个是说 mode 没有设置,会默认以生产环境进行开发
ERROR in ./src/App.vue 1:0
这个提示就很明显了,webpack 说:
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
需要一个 Vue 的 loader 去解决问题
这个问题应该也是一样的,具体报错信息如下:
Module not found: Error: Can't resolve 'vue' in 'D:\\vue-app-base\src'
这个问题是属于 output 文件的问题了,先解决上面打包的问题,再看看这个问题会不会出现
这个问题很好解决,现在这个阶段,暂时会修改 scripts 中的命令行参数,去设置成 development 这个开发模式:
- {
- "scripts": {
- "build": "webpack --mode=development"
- }
- }
同样再运行 npm run build
,就发现,报错信息居然少了一个:
webpack 5.41.0 compiled with 3 errors in 103 ms
最后一个 ERROR in bundle.js from Terser 居然消失了。那也就是说,现在剩下的 3 个报错都是开发时的报错,那就可以着手准备开放的 loader 和 plugin 的实现了。
另外,这个时候虽然还报错,但是 dist 目录已经能够显示出来了,证明 webpack 至少运行过一遍,并且导出了打包文件——这次可以确认 webpack 的安装和基础配置都没有问题了:
vue loader 是 webpack 的插件,这里的配置也都是跟着官方文档实现的。
1、安装
vue-loader
和vue-template-compiler
- npm install -D vue-loader vue-template-compiler
- # 突然意识到 cannot find Vue 的错误是因为我没有下载 package.json 里面列举的 Vue
- # 于是重新做一次下载,将需要的依赖包下载好
- npm install
2、按照官方文档的内容,重新编写
webpack.config.js
的内容
- // 新增内容
- const { VueLoaderPlugin } = require('vue-loader');
-
- module.exports = {
- // 新增内容
- module: {
- rules: [{ test: /\.vue$/, loader: 'vue-loader' }],
- },
- plugins: [new VueLoaderPlugin()],
- };
3、继续跟着官方文档,下载和安装所需要的依赖以及重新编写
webpack.config.js
- # babel 负责解析 JavaScript
- npm install -D babel-loader @babel/core
- # 其他两个负责解析CSS
- npm install -D vue-style-loader css-loader
- # 这也是必须的插件,否则会报错
- # 官方文档里没有列出来,如果你那里出现不同的报错,一定要看报错信息
- npm i -D @vue/cli-plugin-babel
- // 新增内容
- const { VueLoaderPlugin } = require('vue-loader');
-
- module.exports = {
- // module里面的东西为新增内容
- module: {
- rules: [
- // 解析Vue文件
- { test: /\.vue$/, loader: 'vue-loader' },
- // 它会应用到普通的 `.js` 文件
- // 以及 `.vue` 文件中的 `<script>` 块
- {
- test: /\.js$/,
- loader: 'babel-loader',
- },
- // 它会应用到普通的 `.css` 文件
- // 以及 `.vue` 文件中的 `<style>` 块
- {
- test: /\.css$/,
- use: ['vue-style-loader', 'css-loader'],
- },
- ],
- },
- plugins: [
- // 请确保引入这个插件!
- new VueLoaderPlugin(),
- ],
- };
4、运行
npm run build
,这时候就只剩下两个报错信息了,一个是 png 打包报错(缺少图片处理),一个是 less 打包报错(缺少 less)
CSS 加载的内容是 webpack 官方提供的:less-loader,所以这里也会跟着步骤一步一步解决报错信息
1、下载必须的依赖包
- # 这是 style-loader,是下面配置需要用到的
- npm install style-loader --save-dev
- # 这是 less 相关的内容
- npm install less less-loader --save-dev
2、修改配置文件
注*:这里官方文档用的是 loader,但是不知道为什么使用 loader 会报错,遂改为了 use。如果你用 use 会报错,那就试试看 loader。webpack 的版本变化可能会让使用变得非常困难……
- module.exports = {
- module: {
- rules: [
- // 其他地方不变
- // 对 less 文件进行处理
- {
- test: /\.less$/i,
- use: [
- // compiles Less to CSS
- 'style-loader',
- 'css-loader',
- 'less-loader',
- ],
- },
- ],
- },
- };
3、运行 npm run build
进行检查
这次只剩下一个 png 的问题了
1、下载对应的 loader,这里用的是 file-loader
D:\\vue-app-base>npm i -D file-loader
2、修改配置文件
- module.exports = {
- output: {
- filename: 'bundle.js',
- path: path.resolve(__dirname, 'dist'),
- // 新增内容,修改路径,将其改为相对路径而不使用绝对路径
- publicPath: './',
- },
- module: {
- rules: [
- // 省略其他的配置
- // 针对 png 图片进行处理
- {
- test: /\.png$/i,
- // 如果像上面一样直接使用 use: "file-loader"
- // 会出现图片资源为 "[object Module]" 的问题
- // 这是因为新版的 file-loader 自动开启了 ES模块
- // 手动关闭即可正确显示
- use: {
- loader: 'file-loader',
- options: {
- esModule: false,
- },
- },
- },
- ],
- },
- };
注*:这里的 file-loader 有一些特殊的属性,为了能够正确的显示图片,一定要将 esModule 设置为 false
这是由于 file-loader 版本的不同造成的,低版本环境下默认 esModule 是关闭的,所以可以正确显示。但是我现在使用的版本是 6.2,默认就是开启 esModule 的。当 esModule 开启的时候,图片引入的路径是 "[object Module]",而不是 src="./26bd867dd65e26dbc77d1e151ffd36e0.png"。
3、尝试打包
终于没有任何错误信息了,看起来是已经打包成功。
- D:\\vue-app-base>npm run build
-
- > vue-app-base@0.1.0 build D:\\vue-app-base
- > webpack --mode=development
-
- asset bundle.js 566 KiB [emitted] (name: main)
- asset 26bd867dd65e26dbc77d1e151ffd36e0.png 6.69 KiB [emitted] [immutable] [from: src/assets/logo.png] (auxiliary name: main)runtime modules 2.04 KiB 6 modules
- modules by path ./node_modules/core-js/ 147 KiB
- modules by path ./node_modules/core-js/internals/*.js 85.2 KiB 114 modules
- modules by path ./node_modules/core-js/modules/*.js 62 KiB 36 modules
- modules by path ./src/ 16.1 KiB 20 modules
- modules by path ./node_modules/style-loader/dist/runtime/*.js 4.12 KiB 4 modules
- modules by path ./node_modules/vue-style-loader/lib/*.js 6.74 KiB
- ./node_modules/vue-style-loader/lib/addStylesClient.js 6.09 KiB [built] [code generated]
- ./node_modules/vue-style-loader/lib/listToStyles.js 671 bytes [built] [code generated]
- ./node_modules/vue/dist/vue.runtime.esm.js 222 KiB [built] [code generated]
- ./node_modules/vue-loader/lib/runtime/componentNormalizer.js 2.71 KiB [built] [code generated]
- ./node_modules/@babel/runtime/helpers/esm/typeof.js 726 bytes [built] [code generated]
- ./node_modules/css-loader/dist/runtime/api.js 1.75 KiB [built] [code generated]
- webpack 5.41.0 compiled successfully in 3548 ms
并且也能看到打包的目录下出现了新的图片:
注*:如果图片比较小的情况下,可以使用 url-loader,这样可以减少 http 请求的数量。
随后,手动复制黏贴和修改了一下 index.html,看一下渲染结果:
所有的内容都可以正常显示,可以开始静态资源的处理了。
1、下载对应的 loader,这里用的是 file-loader
D:\\vue-app-base>npm install url-loader --save-dev
2、修改配置文件
不过说起来,vue 的 logo 正好卡在 8kb 这个尺寸,所以这大概是有什么约定俗成的规矩的?
注意,这里要将 file-loader 修改为 url-loader,而不能叠加使用 url-loader 和 file-loader 两个,原因是因为 url-loader 的 fallback 函数就是 file-loader,同时使用两个 loader 的话,url-loader 会对原本图片文件的路径进行 base64 的转换。这就会导致转换出来的图片不可见——转换的是图片路径,而非图片。
具体的讨论在 url-loader 的一个 issue 里有:url-loader is encoding path instead of image。
也算是踩了个雷学到了个知识点。
- module.exports = {
- module: {
- rules: [
- {
- test: /\.png$/i,
- use: [
- {
- // 原本是 file-loader,这里要修改为 url-loader
- loader: 'url-loader',
- options: {
- // 这个上限是官方文档设立的,这里就不改了
- limit: 8192,
- // 同理,不设置为false打开的会是 esModule
- esModule: false,
- },
- },
- ],
- },
- ],
- },
- };
胜利的曙光已经近在眼前,下一步只需要解决静态资源的问题就好了。这里的静态资源指的是 public 下的 index.html 和 favicon.ico。首先需要将 public 下面的内容 cv 到 dist 下,随后还要处理一下 HTML 中的模板文件。
这里使用的插件是 htmlWebpackPlugin,这个也是 Vue 的原生项目中的提示:
<title><%= htmlWebpackPlugin.options.title %></title>
具体的配置可以查看 github 上的说明:
html-webpack-plugin
1、下载安装插件
D:\\vue-app-base>npm i -D html-webpack-plugin
2、修改配置文件
这里就是根据官方文档来修改配置了。
注*:BASE_URL 是环境变量,所以需要使用 deinfeProperty 去设置
- // 新导入的两个依赖
- const webpack = require('webpack');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
-
- module.exports = {
- plugins: [
- // 设置 webpack 所要的基础配置
- new webpack.DefinePlugin({
- BASE_URL: JSON.stringify('./'),
- }),
- // 空的狗欧早寒素仅会生成一个 index.html,会引入合适的文件,但是入口DOM节点 app 不见了,所以需要其他的配置
- new HtmlWebpackPlugin({
- template: 'public/index.html',
- favicon: 'public/favicon.ico',
- }),
- ],
- };
注 2*:新学到了一招,也可以直接在 html-webpack-plugin 里面直接设置:
- new HtmlWebpackPlugin({
- template: 'public/index.html',
- templateParameters: {
- BASE_URL: '/',
- },
- });
3、运行 npm run build
打包
此时的结果如下:
可以看到 favicon.ico 也被打包好了,index.html 的内容如下:
可以看到,标题(title), Logo 都已经被动态修改了,而且内容也可以正常渲染:
现在每次编写还是会重写 dist 中的内容,虽然不会影响结果,但是可能会导致之前产出的文件遗留在文件夹中,导致不必要的浪费。这里会使用 clean-webpack-plugin 这个插件去解决这个问题,npmjs 的地址为:clean-webpack-plugin
注*:默认这个版本会将所有输出目录下的内容全都清空。
1、下载安装插件
npm install --save-dev clean-webpack-plugin
2、修改配置
这个配置改起来还是很快的,直接引用即可。
- const { CleanWebpackPlugin } = require('clean-webpack-plugin');
-
- module.exports = {
- plugins: [
- // 前面的配置不变
- new CleanWebpackPlugin(),
- ],
- };
3、运行 npm run build
打包
我运行了一下成功了,接下来就修改另外一个问题了。
之前在配置 html-webpack-plugin 这个插件的时候,我又加了一个 favicon.ico,然后就发现,Vue 项目原本就有一个 favicon.ico,这里又加了一个,就出现了重复代码:
在上面调用 clean-webpack-plugin 的时候,我把原本的 favicon 配置去掉了,又出现图片没有被迁徙的问题。这里就找一个插件,进行静态资源的迁徙。
这里用的插件是在 webpack 官网上找到的一个插件:copy-webpack-plugin
1、下载安装插件
npm install copy-webpack-plugin --save-dev
2、修改配置
这里只需要迁徙 favicon.ico,所以就只设定了这一个文件,不过 copy-webpack-plugin 实际上可以迁徙单个文件,也可以迁徙整个文件夹
- // 日常加引用
- const CopyPlugin = require('copy-webpack-plugin');
-
- module.exports = {
- plugins: [
- // 其余不变
- // 这里只迁徙了 favico.ico 这个文件
- new CopyPlugin({
- patterns: [{ from: 'public/favicon.ico', to: './' }],
- }),
- ],
- };
这样就完成了对 favicon.ico 文件的迁徙
将 package.json 中的 build 修改一下:
// 之前是development "build": "webpack --mode=production",
在运行打包命令 npm run build
,webpack 就会根据生产环境对打包的文件进行自动压缩:
HTML 的入口文件:
打包后的 bundle.js 文件:
这样的话,一个基础的生产环境打包功能就实现了。
下一步的目标是学习使用 webpack-dev-server 对开发环境进行配置——毕竟我这里使用的是 live server 插件实现的热更新,但是并不能保证所有的人都用一个编辑器/IDE,更别说同一个插件了。
同样,tree shaking 和 code splitting 也是需要考虑的问题,这也会在下一篇内容进行学习和配置。
最后,Linting 应该也是需要加上的,保持代码风格的统一对于后期的维护还是很有帮助的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。