【前端工程化】(P117~148)

前端工程化也叫前端模块化,接下来学习如何以模块化的方式进行前端项目的开发。

学习目标:

  1. 知道有哪些模块化相关规范
  2. 使用打包工具 webpack 搭建基本的工程化项目结构
  3. 使用 Vue 单文件组件
  4. 使用 Vue 脚手架快速创建企业级的view模板项目
  5. 在 Vue 项目中使用 Element-UI 这个流行的vue组件库

【模块化相关规范】

1. 模块化概述

传统开发模式的主要问题:

  1. 命名冲突:比如多个JS之间如果存在重名变量,则会发生变量覆盖问题
  2. 文件依赖:指的是JS文件之间无法实现相互的引用

通过模块化解决上述问题:

  • 模块化就是把单独的一个功能封装到一个模块(文件)中,模块之间相互隔离,但是可以通过特定的接口公开内部成
    员,也可以依赖别的模块
  • 模块化开发的好处:方便代码的重用,从而提升开发效率,并且方便后期的维护

2. 浏览器端模块化规范

  1. AMD

典型代表是Require.js,官网:http://www.requirejs.cn/

  1. CMD

典型代表是Sea.js,官网:https://seajs.github.io/seajs/docs/

无需过多关注 AMD 和 CMD,他们已经落伍了,有了更好的替代方案

3. 服务器端模块化规范

典型的就是 node.js 中的 CommonJS 规范:

  1. 模块分为 单文件模块
  2. 模块成员导出(向外暴露成员):module.exportsexports
  3. 模块成员导入(导入其他模块):require(‘模块标识符‘)

4. 大一统的模块化规范:ES6模块化

在 ES6 模块化规范诞生之前,Javascript 社区已经尝试并提出了 AMD、CMD、CommonJS 等模块化规范。

但是,这些社区提出的模块化标准,还是存在一定的差异性局限性并不是浏览器与服务器通用的模块化标准,例如:

  • AMD 和 CMD 适用于浏览器端的 Javascript 模块化
  • CommonJS 适用于服务器端的 Javascript 模块化

因此,ES6 语法规范中,在语言层面上定义了 ES6 模块化规范,是浏览器端与服务器端通用的模块化开发规范。

ES6模块化规范中定义:

  • 每个 js 文件都是一个独立的模块
  • 导入模块成员使用 import 关键字
  • 暴露模块成员使用 export 关键字

(Node.js通过babel体验ES6模块化)

Node.js 对ES6的模块化支持得不是很好,需要通过结合 babel 这个第三方插件在 node 中体验高级的 ES6 特性。babel是一个语法转换工具,可以把高级的、有兼容性的JavaScript代码转换为低级的、没有兼容性的JavaScript代码。

如何在node.js中配置babel?可以新建空文件夹作为项目根目录,并用vscode打开,在vscode新建终端执行以下命令:

  • 一、安装 babel 相关四个依赖包

    1
    npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
  • 二、额外安装一个叫做 babel/polyfil 的第三方插件

    1
    npm install --save @babel/polyfill
  • 三、项目根目录中创建babel的配置文件 babel.config.js,并在配置文件 babel.config.js 中添加下方代码进行改造

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // presets是一个语法转化的数组,提供了我们在转换期间可能会用到的一些语法转换插件
    // 其中 babel/env 就是刚刚上面装的插件
    // targets节点代表说,转换完毕后的代码起码要支持哪些浏览器
    const presets = [
    ["@babel/env", {
    targets: {
    edge: "17",
    firefox: "60",
    chrome: "67",
    safari: "11.1"
    }
    }]
    ];
    // 最后通过 module.exports 向外暴露出去,供babel来进行使用
    module.exports = { presets };
  • 四、项目根目录中创建index.js,里面添加一句:

    1
    console.log('ok')
  • 五、终端运行 npx babel-node index.js 命令执行代码,若命令行输出“ok”说明运行成功。

    这个 npx 命令是 npm 从5.2版开始增加的命令。 npx 想要解决的主要问题,就是方便调用项目内部安装的模块。
    插件babel运行之前会读取自己babel.config.js配置文件中的相关信息,会根据我们指定的配置来做相关的代码转换。

现在它已经支持我们使用那些高级的ES6的特性了,比如说ES6的模块化导入就可以基于这样的一个node项目来进行相关的学习。

5. ES6 模块化的基本语法

(1) 默认导出 与 默认导入

注意:每个模块中,只允许使用唯一的一次 export default导出,否则会报错!不使用不会报错,但会打印出空对象。

  • 默认导出语法:export default 默认导出的成员名称

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 当前文件模块为 m1.js

    // 定义私有成员 a 和 c
    let a = 10
    let c = 20
    // 外界访问不到变量 d ,因为它没有被暴露出去
    let d = 30
    function show() {}

    // 将本模块中的私有成员暴露出去,供其它模块使用
    export default {
    a,
    c,
    show
    }
  • 默认导入语法:import 接收名称 from '模块标识符'
    from之前可以指定接收的名称,名称可以是任意的,只要合法就行。

    1
    2
    3
    4
    5
    6
    7
    // 在index.js中导入模块成员
    import m1 from './m1.js'

    console.log(m1)
    // 打印输出的结果为:
    // { a: 10, c: 20, show: [Function: show] }
    // 因为刚刚只暴露了私有成员 a 和 c,变量d没有暴露出去

(2) 按需导出 与 按需导入

注意:每个模块中,可以使用多次按需导出

  • 按需导出语法: export let s1 = 10

    1
    2
    3
    4
    5
    6
    7
    // 当前文件模块为 m1.js
    // 向外按需导出变量 s1,其中export是关键字
    export let s1 = 'aaa'
    // 向外按需导出变量 s2
    export let s2 = 'ccc'
    // 向外按需导出方法 say
    export function say = function() {}
  • 按需导入语法: import { s1 } from '模块标识符'

    1
    2
    3
    4
    5
    6
    // 导入模块成员
    // 其中名称不能乱写,要与按需导出的名称有一一对应的关系,但可以用as关键字起别名
    import { s1, s2 as ss2, say } from './m1.js'
    console.log(s1) // 打印输出 aaa
    console.log(ss2) // 打印输出 ccc
    console.log(say) // 打印输出 [Function: say]

JS文件中既有刚刚的默认导出,又有现在按需导出,会冲突吗?
不会的。import m1 from会默认指向export default默认导出的成员。m1中是不会包含export let按需导出的成员的。
但如果是这样书写:import m1, {} from './m1.js',逗号前是默认导入的成员,逗号后是按需导入的成员。

(3) 直接导入并执行模块代码

把 from 关键字省略就行了

有时候,我们只想单纯执行某个模块中的代码,并不需要得到模块中向外暴露的成员,此时,可以直接导入并执行模块代码。

1
2
3
4
5
// 当前文件模块为 m2.js
// 在当前模块中执行一个 for 循环操作,并没有暴露任何成员
for(let i = 0; i < 3; i++) {
console.log(i)
}
1
2
3
// 直接导入并执行模块代码
// 只需执行,但不需要接收 m2 的任何成员
import './m2.js'

【webpack】

1. 当前 Web 开发面临的困境

  • 文件依赖关系错综复杂
  • 静态资源请求效率低
  • 模块化支持不友好
  • 浏览器对高级 Javascript 特性兼容程度较低
  • etc…

(webpack 概述)

webpack 是一个流行的前端项目构建工具(打包工具),可以解决当前 web 开发中所面临的困境。
webpack 提供了友好的模块化支持,以及代码压缩混淆处理 js 兼容问题性能优化等强大的功能,从而让程序员把
工作的重心放到具体的功能实现上,提高了开发效率和项目的可维护性。

目前绝大多数企业中的前端项目,都是基于 webpack 进行打包构建的。

2022-49 webpack.png

webpack中文官网:https://webpack.docschina.org/

总的来说,webpack在整个前端项目开发中起到了什么作用呢?它提供了友好的模块化支持、以及代码压缩混淆、处理JS兼容问题以及性能优化这些强大的功能。

2. webpack 的基本使用

(1) 创建列表隔行变色项目

  1. 新建项目空白目录(尽量别中文命名因为好像会报错),并运行 npm init -y 命令,快速初始化一个包管理配置文件 package.json
  2. 新建 src 源代码目录
  3. 新建 src -> index.html 首页
  4. 初始化首页基本的结构(vscode创建多行表格的快捷语句是ul>li{这是第$个li}*9
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./index.js"></script>
    </head>
    <body>
    <ul>
    <li>这是第1个li</li>
    <li>这是第2个li</li>
    <li>这是第3个li</li>
    <li>这是第4个li</li>
    <li>这是第5个li</li>
    <li>这是第6个li</li>
    <li>这是第7个li</li>
    <li>这是第8个li</li>
    <li>这是第9个li</li>
    </ul>
    </body>
    </html>
  5. 运行 npm install jquery -S 命令,安装 jQuery
  6. 要求通过模块化的形式,实现列表隔行变色效果
    • 新建 src -> index.js 文件
    • 在index.html中导入js:<script src="./index.js"></script>
    • 在index.js中输入以下代码,然后在浏览器打开页面
      1
      2
      3
      4
      5
      6
      7
      // 使用默认导入的方式引入jQuery
      import $ from 'jquery'

      $(function(){
      $('li:odd').css('backgroundColor', 'pink') //选中奇数行
      $('li:even').css('backgroundColor', 'lightblue') //选中偶数行
      })
      浏览器报错Uncaught SyntaxError: Cannot use import statement outside a module
      因为js文件第一行是ES6的模块化语法,浏览器对这种语法支持得并不是很好,所以浏览器不识别,就报错;
      我们可以通过webpack把这种有兼容性的代码转换为没有兼容性的代码;

(2) 在项目中安装和配置webpack

  1. 运行 npm install webpack webpack-cli -D 命令,安装 webpack 两个相关的包
    这一步真的巨慢,进度条一直卡在中间,科学上网建议换个网速快一点的线路
  2. 在项目根目录中,创建名为 webpack.config.js 的 webpack 配置文件
  3. 在 webpack 的配置文件中,初始化如下基本配置:
    1
    2
    3
    4
    5
    6
    // 向外暴露一个webpack配置对象
    // 其中mode属性值为字符串,用来指定我们的构建模式,development指开发模式(我们转换出来的代码不会进行压缩与混淆,转换速度会比较快)
    // 构建模式的另一种模式可选值是production产品发布模式(会对转换出来的代码进行压缩与混淆,转换时间就会长一些)
    module.exports = {
    mode: 'development' // mode 用来指定构建模式
    }
  4. 在 package.json 配置文件中的 scripts 节点下,新增 dev 脚本如下,脚本的命令叫做“webpack”:
    1
    2
    3
    "scripts": {
    "dev": "webpack" // script 节点下的脚本,可以通过 npm run 执行
    }

    问题提醒:Problems loading reference 'https://json.schemastore.org/package': Unable to load schema from 'https://json.schemastore.org/package': connect ECONNREFUSED 127.0.0.1:19180.
    不知道是啥,我没管

  5. 在终端中运行 npm run dev 命令,启动 webpack 进行项目打包。
    执行npm run dev后:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    > webpack-study@1.0.0 dev
    > webpack

    asset main.js 323 KiB [emitted] (name: main)
    runtime modules 937 bytes 4 modules
    cacheable modules 282 KiB
    ./src/index.js 227 bytes [built] [code generated]
    ./node_modules/jquery/dist/jquery.js 282 KiB [built] [code generated]
    webpack 5.70.0 compiled successfully in 1897 ms
  • 由这段命令提示可知:
    • 当前 webpack 的版本号是 5.70.0
    • 打包总共花费了 1897 ms
    • 输出的资源名字叫做 main.js,体积是 323 KiB
    • main.js 的输出路径是webpack自动创建的 dist 目录下

现在,把 index.html 中的 <script src="./index.js"></script>

修改为 <script src="../dist/main.js"></script>

现在打开页面,就可以发现隔行变色效果实现了。

(3) 配置打包的入口与出口

webpack 的 4.x 版本中默认约定:

  • 打包的入口文件为 src -> index.js
  • 打包的输出文件为 dist -> main.js

如果要修改打包的入口与出口,可以在 webpack.config.js 中新增如下配置信息:

1
2
3
4
5
6
7
8
const path = require('path') // 导入node.js中专门操作路径的模块
module.exports = {
entry: path.join(__dirname, './src/index.js'), // entry节点代表打包入口文件的绝对路径。其中__dirname指当前文件所处的目录,与逗号后面的路径拼接在一起就形成了绝对路径
output: { // output是一个配置对象
path: path.join(__dirname, './dist'), // path属性用来指定输出文件的存放路径
filename: 'bundle.js' // filename属性用来指定输出文件的名称
}
}

然后终端执行命令 npm run dev ,从而把webpack跑起来。执行结果如下:

1
2
3
4
5
6
7
8
9
> webpack-study@1.0.0 dev
> webpack

asset bundle.js 323 KiB [emitted] (name: main)
runtime modules 937 bytes 4 modules
cacheable modules 282 KiB
./src/index.js 227 bytes [built] [code generated]
./node_modules/jquery/dist/jquery.js 282 KiB [built] [code generated]
webpack 5.70.0 compiled successfully in 592 ms

可以看到打包完成,输出文件确实叫bundle.js,dist文件夹下确实也多了这个js文件

注释或删掉index.html中的旧的<script src="../dist/main.js"></script>,替换成重新打包新生成的<script src="../dist/bundle.js"></script>

现在浏览器打开页面,发现隔行变色效果依然生效了。

(4) 配置webpack的自动打包功能

为什么要设置自动打包呢?因为index.html中引入的是dist文件夹下我们打包好的那个main.js或者bundle.js等文件,每次我们在index.js中修改源代码后都需要重新npm run dev执行打包的过程,最新的代码才会生效。太麻烦了。

  1. 运行 npm install webpack-dev-server -D 命令,安装支持项目自动打包的工具
  2. 修改 package.json -> scripts 中的 dev 命令如下(从webpack修改成webpack-dev-server):
    1
    2
    3
    "scripts": {
    "dev": "webpack-dev-server" // script 节点下的脚本,可以通过 npm run 执行
    }
  3. 将 src -> index.html 中,script 脚本的引用路径,从”../dist/bundle.js“修改为根路径下的 “/buldle.js
  4. 运行 npm run dev 命令,重新进行打包
  5. 稍等片刻,在浏览器中访问 http://localhost:8080 地址,点击src文件夹即可查看自动打包后的页面效果。

如果页面不能正常显示,只显示一行“Cannot GET /”,可以打开webpack.config.js文件:

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

module.exports = {
mode: 'development', //development 或 production
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, './dist'),
filename: 'bundle.js'
}
}

在其中加入加入devServer节点,即修改成如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const path = require('path')

module.exports = {
mode: 'development', //development 或 production
entry: path.join(__dirname, './src/index.js'),
output: {
path: path.join(__dirname, './dist'),
filename: 'bundle.js'
},
devServer: {
//....//
static: {
directory: path.join(__dirname, './'),
watch: true
}
}
}

重新运行 npm run dev 打包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
> webpack-study@1.0.0 dev
> webpack-dev-server

<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
<i> [webpack-dev-server] On Your Network (IPv4): http://xx.xx.xx.xx:8080/
<i> [webpack-dev-server] Content not from webpack is served from 'C:\Users\10272\Desktop\webpack-study\public' directory
asset bundle.js 563 KiB [emitted] (name: main)
runtime modules 27 KiB 12 modules
modules by path ./node_modules/ 443 KiB
modules by path ./node_modules/webpack-dev-server/client/ 56.8 KiB 12 modules
modules by path ./node_modules/webpack/hot/*.js 4.3 KiB
./node_modules/webpack/hot/dev-server.js 1.59 KiB [built] [code generated]
./node_modules/webpack/hot/log.js 1.34 KiB [built] [code generated]
+ 2 modules
modules by path ./node_modules/html-entities/lib/*.js 81.3 KiB
./node_modules/html-entities/lib/index.js 7.74 KiB [built] [code generated]
./node_modules/html-entities/lib/named-references.js 72.7 KiB [built] [code generated]
+ 2 modules
./node_modules/jquery/dist/jquery.js 282 KiB [built] [code generated]
./node_modules/ansi-html-community/index.js 4.16 KiB [built] [code generated]
./node_modules/events/events.js 14.5 KiB [built] [code generated]
./src/index.js 227 bytes [built] [code generated]
webpack 5.70.0 compiled successfully in 3758 ms

根据上面运行代码可以得知:

  • webpack-dev-server工具将我们的项目托管到了localhost:8080/端口上;
  • 打包好的文件通过localhost:8080/bundle.js访问;

可以发现,终端运行命令打包完成后,并没有退出终端,而是光标在最后一行一闪一闪。这是因为他在监听我们项目中代码的改变,只要代码变化了,它就会帮我们重新打包,这样就方便很多了。你可以试试在index.js里修改颜色并保存,页面会实时显示效果。

  • 注意:
    1. webpack-dev-server 会启动一个实时打包的 http 服务器
    2. webpack-dev-server 打包生成的输出文件,默认放到了项目根目录中,而且是虚拟的、看不见的

(5) 配置html-webpack-plugin生成预览页面

刚刚配置完webpack自动打包后,输入localhost:8080/,我们需要手动点击src文件夹才能看到预览页面。

那我们如何进入localhost:8080/无需手动点一下就能直接看到页面呢?

  1. 运行 npm install html-webpack-plugin -D 命令,安装生成预览页面的插件
  2. 修改 webpack.config.js 文件头部区域,添加如下配置信息:
    1
    2
    3
    4
    5
    6
    // 导入生成预览页面的插件,得到一个构造函数
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const htmlPlugin = new HtmlWebpackPlugin({ // 创建插件的实例对象
    template: './src/index.html', // 指定要用到的模板文件
    filename: 'index.html' // 指定生成的文件的名称,该文件存在于内存中,在目录中不显示
    })
  3. 修改 webpack.config.js 文件中向外暴露的配置对象,新增plugins配置节点:
    1
    2
    3
    module.exports = {
    plugins: [ htmlPlugin ] // plugins 数组是 webpack 打包期间会用到的一些插件列表
    }

运行 npm run dev 命令,重新进行打包。

稍等片刻,在浏览器中访问 http://localhost:8080 地址直接就能看见页面啦!

总结一下步骤:1.安装插件;2.导入构造函数;3.创建(new)一个插件实例对象;4.把实例挂载到plugins数组中。

(6) 配置自动打包相关的参数

上面的 html-webpack-plugin 插件解决了我们输入地址后不用手动点击就能看到页面,

但是有没有可能我们执行完 npm run dev 命令之后连地址都不用我们输入就能自动弹出页面呢?

1
2
3
4
5
6
7
// package.json中的配置
// --open 打包完成后自动打开浏览器页面
// --host 配置 IP 地址
// --port 配置端口
"scripts": {
"dev": "webpack-dev-server --open --host 127.0.0.1 --port 8888"
},

修改完重新运行 npm run dev 命令。

3. webpack 中的加载器

(1) 通过loader打包非js模块

在实际开发过程中,webpack 默认只能打包处理以 .js 后缀名结尾的模块,其他非 .js 后缀名结
尾的模块,webpack 默认处理不了需要调用 loader 加载器才可以正常打包,否则会报错!

loader 加载器作用:可以协助 webpack 打包处理特定的文件模块,比如:

  • less-loader 可以打包处理 .less 相关的文件
  • sass-loader 可以打包处理 .scss 相关的文件
  • url-loader 可以打包处理 css 中与 url 路径相关的文件

(2) loader 的调用过程

loader 的调用过程

4. webpack 中加载器的基本使用

qvnhvQ.png

(1) 打包处理 css 文件

  1. 运行 npm i style-loader css-loader -D 命令,安装处理 css 文件的 loader
  2. webpack.config.jsmodule -> rules 数组中,添加 loader 规则如下:
    1
    2
    3
    4
    5
    6
    7
    8
    // 新建一个module对象,在rules属性数组中添加所有第三方文件模块的匹配规则
    // 数组中test属性后面接收的正则表达式表示要匹配的后缀名类型,其中\.表示匹配后缀名中的点号,$代表以css结尾的文件类型
    // 数组中use属性表示对应要调用的 loader
    module: {
    rules: [
    { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    ]
    }

注意:

  • use 数组中指定的 loader 顺序是固定的
  • 多个 loader 的调用顺序是:从后往前调用(所以处理顺序是css-loaderstyle-loader,最后交给webpack)

(2) 打包处理 less 文件

  1. 运行 npm i less-loader less -D 命令,安装这两个依赖项
  2. webpack.config.jsmodule -> rules 数组中,添加 loader 规则如下:
    1
    2
    3
    4
    5
    6
    // 所有第三方文件模块的匹配规则
    module: {
    rules: [
    { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }
    ]
    }

(3) 打包处理 scss 文件

  1. 运行 npm i sass-loader node-sass -D 命令
  2. webpack.config.jsmodule -> rules 数组中,添加 loader 规则如下:
    1
    2
    3
    4
    5
    6
    // 所有第三方文件模块的匹配规则
    module: {
    rules: [
    { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }
    ]
    }

(4) 配置postCSS自动添加css的兼容前缀

  1. 运行 npm i postcss-loader autoprefixer -D 命令
  2. 在项目根目录中创建 postcss 的配置文件 postcss.config.js,并初始化如下配置:
    1
    2
    3
    4
    const autoprefixer = require('autoprefixer') // 导入自动添加前缀的插件
    module.exports = {
    plugins: [ autoprefixer ] // 挂载插件
    }
  3. webpack.config.jsmodule -> rules 数组中,修改 css 的 loader 规则如下:
    1
    2
    3
    4
    5
    6
    7
    // 所有第三方文件模块的匹配规则
    module: {
    rules: [
    // { test: /\.css$/, use: ['style-loader', 'css-loader'] }, // 原来的css规则可以注释掉
    { test:/\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader'] }
    ]
    }

(5) 打包样式表中的图片和字体文件

我的疑问是,在我没有安装下面的 url-loaderfile-loader 这两个依赖包前,我电脑的webpack也能正常将图片打包并显示在前端页面……

  1. 运行 npm i url-loader file-loader -D 命令
  2. webpack.config.jsmodule -> rules 数组中,添加 loader 规则如下:
    由于 file-loaderurl-loader 的内置依赖项,所以我们只安装就可以,不用去配置file-loader。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    module: {
    rules: [
    // {test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, use: ['url-loader'] }, //下面那种写法也可以
    {
    test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, // 竖线代表或者
    use: 'url-loader?limit=16940' // 问号代表要传参
    // 这里的limit是一个参数,当图片小于该字节数时,图片会转为base64;图片大于或等于该值,就不会被转成base64
    }
    ]
    }

在我操作完上方步骤,我电脑的webpack反而不能正常将图片打包并显示在前端页面……什么鬼?并且控制台没有任何报错,代码中也确确实实引用了图片的URL地址
搜索了一下,很多人遇到了和我一样的情况:

原来,在webpack5的官网中file-loader/url-loader/raw-loader等已经是弃用了的,而是通过资源模块(asset module) 替代了,如果还要使用这些废弃了的文件的话,必须最后加上一句type: 'javascript/auto',否则会出现一张图片打包两次,而且会出现背景图片不会显示到页面上的问题(参考博文、以及参考webpack官网-资源模块)。

看了一下package.json中的版本信息,我的确实是webpack5。

1
2
3
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"

那如何解决现在的问题呢?

  1. 可以根据其他人博客或者webpack官网配置一下webpack.config.js的信息,解决asset重复的问题;
  2. 或者降级为webpack4,但不建议哈;
  3. 或者直接npm uninstall url-loader file-loader -D删除依赖包。

和我一样懒的话,直接选择第三种卸载就完事了,留着干嘛,多余的东西。

执行命令卸载完后,我的webpack.config.js中可以这样设置(最常用的asset示范):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module.exports = {
module: {
rules: [
{
test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,
type: 'asset',
generator: {
filename: "img/[name]_[hash:6][ext]" // 文件命名
},
parser: {
dataUrlCondition: {
maxSize: 15 * 1024 // 超过15kb不转base64
}
}
}
]
}
}

可以看到上面有个转base64的限制,因为提升应用性能的一个重要的条件是降低http请求数,而应用中经常会有大大小小的图片需要处理,对应用中的小图标来说,css sprite 是首选,将各种图标集合成一张大的图片可以很好的减少网络请求数。而对于需要独立开的图片,且大小在合理范围内时,我们可以将图片转换成 base64位编码,内嵌到css 中,同样可以减少请求。但对于相对大的图片来说还是不转base64,直接URL地址更好。

然后重新npm run dev打包,否则不生效。

这种方式可以代替url-loaderfile-loader,也再也不用下载这两个loader了。

(6) 打包处理 js 文件中的高级语法

index.js中,我们添加几行高级语法代码,例如:

1
2
3
4
5
6
// 定义一个JS高级语法(关键字Person和它的静态的info属性)
class Person {
static info = 'aaa'
}

console.log(Person.info)

然后刷新页面,会发现浏览器报错了,提示我们webpack默认打包处理不了这种高级的JS语法。那怎么办呢?我们需要配置一下 babel 相关的 loader 来解析并且转换这些高级的语法。

虽然但是,视频教程中演示的会报错,可我的页面刷新后却能正常显示,不会是因为现在 webpack5 默认支持高级语法了吧?搜索了一下,没有找到webpack5支持高级语法的说法,那先不管了,按着教程步骤走吧。

  1. 安装babel转换器相关的包:npm i babel-loader @babel/core @babel/runtime -D
  2. 安装babel语法插件相关的包:npm i @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D
  3. 在项目根目录中,创建 babel 配置文件 babel.config.js 并初始化基本配置如下:
    1
    2
    3
    4
    5
    //向外暴露配置对象,包括presets和plugins两个数组
    module.exports = {
    presets: [ '@babel/preset-env' ],
    plugins: [ '@babel/plugin-transform-runtime', '@babel/plugin-proposal-class-properties' ]
    }
  4. webpack.config.jsmodule -> rules 数组中,添加 loader 规则如下:
    1
    2
    // test用来匹配所有.js结尾的文件;exclude为排除项,表示babel-loader不需要处理node_modules中的js文件
    { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }

重新npm run dev,页面正常显示。(幸亏不是跟上面打包图片那个似的安装完依赖包反而不管用)


【Vue单文件组件】

1. 传统组件的问题和解决方案

  • 传统组件的问题:

    1. 全局定义的组件必须保证组件的名称不重复
    2. 字符串模板缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的反斜杠 \ 转义字符
    3. 不支持 CSS 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
    4. 没有构建步骤限制,只能使用 HTML 和 ES5 JavaScript, 而不能使用高级预处理器进行转换(如:Babel)
  • 解决方案:

    • 针对传统组件的问题,Vue 提供了一个解决方案 —— 使用 Vue 单文件组件。

2. Vue 单文件组件的基本用法

  • 单文件组件的组成结构
    • template 组件的模板区域
    • script 业务逻辑区域
    • style 样式区域

.vue单文件组件模板:

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
<template>

<div>
<h1> 这里用于定义Vue组件的模板内容 </h1>
</div>

</template>

<script>

// 这里用于定义Vue组件的业务逻辑
// export default暴露一个配置对象
export default {
//私有数据
data() {
return {}
},
//处理函数
methods: {}
};

</script>

<style scoped>

/* 这里用于定义组件的私有样式,
建议为每个.vue页面的style都添加一个scoped指令,防止页面间的冲突问题 */
h1 {
color: red;
}

</style>

在项目的src目录下新建一个components目录,在该目录下新建一个App.vue单文件组件。

要在VSCode中编写Vue文件格式,需要在扩展商店安装一个插件Vetur,它支持Vue的代码高亮和其他相关功能,这是它的官方文档

安装完Vetur后,如果在.vue单文件中输入<template>标签,编辑器会报错变红。
解决方法:点击Vscode窗口左下角齿轮,选择设置,在搜索框里输入Vetur,下滑到最下面找到Vetur>Validation:Template Props选项,把Validate vue-html in <template> using eslint-plugin-vue选项的勾选框取消掉。重新打开.vue单文件,可以看到不报错了。

3. webpack中配置vue组件的加载器

index.js中引入Vue单文件:

1
2
// 导入单文件组件
import App from './components/App.vue'

因为webpack默认只能打包处理JS文件,因此Vue单文件肯定是处理不了的,所以要配置对应的loader加载器来解析转换,否则页面会报错。

  1. 运行 npm i vue-loader vue-template-compiler -D 命令(其中后者是前者的内置依赖项)
  2. webpack.config.js 配置文件中,添加 vue-loader 的配置项如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 导入vue-loader插件并接收
    const VueLoaderPlugin = require('vue-loader/lib/plugin')
    module.exports = {
    plugins: [
    // ... 其它插件(用逗号分隔开)
    new VueLoaderPlugin() // 请确保引入这个插件!
    ],
    module: {
    rules: [
    // ... 其它规则

    // 新增.vue文件的配置规则,调用vue-loader进行解析和转换
    { test: /\.vue$/, use: 'vue-loader' }
    ]
    }
    }

重新打包,发现报错Error: Cannot find module 'vue-loader/lib/plugin',找了一下node_modules的vue-loader文件夹里面确实没有lib文件夹,只有dist文件夹。执行npm view vue-loader versions查看一下版本信息:

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
npm view vue-loader versions 
[
'0.1.0', '0.2.0', '0.3.0', '1.1.0',
'1.1.2', '1.1.3', '1.1.4', '1.1.5',
'1.1.6', '2.0.0', '2.0.1', '2.0.2',
'2.0.3', '2.1.0', '2.1.1', '3.0.2',
'3.0.3', '3.0.4', '4.0.0', '4.0.1',
'4.0.2', '4.0.3', '4.0.4', '4.0.5',
'4.0.6', '4.0.7', '4.0.8', '4.0.9',
'4.0.10', '5.0.0', '6.0.0', '6.0.1',
'6.0.2', '6.0.3', '6.0.4', '6.0.5',
'6.1.0', '7.0.0', '7.0.1', '7.0.2',
'7.0.3', '7.1.0', '7.1.1', '7.1.2',
'7.1.3', '7.1.4', '7.1.5', '7.1.6',
'7.1.7', '7.1.8', '7.2.0', '7.3.0',
'7.4.0', '7.4.1', '7.4.2', '7.5.0',
'7.5.1', '7.5.2', '7.5.3', '8.0.0',
'8.0.1', '8.0.2', '8.0.3', '8.0.4',
'8.0.5', '8.1.0', '8.1.1', '8.1.2',
'8.1.3', '8.1.4', '8.2.0', '8.2.1',
'8.2.2', '8.2.3', '8.3.0', '8.3.1',
'8.4.0', '8.5.0', '8.5.1', '8.5.2',
'8.5.3', '8.5.4', '8.6.0', '8.6.1',
'8.7.0', '8.7.1', '9.0.0', '9.0.1',
'9.0.2', '9.0.3', '9.1.0', '9.1.1',
'9.1.2', '9.1.3', '9.2.0', '9.2.1',
'9.2.2', '9.2.3', '9.3.0', '9.3.1',
'9.3.2', '9.4.0', '9.4.1', '9.4.2',
'9.5.0', '9.5.1', '9.5.2', '9.5.3',
'9.6.0', '9.7.0', '9.8.0', '9.8.1',
'9.9.0', '9.9.1', '9.9.2', '9.9.3',
'9.9.4', '9.9.5', '10.0.0', '10.0.1',
'10.0.2', '10.0.3', '10.0.4', '10.1.0',
'10.1.1', '10.1.2', '10.2.0', '10.2.1',
'10.2.2', '10.2.3', '10.2.4', '10.3.0',
'11.0.0', '11.1.0', '11.1.1', '11.1.2',
'11.1.3', '11.1.4', '11.2.0', '11.3.0',
'11.3.1', '11.3.2', '11.3.3', '11.3.4',
'12.0.0', '12.0.1', '12.0.2', '12.0.3',
'12.0.4', '12.1.0', '12.1.1', '12.2.0',
'12.2.1', '12.2.2', '13.0.0', '13.0.1',
'13.0.2', '13.0.3', '13.0.4', '13.0.5',
'13.1.0', '13.2.0', '13.2.1', '13.3.0',
'13.4.0', '13.5.0', '13.5.1', '13.6.0',
'13.6.1', '13.6.2', '13.7.0', '13.7.1',
'13.7.2', '13.7.3', '14.0.0', '14.0.1',
'14.0.2', '14.0.3', '14.1.0', '14.1.1',
'14.2.0', '14.2.1', '14.2.2', '14.2.3',
'14.2.4', '15.0.0-beta.1', '15.0.0-beta.2', '15.0.0-beta.3',
'15.0.0-beta.4', '15.0.0-beta.5', '15.0.0-beta.6', '15.0.0-beta.7',
'15.0.0-rc.1', '15.0.0-rc.2', '15.0.0', '15.0.1',
'15.0.2', '15.0.3', '15.0.4', '15.0.5',
'15.0.6', '15.0.7', '15.0.8', '15.0.9',
'15.0.10', '15.0.11', '15.0.12', '15.1.0',
'15.2.0', '15.2.1', '15.2.2', '15.2.3',
'15.2.4', '15.2.5', '15.2.6', '15.2.7',
'15.3.0', '15.4.0', '15.4.1', '15.4.2',
'15.5.0', '15.5.1', '15.6.0', '15.6.1',
'15.6.2', '15.6.3', '15.6.4', '15.7.0',
'15.7.1', '15.7.2', '15.8.0', '15.8.1',
'15.8.2', '15.8.3', '15.9.0', '15.9.1',
'15.9.2', '15.9.3', '15.9.4', '15.9.5',
'15.9.6', '15.9.7', '15.9.8', '16.0.0-alpha.0',
'16.0.0-alpha.1', '16.0.0-alpha.2', '16.0.0-alpha.3', '16.0.0-beta.1',
'16.0.0-beta.2', '16.0.0-beta.3', '16.0.0-beta.4', '16.0.0-beta.5',
'16.0.0-beta.6', '16.0.0-beta.7', '16.0.0-beta.8', '16.0.0-beta.9',
'16.0.0-beta.10', '16.0.0-rc.0', '16.0.0-rc.1', '16.0.0-rc.2',
'16.0.0', '16.1.0', '16.1.1', '16.1.2',
'16.2.0', '16.3.0', '16.3.1', '16.3.2',
'16.3.3', '16.4.0', '16.4.1', '16.5.0',
'16.6.0', '16.7.0', '16.7.1', '16.8.0',
'16.8.1', '16.8.2', '16.8.3', '17.0.0'
]

package.json查看vue-loader版本,是最新的17.0.0,可能太新了,执行npm i -D vue-loader@15.0.0随便降级到 15.7.0 吧。降级完发现 node_modules 的 vue-loader 文件夹里出现lib目录了,里面也有 plugin.js 文件,这次总不能再报错了吧。

重新打包,又报错了Cannot find module 'webpack/lib/RuleSet'啊啊啊气死了。

搜了一下,好像是node.js的版本太高,执行node -v看了一下node版本是v16.13.1,根据网上说法要把nodeJS的版本切换到12或者更低。又TM是版本问题!我之前以及现在已经经历了太多太多因为node和npm版本问题引发的报错了,抓狂!

我看到vue-losder的GitHub的Issues里面有人说安装vue-loader@15.9.7可以解决问题,我试了一下,出现了新的报错Error: Cannot find module 'webpack/lib/rules/DescriptionDataMatcherRulePlugin',在stackoverflow找到该报错的解决方式是把vue-loader更新一下:npm update vue-loader。更新后重新打包,打包成功并弹出了页面!(虽然执行的是update而且确实解决了问题,但其实我看见 package.json 里面 vue-loader 的版本依然是 15.9.7 没有变,所以 npm update 命令执行时究竟更新的什么?它究竟处理了什么来消除了这个让人懊恼的报错?这个待会再说)

打包成功并弹出了页面,但是可能刚刚复制粘贴进App.vue文件的代码有点语法错误问题,导致解析到<template>模板中的某一行时报错了,于是简单修改了一下。

修改完App.vue中所有可能存在的所有语句的格式错误后,页面又报了个错误:

1
2
3
4
5
Compiled with problems:X

ERROR in ./src/components/App.vue 23:14-28

Module not found: Error: Can't resolve 'vue' in 'C:\Users\10272\Desktop\webpack-study\src\components'

什么叫做没找到模块,无法解析App.vue?那我刚刚安装的vue-loadervue-template-compiler 没生效?

百思不得其解的时候,看到【解决vue-loader加载不上的问题】和【vue-loader】这两篇文章中都提到了,安装 vue-loader 也必须要下载vue,于是我执行 npm install vue -D 下载了,重新打包,页面弹出但再次报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Compiled with problems:

ERROR in ./src/components/App.vue

Module Error (from ./node_modules/vue-loader/lib/index.js):


Vue packages version mismatch:

- vue@3.2.31 (C:\Users\10272\Desktop\webpack-study\node_modules\vue\index.js)
- vue-template-compiler@2.6.14 (C:\Users\10272\Desktop\webpack-study\node_modules\vue-template-compiler\package.json)

This may cause things to work incorrectly. Make sure to use the same version for both.
If you are using vue-loader@>=10.0, simply update vue-template-compiler.
If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump vue-template-compiler to the latest.


ERROR in ./src/components/App.vue

Module build failed (from ./node_modules/vue-loader/lib/index.js):
TypeError: Cannot read properties of undefined (reading 'parseComponent')

原来是由于 vue@3.2.31vue-template-compiler@2.6.14 版本不相同。如果我的 vue-loader 版本大于等于10.0,简单地update一下vue-template-compiler就行了;如果我的 vue-loader 版本小于10.0,则重新安装 vue loader/vueify 前应将vue模板编译器vue-template-compiler升级到最新版本。

在 package-lock.json 中看了一下我vue-loader版本是"vue-loader": "^15.9.7",大于10.0,所以我只需执行 npm update vue-template-compiler 就行了。

然后重新npm run dev打包运行,还是报相同的错误,说 vue@3.2.31vue-template-compiler@2.6.14 版本不相同。因为好像npm update命令不改变 package-lock.json 的版本信息,也不知道这个更新命令是干啥的。

运行一下npm view vue-template-compiler versions看看有哪些版本:

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
npm view vue-template-compiler versions
[
'0.1.0', '2.0.0-alpha.1', '2.0.0-alpha.2', '2.0.0-alpha.3',
'2.0.0-alpha.4', '2.0.0-alpha.5', '2.0.0-alpha.6', '2.0.0-alpha.7',
'2.0.0-alpha.8', '2.0.0-beta.1', '2.0.0-beta.2', '2.0.0-beta.3',
'2.0.0-beta.4', '2.0.0-beta.5', '2.0.0-beta.6', '2.0.0-beta.7',
'2.0.0-beta.8', '2.0.0-rc.1', '2.0.0-rc.2', '2.0.0-rc.3',
'2.0.0-rc.4', '2.0.0-rc.5', '2.0.0-rc.6', '2.0.0-rc.7',
'2.0.0-rc.8', '2.0.0', '2.0.1', '2.0.2',
'2.0.3', '2.0.4', '2.0.5', '2.0.6',
'2.0.7', '2.0.8', '2.1.0', '2.1.1',
'2.1.2', '2.1.3', '2.1.4', '2.1.5',
'2.1.6', '2.1.7', '2.1.8', '2.1.9',
'2.1.10', '2.2.0-beta.1', '2.2.0-beta.2', '2.2.0',
'2.2.1', '2.2.2', '2.2.3', '2.2.4',
'2.2.5', '2.2.6', '2.3.0-beta.1', '2.3.0',
'2.3.1', '2.3.2', '2.3.3', '2.3.4',
'2.4.0', '2.4.1', '2.4.2', '2.4.3',
'2.4.4', '2.5.0', '2.5.1', '2.5.2',
'2.5.3', '2.5.4', '2.5.5', '2.5.6',
'2.5.7', '2.5.8', '2.5.9', '2.5.10',
'2.5.11', '2.5.12', '2.5.13', '2.5.14',
'2.5.15', '2.5.16', '2.5.17-beta.0', '2.5.17',
'2.5.18-beta.0', '2.5.18', '2.5.19', '2.5.20',
'2.5.21', '2.5.22', '2.6.0-beta.1', '2.6.0-beta.2',
'2.6.0-beta.3', '2.6.0', '2.6.1', '2.6.2',
'2.6.3', '2.6.4', '2.6.5', '2.6.6',
'2.6.7', '2.6.8', '2.6.9', '2.6.10',
'2.6.11', '2.6.12', '2.6.13', '2.6.14'
]

它也没有vue@3.2.31相同的版本呀,那我把 vue 降级吧,降成和 vue-template-compiler 一样的 2.6.14。不过得先 npm view vue versions 看一下有没有这个版本:

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
npm view vue versions                  
[
'0.0.0', '0.6.0', '0.7.0',
'0.7.1', '0.7.3', '0.7.4',
'0.7.5', '0.7.6', '0.8.0',
'0.8.1', '0.8.2', '0.8.3',
'0.8.4', '0.8.6', '0.8.7',
'0.8.8', '0.9.0', '0.9.1',
'0.9.2', '0.9.3', '0.10.0',
'0.10.1', '0.10.2', '0.10.3',
'0.10.4', '0.10.5', '0.10.6',
'0.11.0-rc', '0.11.0-rc2', '0.11.0-rc3',
'0.11.0', '0.11.1', '0.11.2',
'0.11.3', '0.11.4', '0.11.5',
'0.11.6', '0.11.7', '0.11.8',
'0.11.9', '0.11.10', '0.12.0-beta1',
'0.12.0-beta2', '0.12.0-beta3', '0.12.0-beta4',
'0.12.0-beta5', '0.12.0-csp', '0.12.0-rc',
'0.12.0-rc2', '0.12.0', '0.12.1-csp',
'0.12.1-csp.1', '0.12.1-csp.2', '0.12.1',
'0.12.2', '0.12.3', '0.12.4',
'0.12.5-csp', '0.12.5', '0.12.6-csp',
'0.12.6', '0.12.7-csp', '0.12.7',
'0.12.8-csp', '0.12.8', '0.12.9-csp',
'0.12.9', '0.12.10-csp', '0.12.10',
'0.12.11-csp', '0.12.11', '0.12.12-csp',
'0.12.12', '0.12.13-csp', '0.12.13',
'0.12.14-csp', '0.12.14', '0.12.15-csp',
'0.12.15', '0.12.16-csp', '0.12.16',
'1.0.0-alpha.1', '1.0.0-alpha.2', '1.0.0-alpha.3',
'1.0.0-alpha.4', '1.0.0-alpha.5', '1.0.0-alpha.6',
'1.0.0-alpha.7', '1.0.0-alpha.8', '1.0.0-beta.1',
'1.0.0-beta.2', '1.0.0-beta.3', '1.0.0-beta.4',
'1.0.0-csp', '1.0.0-migration', '1.0.0-rc.1',
'1.0.0-rc.2', '1.0.0-rc.2-migration', '1.0.0',
'1.0.1', '1.0.2', '1.0.3',
'1.0.4', '1.0.5', '1.0.6',
'1.0.7', '1.0.8', '1.0.9',
'1.0.10-csp', '1.0.10', '1.0.11-csp',
'1.0.11', '1.0.12-csp', '1.0.12-csp-1',
'1.0.12', '1.0.13-csp', '1.0.13',
'1.0.14-csp', '1.0.14', '1.0.15-csp',
'1.0.15', '1.0.16-csp', '1.0.16',
'1.0.17-csp', '1.0.17', '1.0.18-csp',
'1.0.18', '1.0.19-csp', '1.0.19',
'1.0.20-csp', '1.0.20', '1.0.21-csp',
'1.0.21', '1.0.22-csp', '1.0.22',
'1.0.23-csp', '1.0.23', '1.0.24-csp',
'1.0.24', '1.0.25-csp', '1.0.25',
'1.0.26-csp', '1.0.26', '1.0.27-csp',
'1.0.27', '1.0.28-csp', '1.0.28',
'2.0.0-alpha.1', '2.0.0-alpha.2', '2.0.0-alpha.3',
'2.0.0-alpha.4', '2.0.0-alpha.5', '2.0.0-alpha.6',
'2.0.0-alpha.7', '2.0.0-alpha.8', '2.0.0-beta.1',
'2.0.0-beta.2', '2.0.0-beta.3', '2.0.0-beta.4',
'2.0.0-beta.5', '2.0.0-beta.6', '2.0.0-beta.7',
'2.0.0-beta.8', '2.0.0-rc.1', '2.0.0-rc.2',
'2.0.0-rc.3', '2.0.0-rc.4', '2.0.0-rc.5',
'2.0.0-rc.6', '2.0.0-rc.7', '2.0.0-rc.8',
'2.0.0', '2.0.1', '2.0.2',
'2.0.3', '2.0.4', '2.0.5',
'2.0.6', '2.0.7', '2.0.8',
'2.1.0', '2.1.1', '2.1.2',
'2.1.3', '2.1.4', '2.1.5',
'2.1.6', '2.1.7', '2.1.8',
'2.1.9', '2.1.10', '2.2.0-beta.1',
'2.2.0-beta.2', '2.2.0', '2.2.1',
'2.2.2', '2.2.3', '2.2.4',
'2.2.5', '2.2.6', '2.3.0-beta.1',
'2.3.0', '2.3.1', '2.3.2',
'2.3.3', '2.3.4', '2.4.0',
'2.4.1', '2.4.2', '2.4.3',
'2.4.4', '2.5.0', '2.5.1',
'2.5.2', '2.5.3', '2.5.4',
'2.5.5', '2.5.6', '2.5.7',
'2.5.8', '2.5.9', '2.5.10',
'2.5.11', '2.5.12', '2.5.13',
'2.5.14', '2.5.15', '2.5.16',
'2.5.17-beta.0', '2.5.17', '2.5.18-beta.0',
'2.5.18', '2.5.19', '2.5.20',
'2.5.21', '2.5.22', '2.6.0-beta.1',
'2.6.0-beta.2', '2.6.0-beta.3', '2.6.0',
'2.6.1', '2.6.2', '2.6.3',
'2.6.4', '2.6.5', '2.6.6',
'2.6.7', '2.6.8', '2.6.9',
'2.6.10', '2.6.11', '2.6.12',
'2.6.13', '2.6.14', '3.0.0-alpha.0',
'3.0.0-alpha.1', '3.0.0-alpha.2', '3.0.0-alpha.3',
'3.0.0-alpha.4', '3.0.0-alpha.5', '3.0.0-alpha.6',
'3.0.0-alpha.7', '3.0.0-alpha.8', '3.0.0-alpha.9',
'3.0.0-alpha.10', '3.0.0-alpha.11', '3.0.0-alpha.12',
'3.0.0-alpha.13', '3.0.0-beta.1', '3.0.0-beta.2',
'3.0.0-beta.3', '3.0.0-beta.4', '3.0.0-beta.5',
'3.0.0-beta.6', '3.0.0-beta.7', '3.0.0-beta.8',
'3.0.0-beta.9', '3.0.0-beta.10', '3.0.0-beta.11',
'3.0.0-beta.12', '3.0.0-beta.13', '3.0.0-beta.14',
'3.0.0-beta.15', '3.0.0-beta.16', '3.0.0-beta.17',
'3.0.0-beta.18', '3.0.0-beta.19', '3.0.0-beta.20',
'3.0.0-beta.21', '3.0.0-beta.22', '3.0.0-beta.23',
'3.0.0-beta.24', '3.0.0-rc.1', '3.0.0-rc.2',
'3.0.0-rc.3', '3.0.0-rc.4', '3.0.0-rc.5',
'3.0.0-rc.6', '3.0.0-rc.7', '3.0.0-rc.8',
'3.0.0-rc.9', '3.0.0-rc.10', '3.0.0-rc.11',
'3.0.0-rc.12', '3.0.0-rc.13', '3.0.0',
'3.0.1', '3.0.2', '3.0.3',
'3.0.4', '3.0.5', '3.0.6',
'3.0.7', '3.0.8', '3.0.9',
'3.0.10', '3.0.11', '3.1.0-beta.1',
'3.1.0-beta.2', '3.1.0-beta.3', '3.1.0-beta.4',
'3.1.0-beta.5', '3.1.0-beta.6', '3.1.0-beta.7',
'3.1.0', '3.1.1', '3.1.2',
'3.1.3', '3.1.4', '3.1.5',
'3.2.0-beta.1', '3.2.0-beta.2', '3.2.0-beta.3',
'3.2.0-beta.4', '3.2.0-beta.5', '3.2.0-beta.6',
'3.2.0-beta.7', '3.2.0-beta.8', '3.2.0',
'3.2.1', '3.2.2', '3.2.3',
'3.2.4', '3.2.5', '3.2.6',
'3.2.7', '3.2.8', '3.2.9',
'3.2.10', '3.2.11', '3.2.12',
'3.2.13', '3.2.14', '3.2.15',
'3.2.16', '3.2.17', '3.2.18',
'3.2.19', '3.2.20', '3.2.21',
'3.2.22', '3.2.23', '3.2.24',
'3.2.25', '3.2.26', '3.2.27',
'3.2.28', '3.2.29', '3.2.30',
'3.2.31'
]

可以看到有,那就执行 npm i vue@2.6.14 -D,重新npm run dev打包生成。

卧槽卧槽卧槽卧槽成功了,页面成功弹出来且没有报错!!!

我因为这个报错耽误了一下午和一晚上,现在的心情好爽!深呼一口气…

幸亏解决了,再不解决我就气出高血压并把头发都愁掉了。

至此,package-lock.json中npm包的版本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"devDependencies": {
"@babel/core": "^7.17.9",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@babel/runtime": "^7.17.9",
"autoprefixer": "^10.4.4",
"babel-loader": "^8.2.4",
"css-loader": "^6.7.1",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"node-sass": "^7.0.1",
"postcss-loader": "^6.2.1",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"vue": "^2.6.14",
"vue-loader": "^15.9.7",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"

现在探究一下上面那个咱们保留的疑问:使用npm update命令更新vue-loader依赖包后,package.json中devDependencies里对应包的版本号为什么不变?究竟有没有更新?如果没有,那又为什么能解决我安装完vue-loader@15.9.7重新 npm run dev 打包时出现的Error: Cannot find module 'webpack/lib/rules/DescriptionDataMatcherRulePlugin'这个报错?搜到了知乎的一篇文章,其中提到:

  • npm install与npm update 两者最大的区别是在对待已经安装过的模糊版本时候:
    1. npm install会忽略模糊版本
    2. npm update会更新模糊版本至最新
  • 除此之外, install and update 处理 devDependencies 方式也不同:
    1. npm install会安装/更新 devDependencies,除非你指定 –production 标志
    2. npm update会忽略 devDependencies,除非你指定 –dev 标志

所以说,执行npm update之后确实是更新了,只不过没有在package.json修改版本号?那为啥我直接npm install安装的最新的vue-loader@17.0.0版本不能用,把旧版本vue-loader@15.9.7用npm update更新到最新就能用且不报错了呢?实在想不通,在这里先挖个坑,以后有时间或者在遇到的时候再回来补充,或者到时候单独写一篇文章仔细分析一下。

4. 在webpack项目中使用vue

  1. 运行 npm i vue –S 安装 vue(上面刚刚安装过了)
  2. src -> index.js 入口文件中,通过 import Vue from 'vue' 来导入 vue 构造函数
  3. 创建 vue 的实例对象,并指定要控制的 el 区域
  4. 通过 render 函数渲染 App 根组件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 1. 导入 Vue 构造函数
    import Vue from 'vue'
    // 2. 导入 App 根组件
    import App from './components/App.vue'

    const vm = new Vue({
    // 3. 指定 vm 实例要控制的页面区域
    el: '#app',
    // 4. 通过 render 函数,把指定的组件渲染到 el 区域中
    render: h => h(App)
    })

格外注意一下render函数,我们之前可能没有用过,今后再webpack项目中尽量都是用render函数来渲染指定的组件。像其他的component以及template在这里尽量都不要用了。因为在webpack中使用Vue的时候,它导入的Vue并不是最全的版本的Vue,而是一个阉割版的Vue,它只支持使用render函数来渲染组件,不支持componenttemplate属性。

5. webpack的打包发布

上线之前需要通过webpack将应用进行整体打包,可以通过 package.json 文件配置打包命令:

1
2
3
4
5
6
7
8
// 在package.json文件中配置 webpack 打包命令
// 该命令默认加载项目根目录中的 webpack.config.js 配置文件
"scripts": {
// 用于开发调试的命令
"dev": "webpack-dev-server --open --host 127.0.0.1 --port 8888",
// 用于打包的命令
"build": "webpack -p" // -p参数会在打包前读取打包配置
},

执行npm run build命令打包前,dist目录可以整个先删掉,一会还会自动生成的。

打包时报了错:

1
2
3
4
5
6
7
npm run build

> webpack-study@1.0.0 build
> webpack -p

[webpack-cli] Error: Unknown option '-p'
[webpack-cli] Run 'webpack --help' to see available commands and options

那还是把参数-p去掉吧,重新npm run build,打包成功。

项目根文件夹中多了一个dist文件夹,里面有imgbundle.jsindex.html。这个生成的dist目录就是一个成品的项目了,咱们把它交给后台开发人员,让他进行实际的上线,比如发配到服务器上进行外网公布等等操作。


【Vue脚手架】

1. Vue 脚手架的基本用法

Vue 脚手架用于快速生成 Vue 项目基础架构,其官网地址为:https://cli.vuejs.org/zh/

它是一个命令行工具,可以让我们通过执行命令的形式快速生成Vue项目的基础架构。以前我们必须手动搭建webpack项目,手动去配置Vue。现在有了脚手架之后,我们可以直接通过命令行的方式快速生成Vue项目结构,简化项目创建流程,上来就可以写代码,而不用关心项目是怎么创建出来的。

(1) 安装@vue/cli

打开cmd命令行,全局安装 3.x 版本的 Vue 脚手架:

1
npm install -g @vue/cli

现在主流的版本是2.x3.x,推荐使用后者,因为3.x版本也能创建2.x版本的项目。

安装过程耐心等待,完成后可以运行vue -V命令检查是否安装完成,并查看版本号,我的返回的是@vue/cli 5.0.4,说明在计算机上安装成功。

(2) 基于3.x版本脚手架创建vue项目

有三种方式,前两种一定要掌握,是市面上用的最多的两个方式。

最后一种了解就行,它是根据2.x旧模板创建旧的vue项目的。

1
2
3
4
5
6
7
8
9
# 1. 基于 交互式命令行 的方式,创建 新版 vue项目(项目名称要是英文,并且不要写特殊符号)
vue create my-project

# 2. 基于 图形化界面 的方式,创建 新版 vue项目
vue ui

# 3. 基于 2.x 的旧模板,创建 旧版 vue项目
npm install -g @vue/cli-init
vue init webpack my-project

》第一种创建方式(命令行)

打开cmd,基于交互式命令行创建新版vue项目

1
2
# 1. 基于 交互式命令行 的方式,创建 新版 vue项目(项目名称要是英文,并且不要写特殊符号)
vue create vue_proj_01

此时他会提供一个交互式的问答面板,来询问我们安装哪些功能。

1
2
3
4
5
6
Vue CLI v5.0.4
Failed to check for updates
? Please pick a preset: (Use arrow keys)
> Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
Manually select features

我们可以通过上下键选择通过默认方式(Default)创建项目,还是手动选择功能(Manually)然后再创建项目。

推荐使用手动方式选择某些功能,选中最下面那行回车,此时出现新面板,让我们选择安装哪些功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Vue CLI v5.0.4
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and
<enter> to proceed)
>(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
( ) Vuex
( ) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing

比如可以通过上下箭头选中Router,单击一下空格就可以给它打一个星号。星号代表安装,空白代表不安装。继续回车进入下一个面板:

1
2
3
4
5
6
7
Vue CLI v5.0.4
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with (Use arrow keys)
> 3.x
2.x

可以选中2.x版本的Vue项目,回车。

1
2
3
4
5
6
Vue CLI v5.0.4
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n)

这时询问我们是否安装历史模式的路由?(需要为生产中的索引回退进行适当的服务器设置)(是/否)

推荐使用哈希模式(hash)的,所以我们要安装的是哈希模式的路由,而不是历史模式的路由。

所以我们输入n选择否,回车。此时又让我们选择 ESLint 它的语法版本:

1
2
3
4
5
6
7
8
9
10
11
Vue CLI v5.0.4
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a linter / formatter config: (Use arrow keys)
> ESLint with error prevention only
ESLint + Airbnb config
ESLint + Standard config
ESLint + Prettier

推荐选择 Standard config 模式的标准类型的 ESLint ,选中之后回车。

这时候问我们什么时候进行 ESLint 语法规则的校验,我们默认选择第一项Lint on save就行,回车。

1
2
3
4
5
6
7
8
9
10
11
Vue CLI v5.0.4
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a linter / formatter config: Standard
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to pr
oceed)
>(*) Lint on save
( ) Lint and fix on commit

这时候进入新面板,询问我们 Babel, ESLint 等工具的配置文件放置在哪里?

第一种是创建单独的专用配置文件,第二种是把这些工具的配置文件统一的都放到 package.json 中。

1
2
3
4
5
6
7
8
9
10
11
Vue CLI v5.0.4
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
In package.json

推荐选择第一个,各工具配置文件放在单独的文件中,因为这样好维护,保证 package.json 中结构清晰,不容易混乱。

选择后回车,现在询问我们,是否把当前已经做过的选择保存成模板,供后续再创建项目时快速搭建。可以选择 Y 创建模板,也可以选择 N 不保留为模板。

1
2
3
4
5
6
7
8
9
10
Vue CLI v5.0.4
Failed to check for updates
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N)

我选择 N 不保存模板,回车,稍等片刻,待它创建项目、初始化仓库,以及安装完CLI的插件等。

1
2
3
4
5
Vue CLI v5.0.4
Failed to check for updates
✨ Creating project in C:\Users\10272\vue_proj_01.
🗃 Initializing git repository...
⚙️ Installing CLI plugins. This might take a while...

安装完成后如下:

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
Vue CLI v5.0.4
Failed to check for updates
✨ Creating project in C:\Users\10272\vue_proj_01.
🗃 Initializing git repository...
⚙️ Installing CLI plugins. This might take a while...


added 842 packages, and audited 843 packages in 3m

82 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities
🚀 Invoking generators...
📦 Installing additional dependencies...


added 146 packages, and audited 989 packages in 30s

119 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities
⚓ Running completion hooks...

📄 Generating README.md...

🎉 Successfully created project vue_proj_01.
👉 Get started with the following commands:

$ cd vue_proj_01
$ npm run serve

它提示我们 cd vue_proj_01 进入项目根目录中,然后运行 npm run serve 把项目跑起来。执行后,会进行webpack的编译:

1
2
3
4
> vue_proj_01@0.1.0 serve
> vue-cli-service serve

INFO Starting development server...

编译完成后,弹出一个新面板,我们可以选择对应的地址,然后打开浏览器,就能够看到创建出来的项目效果了。

1
2
3
4
5
6
7
8
9
DONE  Compiled successfully in 21785ms


App running at:
- Local: http://localhost:8080/
- Network: http://你的硬件IPV4地址:8080/

Note that the development build is not optimized.
To create a production build, run npm run build.

》第二种创建方式(图形化)

第一种了解一下就可以,采用第二种图形化界面的创建方式,可视化更强也更方便。

打开cmd,输入下面命令,打开一个浏览器面板:

1
2
# 2. 基于 图形化界面 的方式,创建 新版 vue项目
vue ui

点击创建,进入项目的创建面板。这时弹出目录选择框,我们可以选择要创建项目的路径。

挑选完路径,点击按钮在此创建新项目,进入“创建新项目”页面中。

  • 在详情面板中:

    • 填写“项目文件夹”的名称(如:vue_proj_02),注意要合法,不要写中文或特殊字符。
    • 选择“包管理器”(包括npm、yarn、pnpm),选择默认的就好。
    • 下面“更多选项”,默认的就好。
    • 最后“Git仓储”,它已经默认开启了,我们填写一个初始的提交信息,比如init project
    • 点击下一步。
  • 在预设面板中:

    • 它询问我们是否进行相关的配置,我们可以选择默认配置,或者手动配置,或者用以前配置过并保存的模板。
    • 第一次推荐选择手动,点击下一步。
  • 在功能面板中:

    • 推荐大家一定要安装Babel,并把它那一项开启。
    • 然后一定要安装Router路由,把它那一项开启。
    • 下面Vuex可以先不安装,之后用到了再开启。
    • 在下面,把Linter/Formatter开启。
    • 最后,把使用配置文件这一项打开,这样那些配置工具会单独保存到为它创建的专用文件中,而不是全部都统一的放到package.json里,因为那样不好。
    • 点击下一步。
  • 在配置面板中:

    • 挑选Vue版本,默认3.x
    • 询问我们是否使用历史模式的路由,这一项不用管,默认关闭就行。
    • 接下来选择Linter/Formatter的配置文件,这里我们一定要选择标准版本的配置文件Standard config
    • 接下来选择lint features(何时进行 ESLint 语法规则的校验),默认打开Lint on save就可以;然后Lint and fix on commit这个选项默认关闭,我们也可以不用管。

      lint on save
      代码文件中有代码不符合 lint 规则时,会在 compile 阶段提示 warning。如果出现了语法错误,会直接在页面上显示 error
      lint and fix on commit
      代码除了语法错误导致的 error 外不会提示 warning。而是在当前项目进行 git commit 操作的时候,通过 githook,在 pre-commit 阶段执行 lint 和 fix 操作,自动帮我们把有语法错误的地方修改为符合规范。

    • 点击“创建项目”,弹出窗口询问我们是否把刚刚的配置保存为新预设(模板)。可以起个名字比如my_preset_01,点击保存预设并创建项目

      命令行窗口提示我们该预设会保存在Preset my_preset_01 saved in C:\Users\10272\.vuerc
      保存预设的进程可能很慢或者卡住,耐心等待不要动。

当项目创建成功后,浏览器自动跳转到仪表盘面板(dashboard)。

  • 在仪表盘中:
    • 左边菜单侧栏的最上面,点击下拉菜单的“Vue项目管理器”,可以看到总共用这个Vue可视化面板创建了多少个项目,并可以切换。
    • 点击侧边栏的插件选项,可以看到当前项目安装了多少插件,并能够新增和删除。
    • 点击侧边栏的依赖选项,可以看到当前项目安装了多少依赖包,同时可以安装依赖、卸载依赖。
    • 点击侧边栏的配置选项,可以看到提供了相关的配置选项,比如配置Vue项目的CLI和代码纠错的ESLint configuration
    • 点击侧边栏的任务选项,可以看到提供了serve命令、build命令、以及lintinspect命令。serve常用来实现开发期间的打包和运行,build是用来把项目打包为成品去上线时用的。

我们可以选中serve任务,点击运行,等它编译成功后就可以进行项目的开发与调试。运行成功时,点击面板上控制台里的启动app按钮,就可以看到弹出来的项目页面了,非常方便。点击停止,可以结束运行。点击面板上的输出按钮,还可以看到它输出的一些信息。

》第三种创建方式(旧模板)

第三种方法是基于 2.x 的旧模板,创建旧版vue项目。

有个前提条件是全局安装@vue/cli-init这个工具,只有装了这个插件,我们才能基于 2.x 的旧命令来创建一个旧版的Vue项目。

1
npm install -g @vue/cli-init

现在就可以创建旧版项目了:

1
2
# 3. 基于 2.x 的旧模板,创建 旧版 vue项目(请保证项目名称合法)
vue init webpack my-project

运行后等待它下载对应模板(downloading template),下载完成后,它和第一种方法差不多,也是通过一个问答形式的窗口来进行相关的配置。

它首先询问我们项目名称是什么,并且已经给了我们一个默认名称vue_proj_03,我们直接回车就可以。

1
Project name (vue_proj_03)

项目的描述,小括号里也有默认值,我们直接回车:

1
2
Project name vue_proj_03
Project description (A Vue.js project)

再然后让我们填写作者,我们随便输入个就行:

1
2
3
Project name vue_proj_03
Project description A Vue.js project
Author #比如输入itcast,然后回车

接下来询问我们安装哪个版本的Vue,第一个是Runtime + Compiler版本,这个版本是最全版本的Vue,体积比较大,不推荐;推荐安装第二个Runtime-only版本,就是我们所谓阉割版的Vue,它的体积会更小,实际开发中要使用这个。

下一步,询问是否安装vue-router,输入y确认安装路由,回车。

下一步,询问是否安装ESLint,输入y确认安装,它用来进行代码的校验,回车。

下一步,让我们选择ESLint的语法版本,我们选择 standard,也就是标准 ESLint,点击回车。

下一步,询问我们是否安装单元测试 unit tests ,咱们不安装,输入 n ,回车。

下一步,询问是否安装 e2e tests,咱们也不安装,输入 n ,回车。

最后,询问使用哪种方式安装项目依赖包。可以选择NPMYarn,或者先不装一会手动装。咱们选择NPM就行。

回车后,它会创建项目对应的结构并安装依赖项,我们耐心等待。安装完成后,提示我们:

1
2
cd vue_proj_03
npm run dev

执行后会进行webpack的打包编译,编译成功后提示我们项目运行在:

1
Your application is running here: http://localhost:8080

我们可以打开浏览器粘贴地址并回车,就能看到基于 2.x 旧版本的项目页面了。

2. Vue 脚手架生成的项目结构分析

  • 文件夹.git
  • 文件夹node_modules:依赖包目录
  • 文件夹public:静态资源目录(比如index.htmlfavicon.ico
  • 文件夹src:组件源码目录
    • 其中assets文件夹里是我们可能用到的资源,如样式表、图片等
    • 其中components文件夹里放着我们的.vue组件
    • 其中views文件夹里是相关的视图组件,也是.vue文件
    • 其中App.vue是项目的根组件
    • 其中main.js是项目的打包入口文件,里面导入了vue、根组件App.vue、路由router。然后new了一个Vue实例对象,把路由挂载上去了,通过render函数把根组件渲染到首页上去了。最后通过$mount方法把这个Vue实例挂载到了#app所在的区域中。
    • 其中router.js就不用说了,它是路由的配置文件
  • .browserslistrc
  • .editorconfig
  • .eslintrc.js:这是ESLint语法相关的配置文件
  • .gitinore:这是git的忽略文件
  • babel.config.js:Babel配置文件
  • jsconfig.json
  • package.json:项目的包管理配置文件
  • package-lock.json
  • postcss.config.js:可以配置一些前缀等之类的post css的插件
  • README.md
  • vue.config.js

3. Vue 脚手架的自定义配置

(1) 通过 package.json 配置项目

在VScode中打开我们刚刚创建的项目文件夹,新建终端执行npm run server命令打包,项目会成功运行在http://localhost:8080/,但是得手动复制粘贴,怎么配置自动弹出来呢?

package.json 文件的最后一个花括号前,添上下方代码就可以了,前面别忘了加逗号与上一个隔开:

1
2
3
4
5
6
7
// 必须是符合规范的json语法
"vue": {
"devServer": {
"port": "8888", //端口号
"open" : true //打包成功后自动运行浏览器
}
},

然后运行npm run server命令打包,应该会自动弹出网页,并且端口号变成了8888。

注意:不推荐使用这种配置方式。因为 package.json 主要用来管理包的配置信息;为了方便维护,推荐将 vue 脚手架相关的配置,单独定义到 vue.config.js 配置文件中。这样不同工具的配置文件单一一些,方便咱们后期维护。

然而,与网课视频中的不同,我的其实报错了,网页也没有弹出来:

1
2
3
4
5
6
 WARN  "vue" field in package.json ignored due to presence of vue.config.js.
WARN You should migrate it into vue.config.js and remove it from package.json.

# 翻译如下
# package.json中的“vue”字段,由于存在vue.config.js而被忽略
# 您应该将其迁移到vue.config.js中,并将其从package.json中删除

根据报错代码,它的意思也是让我不要在package.json里面写,而是到vue.config.js里面写。可能因为我用Vue-CLI生成的这个项目文件夹里,本身已经创建好了vue.config.js所以导致的报错吧。但我也不深究了,反正该配置方式不推荐。

(2) 通过单独的配置文件配置项目

如果使用这种配置方式,请把上面那种配置中添加在package.json里的代码删掉,两种配置方式只能二选一。

  1. 在项目的跟目录创建文件 vue.config.js(我用vue-cli创建的项目默认就有)
  2. 在该文件中进行相关配置,从而覆盖默认配置,然后npm run server就行了:
    1
    2
    3
    4
    5
    6
    7
    // vue.config.js
    module.exports = {
    devServer: {
    open: true, //自动弹出页面
    port: 8888 //端口号
    }
    }

由于我用vue-cli搭建的该项目文件夹中已经有vue.config.js了,并且其中的代码如下:

1
2
3
4
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
})

所以我只需把devServer字段添加进去,改成下面这样子就可以了:

1
2
3
4
5
6
7
8
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
open: true, //自动弹出页面
port: 8888 //端口号
}
})

但是这样虽然运行成功并弹出页面,可弹出的网址是0.0.0.0:8888/,而不是运行中的http://localhost:8888/,导致页面不能正常显示,所以还得手动在浏览器把0.0.0.0改成localhost,那我设置自动弹出干啥,不是脱了裤子放屁多此一举吗。

搜了一下,在上方代码中再添加一行代码就可以了:

1
2
3
4
5
6
7
8
9
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
open: true, //自动弹出页面
port: 8888, //端口号
host: 'localhost' //设置打开时的地址
}
})

但是,这样虽然运行成功,弹出了页面,地址确实是http://localhost:8888/,页面正常显示,但是网络地址也变得和本地地址一样了,全变成http://localhost:8888/,这可不行呀,我还得让其他设备通过局域网访问呐。

1
2
- Local:   http://localhost:8888/
- Network: http://localhost:8888/

看到有个CSDN博文说执行npm uninstall -g vue-cli把当前 vue-cli 卸载,然后npm install -g @vue/cli@4.5.15降级为 4.5.15 就行了。我的确实是@vue/cli 5.0.4版本,是比较高的最新版,但是除了降级就没有其他办法了吗?

有文章说在package.json的serve命令里加上--open参数,但是并没有什么卵用,弹出的还是0.0.0.0

1
2
3
4
5
"scripts": {
"serve": "vue-cli-service serve --open",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},

查看一下 Vue CLId 的官方文档,明确写着host默认值:0.0.0.0

1
2
3
4
5
6
7
8
9
10
用法:vue-cli-service serve [options] [entry]

选项:

--open 在服务器启动时打开浏览器
--copy 在服务器启动时将 URL 复制到剪切版
--mode 指定环境模式 (默认值:development)
--host 指定 host (默认值:0.0.0.0)
--port 指定 port (默认值:8080)
--https 使用 https (默认值:false)

但只要我一旦用host参数来指定localhost替换默认0.0.0.0,无论我是在package.json中加--host localhost参数,还是在vue.config.js中加host: localhost参数,都会导致Local和Network访问地址都变成http://localhost:8080/

那先算了,有空再研究自动打开吧,暂时先手动或者在vue ui仪表盘里通过点击按钮打开。


【Element-UI的基本使用】

但我看到已经出3.0版本的Element Plus了,

但Element Plus 目前还处于快速开发迭代中,想稳定点的的话推荐项目是vue2.x + Element-UI2.0

使用组件库的好处就是可以省去那些美化样式的时间,让前端程序员把更多的精力放在自己的业务逻辑上。

1. 基于命令行方式手动安装

注意:Element-UI是基于Vue 2.0的,所以最好是在vue 2.x的项目中安装。如果你当初创建时选的是3.x,那就重新创建个项目吧(用vue ui的图形化面板比较方便),否则可能报各种错误。或者你去安装支持Vue 3Element Plus

  1. 安装依赖包 npm i element-ui -S

    -save:模块名将被添加到dependencies,可以简化为参数-S
    -save-dev: 模块名将被添加到devDependencies,可以简化为参数-D

  2. 打开 src 里面的 main.js,也就是打包入口文件,导入 Element-UI 相关资源
    1
    2
    3
    4
    5
    6
    // 导入组件库,并接收这个成员对象
    import ElementUI from 'element-ui';
    // 导入组件相关样式(上面的只是UI结构,样式需要单独导入,否则页面就会变得很丑)
    import 'element-ui/lib/theme-chalk/index.css';
    // 配置 Vue 插件(使用Vue.use函数把ElementUI安装到Vue身上,每个组件中可以直接使用ElementUI提供的组件了)
    Vue.use(ElementUI);
  3. 从ElementUI官网复制一些样式代码,粘贴进App.vue根组件的div里,保存并打包,打开网页查看效果。

执行 npm i element-ui -S 的时候我的电脑发了一个警告,并报了9个严重性漏洞:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
npm WARN deprecated core-js@2.6.12: core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.

added 9 packages, and audited 991 packages in 25s

119 packages are looking for funding
run `npm fund` for details

9 high severity vulnerabilities

To address issues that do not require attention, run:
npm audit fix

To address all issues (including breaking changes), run:
npm audit fix --force

Run `npm audit` for details.

警告内容中文翻译:

弃用的 core-js@2.6.12:core-js@<3.4 不再维护,由于问题数量不推荐使用。 由于 V8 引擎的奇思妙想,旧 core-js 版本中的功能检测可能会导致速度下降高达 100 倍,即使没有填充任何内容。 请将您的依赖项升级到 core-js 的实际版本。

但我看了下,package-lock.json 文件中packages记录的core-js包的版本是"core-js": "^3.8.3",这就很莫名其妙了,明明高于3.4为什么还报错呢。全局搜索了一下,"node_modules/babel-runtime/node_modules/core-js"中的版本记录的是"version":"2.6.12",所以是因为这东西吧。

那我执行npm update core-js -D升级一下吧,然后又报了相同的错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
up to date, audited 991 packages in 14s

119 packages are looking for funding
run `npm fund` for details

9 high severity vulnerabilities

To address issues that do not require attention, run:
npm audit fix

To address all issues possible (including breaking changes), run:
npm audit fix --force

Some issues need review, and may require choosing
a different dependency.

Run `npm audit` for details.

中文翻译如下:

1
2
3
4
5
6
7
8
9
10
11
12
9个高危漏洞

要解决不需要注意的问题,请运行:
npm 审计修复

要解决所有可能的问题(包括重大更改),请运行:
npm 审计修复 --force

有些问题需要审查,可能需要选择
不同的依赖。

运行 `npm audit` 以获取详细信息。

那行,我运行npm audit获取了如下信息:

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
# npm audit report

async <3.2.2
Severity: high
Prototype Pollution in async - https://github.com/advisories/GHSA-fwr7-v2mv-hh25
fix available via `npm audit fix --force`
Will install @vue/cli-plugin-babel@3.12.1, which is a breaking change
node_modules/async
portfinder 0.1.0 || >=0.4.0
Depends on vulnerable versions of async
node_modules/portfinder
@vue/cli-service *
Depends on vulnerable versions of @vue/cli-plugin-vuex
Depends on vulnerable versions of portfinder
node_modules/@vue/cli-service
@vue/cli-plugin-babel >=4.0.0-alpha.0
Depends on vulnerable versions of @vue/cli-service
node_modules/@vue/cli-plugin-babel
@vue/cli-plugin-eslint >=4.0.0-alpha.0
Depends on vulnerable versions of @vue/cli-service
node_modules/@vue/cli-plugin-eslint
@vue/cli-plugin-router *
Depends on vulnerable versions of @vue/cli-service
node_modules/@vue/cli-plugin-router
@vue/cli-plugin-vuex *
Depends on vulnerable versions of @vue/cli-service
node_modules/@vue/cli-plugin-vuex
@vue/eslint-config-standard >=5.1.1
Depends on vulnerable versions of @vue/cli-service
node_modules/@vue/eslint-config-standard
webpack-dev-server >=2.0.0-beta
Depends on vulnerable versions of portfinder
node_modules/webpack-dev-server

9 high severity vulnerabilities

To address issues that do not require attention, run:
npm audit fix

To address all issues possible (including breaking changes), run:
npm audit fix --force

Some issues need review, and may require choosing
a different dependency.

找到一篇博文,说按顺序执行这三行代码可以解决:

1
2
3
npm audit fix
npm audit fix --force
npm audit

当我执行了第一句的npm audit fix,直接出现一堆红色报错吓死我了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: vue_proj_03@0.1.0
npm ERR! Found: eslint-plugin-vue@8.6.0
npm ERR! node_modules/eslint-plugin-vue
npm ERR! dev eslint-plugin-vue@"^8.0.3" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer eslint-plugin-vue@"^7.0.0" from @vue/eslint-config-standard@6.1.0
npm ERR! node_modules/@vue/eslint-config-standard
npm ERR! dev @vue/eslint-config-standard@"^6.1.0" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See C:\Users\10272\AppData\Local\npm-cache\eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\10272\AppData\Local\npm-cache\_logs\2022-04-13T09_45_13_055Z-debug.log

接着执行npm audit fix –force`,结果又出来一堆黄色警告:

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
npm WARN using --force Recommended protections disabled.
npm WARN audit Updating @vue/cli-service to 5.1.0,which is a SemVer major change.
npm WARN audit Updating @vue/cli-plugin-babel to 3.12.1,which is a SemVer major change.
npm WARN audit Updating @vue/cli-plugin-router to 5.1.0,which is a SemVer major change.
npm WARN audit Updating @vue/eslint-config-standard to 5.1.0,which is a SemVer major change.
npm WARN audit Updating @vue/cli-plugin-eslint to 3.12.1,which is a SemVer major change.
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated request-promise-native@1.0.9: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142
npm WARN deprecated @hapi/bourne@1.3.2: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated chokidar@2.1.8: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated eslint-loader@2.2.1: This loader has been deprecated. Please use eslint-webpack-plugin
npm WARN deprecated @hapi/topo@3.1.6: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated eslint-plugin-standard@5.0.0: standard 16.0.0 and eslint-config-standard 16.0.0 no longer require the eslint-plugin-standard package. You can remove it from your dependencies with 'npm rm eslint-plugin-standard'. More info here: https://github.com/standard/standard/issues/1316
npm WARN deprecated circular-json@0.3.3: CircularJSON is in maintenance only, flatted is its successor.
npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm WARN deprecated @hapi/address@2.1.4: Moved to 'npm install @sideway/address'
npm WARN deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated babel-eslint@10.1.0: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.
npm WARN deprecated @hapi/hoek@8.5.1: This version has been deprecated and is no longer supported or maintained
npm WARN deprecated @hapi/joi@15.1.1: Switch to 'npm install joi'
npm WARN deprecated core-js@2.6.12: core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.
npm WARN deprecated core-js@2.6.12: core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.

added 412 packages, removed 490 packages, changed 68 packages, and audited 913 packages in 2m

68 packages are looking for funding
run `npm fund` for details

# npm audit report

ajv <6.12.3
Severity: moderate
Prototype Pollution in Ajv - https://github.com/advisories/GHSA-v88g-cgmw-v5xw
fix available via `npm audit fix --force`
Will install @vue/cli-plugin-eslint@5.0.4, which is a breaking change
node_modules/@vue/cli-plugin-eslint/node_modules/ajv
ajv-keywords 2.1.1
Depends on vulnerable versions of ajv
node_modules/@vue/cli-plugin-eslint/node_modules/ajv-keywords
eslint 2.5.0 - 2.5.2 || 4.2.0 - 5.0.0-rc.0
Depends on vulnerable versions of ajv
Depends on vulnerable versions of table
node_modules/@vue/cli-plugin-eslint/node_modules/eslint
@vue/cli-plugin-eslint <=5.0.0-rc.3
Depends on vulnerable versions of eslint
Depends on vulnerable versions of globby
node_modules/@vue/cli-plugin-eslint
table 3.7.10 - 4.0.2
Depends on vulnerable versions of ajv
node_modules/@vue/cli-plugin-eslint/node_modules/table

glob-parent <5.1.2
Severity: high
Regular expression denial of service in glob-parent - https://github.com/advisories/GHSA-ww39-953v-wcq6
fix available via `npm audit fix --force`
Will install @vue/cli-plugin-eslint@5.0.4, which is a breaking change
node_modules/glob-parent
chokidar 1.0.0-rc1 - 2.1.8
Depends on vulnerable versions of glob-parent
node_modules/watchpack-chokidar2/node_modules/chokidar
watchpack-chokidar2 *
Depends on vulnerable versions of chokidar
node_modules/watchpack-chokidar2
watchpack 1.7.2 - 1.7.5
Depends on vulnerable versions of watchpack-chokidar2
node_modules/watchpack
webpack 4.44.0 - 4.46.0
Depends on vulnerable versions of watchpack
node_modules/webpack
fast-glob <=2.2.7
Depends on vulnerable versions of glob-parent
node_modules/fast-glob
globby 8.0.0 - 9.2.0
Depends on vulnerable versions of fast-glob
node_modules/globby
@vue/cli-plugin-eslint <=5.0.0-rc.3
Depends on vulnerable versions of eslint
Depends on vulnerable versions of globby
node_modules/@vue/cli-plugin-eslint

12 vulnerabilities (4 moderate, 8 high)

To address issues that do not require attention, run:
npm audit fix

To address all issues (including breaking changes), run:
npm audit fix --force

又是一顿疯狂无效搜索,最后也没找到解决方法,只收到没完没了的警告与报错。TMD烦死啦,怎么天天都是版本问题的报错,想吐,真的想吐!不管啦,爱咋样咋样,开始摆烂,你报你的错,我继续做我的项目……还有后面那9个高危漏洞,执行完npm audit fix --force审计修复后变成 12 个漏洞(4 个中等,8 个高),有病是不是,爱咋地咋地,去你大爷的……草

卧槽,现在我打包命令都没法执行了:

1
2
3
4
5
6
7
PS C:\Users\10272\vue_proj_03> npm run serve

> vue_proj_03@0.1.0 serve
> vue-cli-service serve

'vue-cli-service' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

草草草淦淦淦艹艹艹血压上来了…..

重新创建项目吧,日它奶奶,我这么有修养的人,竟然把我逼得在博文里开骂…..

2. 基于图形化界面自动安装

因为用上面那个命令行安装 Element-UI ,我的项目已经废了,打包命令都不管用。所以不得不打开 vue ui 快速通过之前保存的模板又创建了一个2.x的新项目。来吧,继续安装Element-UI,不过这次采用图形化的方式。

你也需要创建一个新的2.x项目。

  1. 运行 vue ui 命令,打开图形化界面
  2. 点开下拉菜单 Vue 项目管理器,进入具体的项目配置面板,创建2.x新项目
  3. 创建成功后,点击 任务 -> 启动 -> 启动App
  4. 点击 插件 -> 添加插件,进入插件查询面板
  5. 搜索 vue-cli-plugin-element ,单击选中,点击右下角安装
  6. 配置插件:
    • How do you want to import Element?(如何导入?)
      Fully inport完整引入/Import on demand按需引入
      选择后者,实现按需导入,只导入用到的组件,从而减少打包后项目的体积
    • Do you wish to overwrite Element’s SCSS variables?(是否要覆盖元素的SCSS变量?)
      这一项问的是关于重载样式为SCSS的,根据自己的需求来进行选择
      当第一项选完“按需导入”后,该选项会隐藏,我们就不用管了
    • Choose the locale you want to load(选择要加载的区域设置)
      这一选项让我们选择本地化的设置是什么
      我们就默认安装zh-CN中国语言的Element-UI就行了
    • 点击“完成安装”按钮,这时它会根据我们刚刚的选项对element插件进行配置。
      其实我看见命令窗口有高危漏洞的警报,但经历了上面的事,我不敢管了:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      4 high severity vulnerabilities

      To address issues that do not require attention, run:
      npm audit fix

      Some issues need review, and may require choosing
      a different dependency.

      Run `npm audit` for details.
    • 耐心等待,进程运行完后,点击继续按钮,我们就完成了vue-cli-plugin-element这个插件的配置。

现在选择“任务”菜单,我们把运行中的项目停止掉。

然后重新运行一下,我们要进行重新打包的过程,编译成功就说明期间没有报错。

用VScode打开项目文件夹,选择src目录下的main.js

  • 可以看到,在入口文件的第四行,我们用import语法导入了当前目录下plugins里面的element.js文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // main.js文件内
    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    import './plugins/element.js'

    Vue.config.productionTip = false

    new Vue({
    router,
    render: h => h(App)
    }).$mount('#app')
  • 这个被导入的element.js就是我们Element-UI中的一些插件,可以看到它里面按需导入的Button这个组件,把Button注册为了Vue的组件文件,这样我们在每个组件中都可以使用button按钮了:

    1
    2
    3
    4
    5
    // element.js文件内
    import Vue from 'vue'
    import { Button } from 'element-ui'

    Vue.use(Button)
  • 打开项目根组件App.vue,打开Element官网中随便一个组件,比如按钮,复制过来一坨代码到App.vue根组件的<div id="app">中。保存,回到vue ui仪表盘,任务 -> ‘启动App’

当看到一些五颜六色的按钮时,说明我们通过图形化的界面来配置Element-UI就已经搞定了。

OK,至此,陆陆续续学了半个多月的“前端工程化”就已经学完了。


参考内容: