# 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gb.akanote.cn/vue/day04.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
