> For the complete documentation index, see [llms.txt](https://gb.akanote.cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gb.akanote.cn/vue/day04.md).

# Part4-Webpack与脚手架

## 一、Webpack(熟悉)

> 从本质上来说，webpack是一个**静态模块打包工具**。
>
> 要想让我们写好的模块化代码在各式各样的浏览器上能做到兼容，就必须借助于其他工具；而webpack的其中一个核心就是让我们可以进行模块化开发，并帮我们处理模块间的依赖关系。不仅仅是Javascript文件，我们的css、图片、json文件等在webpack中都可以当作模块来使用，这就是webpack的模块化概念。

### 1. gulp和webpack

> Gulp侧重于前端开发的 **整个过程** 的控制管理（像是流水线），我们可以通过给gulp配置不同的task（通过Gulp中的gulp.task()方法配置，比如启动server、sass/less预编译、文件的合并压缩等等）来让gulp实现不同的功能，从而构建整个前端开发流程。

**gulpfile.js**

```js
var gulp = require('gulp');
var uglify = require('gulp-uglify'); //压缩代码

// 压缩js
gulp.task('uglify',function(){
    var combined = combiner.obj([
        gulp.src('src/scripts/**/*.js'), //需要压缩的js文件路径
        sourcemaps.init(),
        uglify(), //压缩js
        sourcemaps.write('./'),
        gulp.dest('dest/scripts') //生成的js文件的目录
    ]);
});

//默认任务
gulp.task('default',['uglify']);
```

> Webpack有人也称之为 **模块打包机** ，由此也可以看出Webpack更侧重于模块打包，当然我们可以把开发中的所有资源（图片、js文件、css文件等）都可以看成模块，最初Webpack本身就是为前端JS代码打包而设计的，后来被扩展到其他资源的打包处理。Webpack是通过loader（加载器）和plugins（插件）对资源进行处理的。

### 2. webpack初体验

#### 1. 生成项目依赖文件

```js
// 执行后生成package.json文件
npm init -y 
```

#### 2. 安装依赖

```js
// 最后的参数-D是安装到package.json的开发依赖devDependencies(开发环境)对象里，也可以用 --save-dev代替
npm install webpack webpack-cli -D

// -S是--save的简写，这样安装的话，会安装到dependencies(生产环境)对象里，也可以用 --save代替
npm install jquery -S
```

```js
// package.json
{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.58.1",
    "webpack-cli": "^4.9.0"
  },
  "dependencies": {
    "jquery": "^3.6.0"
  }
}
```

> devDependencies与dependencies的区别：
>
> 在发布npm包的时候，本身dependencies下的模块会作为依赖，一起被下载；devDependencies下面的模块就不会自动下载了；但对于项目而言，npm install 会自动下载devDependencies和dependencies下面的模块。

### 3.创建入口文件

`index.html`：

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
  </ul>
</body>
<script src="./src/index.js"></script>
</html>
```

`src/index.js`：

```js
import $ from 'jquery'
$('ul li:even').css({background: 'red'})
$('ul li:odd').css({background: 'green'})
```

在浏览器打开

[![1568968799462](https://i.loli.net/2021/03/19/sOw4Hi3NURotngc.png)](https://i.loli.net/2021/03/19/sOw4Hi3NURotngc.png)

> 为什么会这样？因为浏览器并不兼容import引入模块这种方式，所以我们要用到webpack打包

### 4. 通过webpack打包

**webpack.config.js：**

```js
const path = require('path');

module.exports = {
  mode: "development",
  entry: path.join(__dirname, './src/index.js'),	// dirname代表索引到文件所在目录
  output: {
    path: path.join(__dirname, './dist'),
    filename: 'main.js'
  }
}
```

**package.json：**

```json
"scripts": {
    "build": "webpack --config webpack.config.js"
}
```

然后修改 `index.html`:

```html
<script src="./dist/main.js"></script>
```

再打开 `index.html`，就可以观察到：

![image-20211011192801529](https://tva1.sinaimg.cn/large/008i3skNgy1gvblhz38kmj617q0bcq3302.jpg)

### 5.webpack-dev-server

> 这时候如果修改index.html的背景颜色red改成是gray，会发现浏览器刷新也没有效果，需要再跑一次`npm run start`命令才有用，这时候就需要webpack-dev-server(热重载)

**安装：**

```js
npm install webpack-dev-server -D
```

**package.json：**

```json
"scripts": {
	"start": "webpack-dev-server --open --port 3002 --hot",
  "build": "webpack --config webpack.config.js"
}

// --open 自动打开浏览器
// --port 服务监听的端口 3002
// --hot  自动更新
```

> 这里注意：
>
> 1、启动webpack-dev-server后， 你在目标文件夹中是看不到编译后的文件的，实时编译后的文件都保存到了内存当中。想看到main.js文件，可以运行localhost:3002/main.js查看

**index.html**

```html
<script src="./main.js"></script>
```

至此，通过 `npm run start` 我们仍然无法访问html页面，因为打包出来的dist被隐藏，同时它也并不包含 `index.html` ，所以会有 `Cannot GET /` 的警告。

接下来，我们解决html的问题：

### 6. html-webpack-plugin

安装：`npm install html-webpack-plugin -D`

**webpack.config.js**

```js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: "development",	// development-开发环境。 production-生产环境
  entry: path.join(__dirname, './index.js'),
  output: {
    path: path.join(__dirname, './dist'),
    filename: 'main.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, './index.html')
    })
  ]
}
```

> 删掉index.html文件里面的main.js引用，因为html-webpack-plugin会自动把打包出来的bundle自动加到我们的index.html代码里

重新运行 `npm run start`，即可看到：

![image-20211011195342567](https://tva1.sinaimg.cn/large/008i3skNgy1gvbm8pc0ywj61fm0caq3b02.jpg)

并且，此时你随意修改 `index.js` 中的代码，界面也会实时更新。

### 7. css-loader

创建一个index.css

**index.css**

```css
body {
    background: skyblue;
}
```

**index.js**

```js
import $ from 'jquery';
$('ul li:even').css({background: 'gray'});
$('ul li:odd').css({background: 'green'});

import './index.css';
```

[![1568972642846](https://i.loli.net/2021/03/19/DlywArz5Nqcudnv.png)](https://i.loli.net/2021/03/19/DlywArz5Nqcudnv.png)

> 为什么报错，因为webpack默认是不识别`.css`文件的，需要我们通过 `loader` 将 `.css` 文件进行解释成正确的模块。

**安装css-loader和style-loader**

```js
npm install css-loader style-loader -D 
//index.css -> bundle.js -> style-loader -> <style> index.html
// css-loader的作用是将index.css文件解析为webpack能识别的模块，然后打包进bundle.js里面，但是这样样式并未成功显示在浏览器中。
// style-loader的作用就是将打包到bundle.js中的样式绑定到浏览器上，以style标签的形式显示出来
```

**webpack.config.js**

```js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: "development",	// development-开发环境。 production-生产环境
  entry: path.join(__dirname, './index.js'),
  output: {
    path: path.join(__dirname, './dist'),
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, './index.html'),
      filename: 'index.html'
    })
  ],
  module: {
    rules: [{
      test: /\.css$/,
      use: ['style-loader', 'css-loader']	// 注意：这里的数组是反向读取的（即从右往左）
    }]
  }
}
```

再重新执行一次 `npm run start` 即可看到样式变化，同时，如果修改样式的话，也可以实时更新。

> 补充：引入的文件是less
>
> 安装：npm install less-loader less -D
>
> 规则：
>
> {
>
> ​ test: /.less$/,
>
> ​ use: \['style-loader', 'css-loader', 'less-loader']
>
> }

### 8. ES6 转 ES5

> 安装

```js
npm install babel-loader @babel/core @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime @babel/preset-env @babel/runtime -D
```

> 配置loader

```json
{
  test: /\.js$/,
  use: [{
    loader: 'babel-loader',
    options: {
      presets: [
        '@babel/preset-env'
      ],
      plugins: [
        [require("@babel/plugin-transform-runtime"), { "legacy": true }],
        [require("@babel/plugin-proposal-class-properties"), { "legacy": true }]
      ]
    }
  }],
  exclude: /node_modules/
}
```

exclude表示排除掉 node\_modules下载的依赖项。这样可以加速网站开发，而且我们也只需要对我们的项目src

源文件进行编译即可。

在 `src/index.js` 中引入es6语法

```js
const fn = () => {
  console.log(123)
}

fn()
```

执行命令编译

```js
npm run start 
```

编译后的结果

```js
var fn = function fn() {\n    console.log(123);\n}
```

至此关于webpack的基本配置已经到这里。

### 9. html热更新

在安装过html-webpack-plugin之后，安装：

```js
npm install --save-dev raw-loader
```

在index.js中引入index.html

```
import '../index.html';
```

在webpack.config.js中配置raw-loader:

```js
module.exports = {
  ......
  module: {
    rules: [
      {
         test: /\.(htm|html)$/,
         use: [
           'raw-loader'
         ]
      },
      ......
    ]
  }
}
```

### 10、图片资源

webpack5开始，不再需要安装loader来支持图片加载与打包。

给 `webpack.config.js` 添加：

```js
{
  test: /\.(png|gif|svg|jpe?g)$/,
    /* 
      asset/resource - 把指定资源拷贝对对应的目录
      asset/inline - 直接转base64，不产生图片
    */
    // type: 'asset/inline',
    type: 'asset/resource',
      generator: {
        filename: 'img/[name].[hash:4][ext]'
      }
},
```

然后给 `index.html` 写入：

```html
<div class="logo"></div>
<img src="" alt="">
```

再到 `index.less` 写入：

```less
.logo{
  width: ...;
  height: ...;
  background: url(./assets/images/logo.png);	// 这里图片自己找即可，要放在src/assets/images
}
```

再到 `index.js` 写入：

```js
import logo from "./assets/images/logo.png"

document.getElementsByTagName('img')[0].src = logo;
```

然后运行 `npm run start` 即可看到图片，或是运行 `npm run build` 查看打包后的结果，并双击 `dist/index.html` 手动打开页面查看效果。

## 二、什么是Vue CLI(掌握)

> 1. 如果你只是简单写几个Vue的Demo程序, 那么你不需要Vue CLI.
> 2. 如果你在开发大型项目, 那么你需要, 并且必然需要使用Vue CLI
>    1. 使用Vue.js开发大型应用时，我们需要考虑代码目录结构、项目结构和部署、热加载、代码单元测试等事情。
>    2. 如果每个项目都要手动完成这些工作，那无疑效率比较低效，所以通常我们会使用一些脚手架工具来帮助完成这些事情。
> 3. 那究竟什么是Vue-CLI呢？
>    1. CLI（Command Line Interface）.翻译为命令行界面，就是我们所说的脚手架。
>    2. Vue CLI是一个官方发布的vue项目脚手架
>    3. 使用vue-cli可以快速搭建Vue环境和webpack配置

## 三、Vue CLI使用准备

#### Node版本

> Vue CLI 需要Node.js 8.9 或者更高版本（推荐使用 12.13.0）。你可以使用`nvm` 或 `nvm-window`来管理电脑上面的Node版本。

**安装Vue CLI脚手架的包：**

```js
npm install -g @vue/cli
# OR
yarn global add @vue/cli
```

安装之后，你就可以在命令行中访问 `vue` 命令。你可以通过简单运行 `vue`，看看是否展示出了一份所有可用命令的帮助信息，来验证它是否安装成功。

你还可以用这个命令来检查其版本是否正确 (4.x)：

```bash
vue --version
```

如果安装比较慢，可以把npm切换成淘宝的源：

```
npm config set registry https://registry.npm.taobao.org/
```

## 四、创建项目(掌握)

#### 初始化项目

**vue create xxx**

运行以下命令来创建一个新项目：

```js
vue create hello-world
```

#### Vue-CLI生成项目流程

```js
vue create 项目名称
```

1. 选择**Manually select features**(自己选择项目用的模块), 回车键确认;
2. 选择 **Babel** **CSS Pre-processors** (选择项目里面需不需要CSS预处理器), 通过`空格`选中或者取消选中, 回车键确认;
3. Pick a CSS pre-processor(选中CSS 预处理器) ,这里选择**Less**, 回车键确认;
4. Where do you prefer placing config for ....(babel protcss的配置是要放置到哪里去), 选择 **In dedicated config files** (独立的文件存放配置就可以),回车确认;
5. Save this as a preset for future projects?(y/N) 把上面的所有选择单独保存成一个配置,方便以后的项目配置, 这里选择y,下一个选择就是输入这个配置的名字;选择N就不保存,然后回车直接生成一个项目出来.

你会被提示选取一个 preset。你可以选默认的包含了基本的 Babel + ESLint 设置的 preset，也可以选“手动选 择特性”来选取需要的特性。

[![](https://i.loli.net/2021/03/19/twCex4qvzMrY1ba.png)](https://i.loli.net/2021/03/19/twCex4qvzMrY1ba.png)

这个默认的设置非常适合快速创建一个新项目的原型，而手动设置则提供了更多的选项，它们是面向生产的项目更加需要的。

[![CLI é¢è§](https://i.loli.net/2021/03/19/hpnidsLBY6xW3VC.png)](https://i.loli.net/2021/03/19/hpnidsLBY6xW3VC.png)

对于每一项的功能，此处做个简单描述：

* TypeScript 支持使用 TypeScript 书写源码。
* Progressive Web App (PWA) Support PWA支持
* Router 路由
* Vuex 状态管理
* CSS Pre-processors 支持 CSS 预处理器。
* Linter / Formatter 支持代码风格检查和格式化。
* Unit Testing 支持单元测试。
* E2E Testing 支持 E2E 测试。

如果你决定手动选择特性，在操作提示的最后你可以选择将已选项保存为一个将来可复用的 preset

> \~/.vuerc
>
> 被保存的 preset 将会存在用户的 home 目录下一个名为 `.vuerc` 的 JSON 文件里。如果你想要修改被保存的 preset / 选项，可以编辑这个文件。
>
> 在项目创建的过程中，你也会被提示选择喜欢的包管理器或使用[淘宝 npm 镜像源](https://npm.taobao.org/)以更快地安装依赖。这些选择也将会存入 `~/.vuerc`。

#### 使用图形化界面

你也可以通过 `vue ui` 命令以图形化界面创建和管理项目：

```bash
vue ui
```

上述命令会打开一个浏览器窗口，并以图形化界面将你引导至项目创建的流程。

[![图形化界面预览](https://i.loli.net/2021/03/19/ZTi4gAyPbwf2FjE.png)](https://i.loli.net/2021/03/19/ZTi4gAyPbwf2FjE.png)

#### 项目结构

[![1569235847530](https://i.loli.net/2021/03/19/mHi7owaJQskxfKD.png)](https://i.loli.net/2021/03/19/mHi7owaJQskxfKD.png)

```js
node_modules
public // 静态资源文件
    |-favicon.ico
    |-index.html
src // 项目源代码，书写代码的地方
    |-assets
    |-App.vue
    |-main.js
.browserslistrc    // 浏览器相关支持情况
.eslintrc.js       // 代码相关支持情况
.gitignore         // Git忽略文件
babel.config.js    // babel配置ES语法 转换
package-lock.json  // npm安装依赖库的具体信息
package.json       // npm依赖库版本信息
postcss.config.js  // css相关转换
README.md          // 项目说明
vue.config.js      // Vue及webpack配置项
```

#### vue.config.js

`vue.config.js` 是一个可选的配置文件，如果项目的 (和 `package.json` 同级的) 根目录中存在这个文件，那么它会被 `@vue/cli-service` 自动加载。你也可以使用 `package.json` 中的 `vue` 字段，但是注意这种写法需要你严格遵照 JSON 的格式来写。

这个文件应该导出一个包含了选项的对象：

```js
// vue.config.js
module.exports = {
  // 选项...(例如：)
  lintOnSave: false	// 关闭eslint
}
```

**webpack中添加别名**

```js
module.exports = {
    //1.基础的配置方式 
    configureWebpack: {
      resolve: {
        alias: {
          'components': '@/components',
          'pages': '@/pages'
        }
      }
    },

    //2.利用webpack4的webpack-chain来配置 
    chainWebpack: (config) => {
      config.resolve.alias
        .set('@', resolve('src'))
        .set('components', resolve('src/components'))
    }
  }
```

## 五、生命周期(掌握)

什么是生命周期： 从Vue创建、运行、到销毁期间，总是伴随着各种各样的事件，这些事件，统称为生命周期。

### 1、vue生命周期图示

[![lifecycle](https://cn.vuejs.org/images/lifecycle.png)](https://cn.vuejs.org/images/lifecycle.png)

### 2、生命周期解读

[![preview](https://i.loli.net/2021/03/19/kfm436SpUxiHyQE.png)](https://i.loli.net/2021/03/19/kfm436SpUxiHyQE.png)

### 3、注意点

[![image-20200715121741390](https://i.loli.net/2021/03/19/5Z1jbKFsNDLahBT.png)](https://i.loli.net/2021/03/19/5Z1jbKFsNDLahBT.png)
