手动搭建vue2项目工程环境[20211221]最新

4,196 阅读6分钟

目前vue项目已经迈入了vue3的时代,为什么还要写关于2.0的呢,因为就目前而言,原有技术栈的公司依然维护着2.x版本的技术栈项目,但是各版本都升级后,相应的资料就没有再有过更新,以至于在配置项目环境的时候频频出错,所以在此留下v2.x最后版本的教程。以供需要的小伙伴使用,也适合新手练手用。

面试中也容易被问到,项目环境是由你搭建还是由项目组搭建,而你只是写业务组件呢?所以学会配置并成功搭建项目环境还是很有必要的。

该教程分为两部分,第一部分采用脚手架创建,第二部分采用手动配置。

截止目前(20211220),vue 最新稳定版本:2.6.14,由于各版本插件之间存在兼容问题,所以部分安装需要注意版本的地方和需要指定版本的地方我都会给出说明(本环境中所采取的版本均为兼容版本中的最高版本), 避免出现错误让小伙伴们再四处搜索查找。

vue-cli 脚手架安装

官网安装教程地址

官网脚手架文档地址

环境

$ npm -v
8.1.0

$ node -v
v16.13.0

$ vue -V
@vue/cli 4.5.15

1.安装脚手架

安装脚手架,可以使用下列任一命令安装这个新的包:

$ npm install -g @vue/cli
# 或者
$ yarn global add @vue/cli

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

你还可以用这个命令来检查其版本是否正确:

$ vue --version

2.升级脚手架

如需升级全局的 Vue CLI 包,请运行:

$ npm update -g @vue/cli

# 或者
$ yarn global upgrade --latest @vue/cli

3.安装项目

脚手架安装好之后就可以执行安装命令进行项目安装了

# vue-cli 为项目名
$ vue create vue-cli

Snipaste_2021-12-20_11-24-25.png

4.选择配置并安装

你会被提示选取一个 preset。你可以选默认的包含了基本的 Babel + ESLint 设置的 preset,也可以选“手动选择特性”来选取需要的特性。选择 vue选项 进行安装,下图为选择界面

Snipaste_2021-12-20_11-21-08.png

4.1选择默认配置

这里先选择默认配置 Default ([Vue 2] babel, eslint) ,选择之后,按回车键就会进入安装过程

image.png

4.2 手动配置选项

这里给出手动选择配置界面,按 键盘 上↑下↓键可以上下移动活动光标,通过按空格键可以选中或取消单个选项。界面如下图:

Snipaste_2021-12-20_11-36-34.png

选择完毕之后按回车,会让你继续选择 vue 版本,如下图:

Snipaste_2021-12-20_11-40-01.png

默认选中 vue2.x 版本,这里我们直接按回车进行安装即可。 此时会提示你是否 使用 history 模式路由。

? Use history mode for router? (Requires proper server setup for in
dex fallback in production) (Y/n)

这里我们选择确认即可,确认之后进行后续配置。

选择css 预处理器(Sass/SCSS):

image

选择eslint 配置(ESLint + Standard config):

image

选择什么时候执行eslint校验(Lint on save):

image

选择以什么样的形式配置以上所选的功能(In dedicated config files):

image

如果选择 y 会让输入名称,以便下次直接使用,否则直接开始初始化项目。

Snipaste_2021-12-20_11-49-06.png

是否将之前的设置保存为一个预设模板(y):确定保存配置。

Snipaste_2021-12-20_11-50-14.png

5.启动项目

# 进入项目目录 并执行启动
$ cd vue-cli
$ yarn serve

image.png

6.成功验证

启动项目之后,通过 http://localhost:8080/ 进行访问,成功则显示如下图:

Snipaste_2021-12-20_11-08-14.png

7.目录说明

    ├─node_modules // npm包文件
    ├─public
    │  └─index.html // 模板文件
    │  └─img
    │      └─icons
    ├─src
    │  ├─assets // 静态资源
    │  ├─components // 公共组件
    │  ├─router // 路由
    │  ├─store // 状态
    │  ├─views // 视图
    │  ├─App.vue // 主vue模块,项目主组件
    │  ├─main.js // 入口文件 初始化vue实例
    │  └─registerServiceWorker.js // 离线缓存
    ├─.browserslistrc //浏览器兼容
    ├─.eslintrc.js // 代码检测工具
    ├─.eslintignore // 配置代码检测忽略文件 (需自行创建)
    ├─.gitignore // git 忽略文件配置
    ├─babel.config.js // 工具链 语法编译 向后兼容
    ├─package.json // 模块基本信息项目开发所需要的模块 版本 项目名称
    ├─package-lock.json // npm install后的产物,记录当前实际安装的 npm包的版本和来源
    ├─vue.config.js // 保存vue配置的文件,可以用于设置代理,打包配置等(需自行创建)
    ├─tests // 单元测试
    │  └─unit
    │     └─example.spec.js // 默认的单元测试例子
    ├─jest.config.js // 单元测试配置
    ├─README.md // markdown格式的项目说明文档
    ├─.env // 在所有的环境中被载入,但优先级别最低 (需自行创建)
    ├─.env.development // 开发环境配置(需自行创建)
    ├─.env.test // 测试环境配置(需自行创建)
    ├─.env.production // 生产环境配置(需自行创建)

手动安装配置

vue2 + webpack4 + babel7

# 初始化项目
yarn init -y
# or
npm init -y

# 安装最新稳定版 
$ npm install vue --save
yarn add vue

$ yarn add webpack webpack-cli webpack-dev-server

yarn add vue-loader --dev


yarn add vue-router

初始化项目

初始化项目,生成 package.json 配置文件

# 初始化项目
yarn init -y
# or
npm init -y

image.png 命令执行完成之后在项目根目录会生成一个package.json 配置文件

安装vue及创建相关组件

# 安装vue2.x最新稳定版 @2.6.14
$ yarn add vue
# or
$ npm install vue --save
  • 创建 index.html 在根目录下创建 index.html 文档,内容如下:
<!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>Vue 2.x</title>
</head>
<body>
    <div id="app"></div>
</body>
</html>
  • 创建 入口文件 main.js 和 vue组件 在根目录下创建 src 目录,并分别创建 src/main.jssrc/App.vue 文件

src/main.js

import Vue from 'vue';
import App from './App.vue';

new Vue({
    el: '#app',
    components: { App },
    template: '<App/>'
})

src/App.vue

<template>
    <div>
        Hello World!
    </div>
</template>

<script>
export default ({
    name: 'App'
})
</script>

<style>

</style>

安装webpack4 并配置

因为webpack4 与 webpack5版本变更较大,所以安装的时候要指定版本@4.46.0,webpack-dev-server 实现代码热更新功能

$ yarn add webpack@4.46.0 webpack-cli --dev
# or
$ npm install webpack@4.46.0 webpack-cli --save-dev
  • 安装热更新插件
$ yarn add webpack-dev-server --dev
# or
$ npm install webpack-dev-server --save-dev
  • 安装各种加载器 安装与css相关解析器, 存在版本兼容问题,需指定版本安装,
$ yarn add style-loader@2.0.0 css-loader@3.6.0 --dev
# or
$ npm install style-loader@2.0.0 css-loader@3.6.0 --save-dev

安装与其他文件相关解析器,url-loader存在版本兼容问题需指定版本安装 url-loader@2.3.0file-loader 解析文件url,并将文件复制到输出的目录中

$ yarn add url-loader@2.3.0 file-loader --dev
# or
$ npm install url-loader@2.3.0 file-loader --save-dev

安装与vue文件相关解析器

$ yarn add vue-loader vue-template-compiler --dev
# or
$ npm install vue-loader vue-template-compiler --save-dev

# 为 vue 安装 缓存器
$ yarn add cache-loader --dev
# or
$ npm install cache-loader --save-dev
  • 安装插件 在安装html-webpack-plugin的时候要指定版本@4.5.2,否则会安装最新版本会报错,最新版本与webpack4不兼容。
$ yarn add html-webpack-plugin@4.5.2 --dev
# or
$ npm install html-webpack-plugin@4.5.2 --save-dev
  • 配置 webpack 在根目录中创建webpack 配置文件 webpack.config.js
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin.js') 
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: path.resolve(__dirname, './src/main.js'),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: "js/[name].[hash:8].js"
    },
    mode: 'development',
    resolve: {
        extensions: ['.js', '.vue', '.json'], // import引用文件省略后缀
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    },
    module: {
        rules: [
            //注意 cache-loader 读取和保存缓存文件是有性能开销的,所以只使用这个加载器来缓存主要的加载器。
            {
                test: /\.vue$/,
                loader: ['cache-loader', "vue-loader"]
            },
            {
                test: /\.js$/,
                use: ['babel-loader'],
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    'style-loader', // 注:style-loader、MiniCssExtractPlugin.loader不能同时使用
                    "css-loader"
                ]
            },
            {
                test: /\.(gif|png|svg|jpe?g)(\?.*)?$/,
                loader: "url-loader", // 建议使用url-loader,不用file-loader,减少http请求次数
                options: {
                    limit: 1024
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, './index.html'),
            inject: 'body'
        }),
        new VueLoaderPlugin() //  手动创建项目,需在webpack中使用vue-loader自带插件
    ]
}

安装babel7 并配置

$ yarn add @babel/core @babel/preset-env babel-loader --dev
# or
$ npm install @babel/core @babel/preset-env babel-loader --save-dev

在根目录中创建.babelrc,初始化babel配置{ "presets": ["@babel/preset-env"] }

{
    "presets": ["@babel/preset-env"]
}

bable参考链接

配置 启动命令

package.json中配置启动命令 "dev": "webpack-dev-server --open --port 3000 --hot"

{
  "name": "vue2.x",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "webpack-dev-server --open --port 3000 --hot",
    "build": "webpack ./src/main.js --mode development"
  },
  "dependencies": {
    "vue": "^2.6.14"
  },
  "devDependencies": {
    "@babel/core": "^7.16.5",
    "@babel/preset-env": "^7.16.5",
    "babel-loader": "^8.2.3",
    "css-loader": "3.6.0",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "4.5.2",
    "style-loader": "2.0.0",
    "url-loader": "2.3.0",
    "vue-loader": "^15.9.8",
    "vue-template-compiler": "^2.6.14",
    "webpack": "^4.46.0",
    "webpack-cli": "^4.9.1",
    "webpack-dev-server": "^4.6.0"
  }
}

启动项目

执行以下命令启动项目

yarn dev
# or
npm run dev

启动项目后,如果出现页面所示,表示安装成功!

image.png

配置sass、less

sass-loader 和 less-loader 都存在版本兼容问题,都需要指定版本

$ yarn add sass sass-loader@10.2.0 --dev
# or
$ npm install sass sass-loader@10.2.0 --save-dev

$ yarn add less less-loader@7.3.0 --dev
# or
$ npm install less less-loader@7.3.0 --save-dev

webpack.config.js 中的配置 module 下新增 sass 规则

module.exports = {
    module: {
        rules: [
            {
                test: /.vue$/,
                loader: "vue-loader"
            },
            {
                test: /.js$/,
                use: ['babel-loader'],
                exclude: /node_modules/
            },{
                // test 表示测试什么文件类型
                test:/.css$/,
                // 使用 'style-loader','css-loader'
                use:['style-loader','css-loader']
            },{
                // 配置sass 需要新增该块配置
                test:/.(scss|sass)$/,
                // 使用 'style-loader','css-loader'
                use:['style-loader','css-loader', 'sass-loader']
            },{
                test:/.less$/,
                use:['style-loader','css-loader', 'less-loader']
            },{
                test: /.(gif|png|svg|jpe?g)(?.*)?$/,
                loader: "url-loader", // 建议使用url-loader,不用file-loader,减少http请求次数
                options: {
                    limit: 8*1024
                }
            }
        ]
    }
}

配置 postcss

实现自动添加css3前缀

postcss-loader 和 autoprefixer 都存在版本兼容问题,所以要指定版本安装

$ yarn add postcss-loader@4.3.0 autoprefixer@9.8.8 --dev
# or
$ npm install postcss-loader@4.3.0 autoprefixer@9.8.8 --save-dev
  • 修改webpack.config.js配置
module.exports = {
   ...
    module: {
        rules: [
            {
                test: /.vue$/,
                loader: "vue-loader"
            },
            {
                test: /.js$/,
                use: ['babel-loader'],
                exclude: /node_modules/
            },{
                test:/.css$/,
                // 使用 'style-loader','css-loader'
                use:['style-loader','css-loader', 'postcss-loader']
            },{
                // test 表示测试什么文件类型
                test:/.(scss|sass)$/,
                // 使用 'style-loader','css-loader'
                use:['style-loader','css-loader', 'sass-loader', 'postcss-loader']
            },{
                test:/.less$/,
                use:['style-loader','css-loader', 'less-loader', 'postcss-loader']
            },{
                test: /.(gif|png|svg|jpe?g)(?.*)?$/,
                loader: "url-loader", // 建议使用url-loader,不用file-loader,减少http请求次数
                options: {
                    limit: 8*1024
                }
            }
        ]
    }
}
  • 在项目根目录下新建一个 postcss.config.js
module.exports = {
  plugins: {
    autoprefixer: {}
  }
}

实现px自动转换成rem

postcss-pxtorem 存在 版本兼容性问题,所以安装需要指定版本

$ yarn add postcss-pxtorem@5.1.1 --dev
# or
$ npm install postcss-pxtorem@5.1.1 --save-dev

在根目录下的配置文件 postcss.config.js 中配置postcss-pxtorem

module.exports = {
  plugins: {
    "postcss-pxtorem": {
      replace: false,
      rootValue: 100, // 根元素字体大小
      // propList: ['*'] // 可以从px更改到rem的属性
      propList: ["height"]
    }
  }
}

如需 postcss-px-to-viewport 插件的小伙伴,可以自定安装并配置,这里就不再详细说明。

CSS样式抽离

CSS样式抽离使用的是 mini-css-extract-plugin 插件, 需要在 webpack 中配置,因版本存在兼容性 webpack4 支持最高版本为 mini-css-extract-plugin@1.6.2

安装 mini-css-extract-plugin 插件

$ yarn add mini-css-extract-plugin@1.6.2 --dev
# or
$ npm install mini-css-extract-plugin@1.6.2 --save-dev

webpack.config.js 中配置

const webpack = require("webpack");
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin.js')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // ++

module.exports = {
    // 配置主入口文件
    entry: path.resolve(__dirname, './src/main.js'),
    output: {
        // 配置打包文件输出的目录
        path: path.resolve(__dirname, 'dist'),
        // 生成的 js 文件名称
        filename: "js/[name].[hash:8].js",
        // 生成的 chunk 名称
        chunkFilename: "js/[name].[hash:8].js",
        // 资源引用的路径
        // publicPath: "./"
    },
    mode: 'development',
    resolve: {
        extensions: ['.js', '.vue', '.json'], // import引用文件省略后缀
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    },
    module: {
        rules: [
            {
                test: /.vue$/,
                loader: "vue-loader"
            },{
                test: /.(js|jsx)$/,
                use: ['babel-loader'],
                exclude: /node_modules/
            },{
                // test 表示测试什么文件类型
                test:/.css$/,
                // 使用 'style-loader','css-loader'
                use:[
                    MiniCssExtractPlugin.loader, // ++
                    // 'style-loader', // --
                    'css-loader', 'postcss-loader']
            },{
                // test 表示测试什么文件类型
                test:/.(scss|sass)$/,
                // 使用 'style-loader','css-loader'
                use:[
                    MiniCssExtractPlugin.loader, // ++
                    // 'style-loader', // --
                    'css-loader', 'sass-loader', 'postcss-loader']
            },{
                test:/.less$/,
                use:[
                    MiniCssExtractPlugin.loader, // ++
                    //'style-loader', // --
                    'css-loader', 'less-loader', 'postcss-loader']
            },{
                test: /.(gif|png|svg|jpe?g)(?.*)?$/,
                loader: "url-loader", // 建议使用url-loader,不用file-loader,减少http请求次数
                options: {
                    limit: 8*1024,
                    fallback: {
                        loader: 'file-loader',
                        options: {
                            name: 'img/[name].[hash:8].[ext]'
                        }
                    }
                }
            },
            {
                test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 4096,
                            fallback: {
                                loader: 'file-loader',
                                options: {
                                    name: 'media/[name].[hash:8].[ext]'
                                }
                            }
                        }
                    }
                ]
            },
            {
                test: /.(woff2?|eot|ttf|otf)(?.*)?$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 4096,
                            fallback: {
                                loader: 'file-loader',
                                options: {
                                    name: 'fonts/[name].[hash:8].[ext]'
                                }
                            }
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, './public/index.html'),
            inject: 'body'
        }),
        new VueLoaderPlugin(), //  手动创建项目,需在webpack中使用vue-loader自带插件
        new webpack.HotModuleReplacementPlugin(),
        new MiniCssExtractPlugin({
            filename: "css/[name].[hash:8].css"
        }) // ++
    ]
}

执行 yarn dev 启动项目,审查元素可看到引入的文件,即为成功配置

image.png

执行打包命令 yarn build 同样在 dist/css/ 下会生成相应css文件

路由配置 vue-router

安装路由插件

$ yarn add vue-router
# or
$ npm install vue-router --save

配置路由插件

image.png

涉及到的文件

创建 src/views/Home.vue及src/views/About.vue组件

// Home 组件
<template>
  <div id="home">
    <h1>Home</h1>
  </div>
</template>

<script>
export default {
  name: 'Home',
  components: {
  }
}
</script>

// About 组件
<template>
  <div id="about">
    <h1>About</h1>
  </div>
</template>

<script>
export default {
  name: 'About',
  components: {
  }
}
</script>

配置 Router,src/routers/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
Vue.use(VueRouter)

// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
import Home from '../views/Home';
// 使用路由懒加载
const About = () => import('../views/About.vue');
const Bar = { template: '<div>bar</div>' }

// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/bar', component: Bar }
]

// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
  // mode: 'history', // 默认 hash 模式
  routes // (缩写) 相当于 routes: routes
})

router.beforeEach((to, from, next) => {
  // if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  // else next()

  next()
})

router.afterEach((to, from) => {
  // ...
})

export default router;
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
// import router from './router/index'
// new Vue({
//   el: '#app',
//   router,
//   components: { App },
//   template: '<App/>'
// })

在 APP.vue 中使用路由, 将相应代码加入到你的页面中即可

<template>
  <div id="app">
    <p>
      <!-- 使用 router-link 组件来导航. -->
      <!-- 通过传入 `to` 属性指定链接. -->
      <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
      <router-link to="/">Home</router-link>
      <router-link to="/about">About</router-link>
    </p>
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 如果不需要过渡动画效果 可以去掉 transition-->
    <!-- <router-view></router-view>-->
    <transition name="slide-left">
      <router-view></router-view>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {
  }
}
</script>

<style lang="scss">

</style>

在实例上进行挂载 在 main.js 中进行配置

import Vue from 'vue';
import App from './App';
import router from './router/index'

new Vue({
    el: '#app',
    router,
    components: { App },
    template: '<App/>'
})

配置路由懒加载

在没配置路由懒加载的情况下,我们的路由组件在打包的时候,都会打包到同一个js文件去,当我们的视图组件越来越多的时候,就会导致这个 js 文件越来越大。然后就会导致请求这个文件的时间变长,最终影响用户体验

  1. 安装依赖
$ yarn add @babel/plugin-syntax-dynamic-import --dev
# or
$ npm install @babel/plugin-syntax-dynamic-import --save-dev

在 Babel 的配置文件.babelrc中配置路由懒加载

{
    "presets": ["@babel/preset-env"],
    "plugins": ["@babel/plugin-syntax-dynamic-import"]
}

修改路由文件 src/router/index.js, 路由的加载,按照 Home组件 及 About组件引入的方式处理即可

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// 使用路由懒加载
const About = () => import('../views/About.vue');

const routes = [
  { path: '/', component: () => import(/* webpackChunkName: "Home" */ '../views/Home.vue') },
  { path: '/about', component: About }
]

const router = new VueRouter({
  // mode: 'history', // 默认 hash 模式
  routes
})

export default router;

验证是否成功,执行打包命令 yarn build,在dist/js/ 文件夹下回生成单个路由组件的js文件

image.png

切换路由会加载相应组件的JS文件

image.png

配置 Vuex

  • 安装 vuex
$ yarn add vuex
# or
$ npm install vuex --save
  • 配置Vuex 在 src 目录下新建一个 store 目录 src/store/index.js 文件
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const state = {
  counter: 0
}

const actions = {
  add: ({commit}) => {
    return commit('add')
  }
}

const mutations = {
  add: (state) => {
    state.counter++
  }
}

const getters = {
  getCounter (state) {
    return state.counter
  }
}

export default new Vuex.Store({
  state,
  actions,
  mutations,
  getters
})

修改 main.js 文件 导入 vuex

import Vue from 'vue';
import App from './App';
import router from './router/index'
import store from './store'  // ++

new Vue({
    el: '#app',
    router,
    store, // ++
    components: { App },
    template: '<App/>'
})

修改 App.vue ,查看 vuex 配置效果

// App.vue
<template>
  <div class="App">
    <div>
      <p>{{getCounter}}</p>
      <button @click="add">add</button>
    </div>
  </div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
  name: 'App',
  data() {
    return {};
  },
  computed: {
    ...mapGetters(['getCounter'])
  },
  methods: {
    ...mapActions(['add'])
  }
};
</script>
<style lang="scss" scoped>
.App {
  text-align: center;
  color: skyblue;
  font-size: 28px;
}
</style>

当点击按钮的时候,可以看到我们的getCounter一直在增加

vuex 配置完成了,但实际项目中vuex也存在一些弊端,当页面刷新后,vuex中state存储的数据同时也会被更新,vuex中存储的数据不能持久化,需要监听处理来维持vuex存储的数据状态持久化。

为解决页面刷新后vuex中存储的数据状态不能持久化的问题,我采取的方案是借助第三方插件工具来实现vuex数据的持久化存储,来解决页面刷新后数据更新的问题。

$ yarn add vuex-persistedstate --dev
# or
$ npm install --save vuex-persistedstate

打包分析

上线部署前,我们需要看一下webpack打包完成后,到底打包了什么东西,有多大,这时候就需要用到这个模块分析工具了 webpack-bundle-analyzer

安装依赖

$ yarn add webpack-bundle-analyzer --dev
# or
$ npm install webpack-bundle-analyzer --save-dev
  • 修改webpack.config.js配置,在 plugins属性中新增一个插件

在开发环境中,我们是没必要进行模块打包分析的,只是当前还没有做环境区分,所以暂时就配置在 webpack.config.js

analyzerMode 配置项


// 性能分析 引入插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
    ...
    plugins: [
        new BundleAnalyzerPlugin(
            {
                analyzerMode: 'server', //可选'server','static','disabled'
                analyzerHost: '127.0.0.1',
                analyzerPort: 8889,
                reportFilename: 'report.html',
                defaultSizes: 'parsed',
                openAnalyzer: true,
                generateStatsFile: false,
                statsFilename: 'stats.json',
                statsOptions: null,
                logLevel: 'info'
            }
        )
    }
}

说明

analyzerMode:'server',可以是server,static,json,disabled。在server模式下,分析器将启动HTTP服务器来显示软件包报告。在"static"静态模式下,会生成带有报告的单个HTML文件。在disabled模式下,你可以使用这个插件来将generateStatsFile设置为true来生成Webpack Stats JSON文件。
analyzerHost: '127.0.0.1', 将在“服务器”模式下使用的端口启动HTTP服务器。
analyzerPort: 8888, 端口号。
reportFilename: 'report.html', 路径捆绑,将在static模式下生成的报告文件。相对于捆绑输出目录。
defaultSizes: 'parsed',默认显示在报告中的模块大小匹配方式。应该是stat,parsed或者gzip中的一个。
openAnalyzer: true:在默认浏览器中自动打开报告。
generateStatsFile:false: 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成。
statsFilename: 'stats.json', 相对于捆绑输出目录。
statsOptions: null,stats.toJson()方法的选项。例如,您可以使用source:false选项排除统计文件中模块的来源。在这里查看更多选项:https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
logLevel: 'info',日志级别,可以是info, warn, error, silent。
excludeAssets:null,用于排除分析一些文件

分析报告图如下: image.png

集成 EditorConfig 配置

EditorConfig 有助于为不同 IDE 编辑器上处理同一项目的多个开发人员维护一致的编码风格。

官网:editorconfig.org

在项目根目录下增加 .editorconfig 文件:

# Editor configuration, see http://editorconfig.org

# 表示是最顶层的 EditorConfig 配置文件
root = true

[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行

[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off
trim_trailing_whitespace = false

注意:

  • VSCode 使用 EditorConfig 需要去插件市场下载插件 EditorConfig for VS Code

    image

  • JetBrains 系列(WebStorm、IntelliJ IDEA 等)则不用额外安装插件,可直接使用 EditorConfig 配置。

集成 Prettier 配置

Prettier 是一款强大的代码格式化工具,支持 JavaScript、TypeScript、CSS、SCSS、Less、JSX、Angular、Vue、GraphQL、JSON、Markdown 等语言,基本上前端能用到的文件格式它都可以搞定,是当下最流行的代码格式化工具。官网:prettier.io/

安装 Prettier

$ yarn add prettier --dev
# or
$ npm install prettier --save-dev

配置 Prettier

在项目根目录下创建 .prettierrc 文件。

{
  "useTabs": false,
  "tabWidth": 2,
  "printWidth": 100,
  "singleQuote": true,
  "trailingComma": "none",
  "bracketSpacing": true,
  "semi": false
}

Prettier 安装且配置好之后,就能使用命令来格式化代码

# 格式化所有文件(. 表示所有文件)
npx prettier --write .

注意:

  • VSCode 编辑器使用 Prettier 配置需要下载插件 Prettier - Code formatter

    image

  • JetBrains 系列编辑器(WebStorm、IntelliJ IDEA 等)则不用额外安装插件,可直接使用 Prettier 配置。

Prettier 配置好以后,在使用 VSCode 或 WebStorm 等编辑器的格式化功能时,编辑器就会按照 Prettier 配置文件的规则来进行格式化,避免了因为大家编辑器配置不一样而导致格式化后的代码风格不统一的问题。

配置 ESLint

ESLint 是一款用于查找并报告代码中问题的工具,并且支持部分问题自动修复。其核心是通过对代码解析得到的 AST(Abstract Syntax Tree 抽象语法树)进行模式匹配,来分析代码达到检查代码质量和风格问题的能力。

安装 ESLint:

$ yarn add eslint --dev
# or
$ npm install eslint --save-dev

配置 ESLint

ESLint 安装成功后,执行 npx eslint --init,然后按照终端操作提示完成一系列设置来创建配置文件。

  • How would you like to use ESLint? (你想如何使用 ESLint?)

image.png

这里我们选择 To check syntax, find problems, and enforce code style(检查语法、发现问题并强制执行代码风格)(上下箭头移动光标,回车键确认选择)

  • What type of modules does your project use?(你的项目使用哪种类型的模块?)

image.png

这里我们选择 JavaScript modules (import/export)

  • Which framework does your project use? (你的项目使用哪种框架?)

image.png

这里我们选择 Vue.js

  • Does your project use TypeScript?(你的项目是否使用 TypeScript?)

image.png

这里我们选择 No

  • Where does your code run?(你的代码在哪里运行?)

image.png

这里我们选择 Browser 和 Node(按空格键进行选择,选完按回车键确定)

  • How would you like to define a style for your project?(你想怎样为你的项目定义风格?)

image.png

这里我们选择 Use a popular style guide(使用一种流行的风格指南)

  • Which style guide do you want to follow?(你想遵循哪一种风格指南?)

image.png

这里我们选择 Airbnb: github.com/airbnb/java…

ESLint 为我们列出了三种社区流行的 JavaScript 风格指南,分别是 Airbnb、Standard、Google。

这三份风格指南都是由众多大佬根据多年开发经验编写,足够优秀,全球很多大小公司都在使用。我们选用 GitHub 上 star 最多的 Airbnb,免去繁琐的配置 ESLint 规则时间,然后让团队成员去学习 Airbnb JavaScript 风格指南即可。

此时,我们在 ESLint 配置了 Airbnb JavaScript 规则,在编码时,所有不符合 Airbnb 风格的代码,编辑器都会给出提示,并且可以自动修复。

这里不建议大家去自由配置 ESLint 规则,这三份 JavaScript 代码风格指南值得我们反复学习,掌握后,编程能力会进一步有所提高。

  • What format do you want your config file to be in?(你希望你的配置文件是什么格式?)

image.png

这里我们选择 JavaScript

  • Would you like to install them now with npm?(你想现在就用 NPM 安装它们吗?)

image.png

根据上面的选择,ESLint 会自动去查找缺失的依赖,我们这里选择 Yes,使用 NPM 下载安装这些依赖包。

注意:如果自动安装依赖失败,那么需要手动安装 Installing eslint-plugin-vue@latest, eslint-config-airbnb-base@latest, eslint@^7.32.0 || ^8.2.0, eslint-plugin-import@^2.25.2

$ yarn add eslint-plugin-vue eslint-config-airbnb-base eslint@^8.2.0 eslint-plugin-import@^2.25.2 --dev
# or
$ npm i eslint-plugin-vue eslint-config-airbnb-base eslint@^8.2.0 eslint-plugin-import@^2.25.2 -D

# 选择typescript的如下安装
$ yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue --dev
# or
$ npm i @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue -D

ESLint 配置文件 .eslintrc.js

上一步操作完成后,会在项目根目录下自动生成 .eslintrc.js 配置文件:

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'plugin:vue/essential',
    'airbnb-base',
  ],
  parserOptions: {
    ecmaVersion: 13,
    sourceType: 'module',
  },
  plugins: [
    'vue',
  ],
  rules: {
  },
};
  1. 根据项目实际情况,如果我们有额外的 ESLint 规则,也在此文件中追加。

注意:

  • VSCode 使用 ESLint 配置文件需要去插件市场下载插件 ESLint

    image

  • JetBrains 系列(WebStorm、IntelliJ IDEA 等)则不用额外安装插件。

配置好以后,我们在 VSCode 或 WebStorm 等编辑器中开启 ESLin,写代码时,ESLint 就会按照我们配置的规则来进行实时代码检查,发现问题会给出对应错误提示和修复方案。

IntelliJ IDEA 开启ESlint 规则

image.png

以下资料供参考:

idea中配置eslint 静态代码检查

eslint-plugin-vue # vue/多词组件名称

used no-plusplus

eslint no-shadow

# Assignment to property of function parameter 'state'

集成 husky 和 lint-staged

虽然我们在项目中已集成了 ESLint 和 Prettier,在编码时,这些工具可以对我们写的代码进行实时校验,在一定程度上能有效规范我们写的代码,但是团队中可能会有些人觉得这些条条框框的限制很麻烦,选择视"提示"而不见,依旧按自己的一套风格来写代码,或者干脆禁用掉这些工具,开发完成就直接把代码提交到了仓库,日积月累,ESLint 也就形同虚设。

所以,我们还需要做一些限制,让没通过 ESLint 检测和修复的代码禁止提交,从而保证仓库代码都是符合规范的。

为了解决这个问题,我们需要用到 Git Hook,在本地执行 git commit 的时候,就对所提交的代码进行 ESLint 检测和修复(即执行 eslint --fix),如果这些代码没通过 ESLint 规则校验,则禁止提交。

实现这一功能,我们借助 husky + lint-staged

husky —— Git Hook 工具,可以设置在 git 各个阶段(pre-commitcommit-msgpre-push 等)触发我们的命令。
lint-staged —— 在 git 暂存的文件上运行 linters。

配置 husky

  • 安装 husky

    $ yarn add husky --dev
    # or
    $ npm i husky -D
    
  • 创建 Git hooks

    $ npx husky install
    

    该命令做了两件事:

    • 在项目根目录下创建 .husky 目录

    • 在 .husky 目录创建 pre-commit hook,并初始化 pre-commit 命令为 npm run test

      如果没有自动生成pre-commit则执行以下命令手动生成,并向git hooks中添加 npm run test命令,npx husky add .husky/_/pre-commit "npm run test"

      运行完该命令后我们会看到.husky/目录下新增了一个名为pre-commit的shell脚本。也就是说在在执行git commit命令时会先执行pre-commit这个脚本。pre-commit脚本内容如下:

      #!/bin/sh
      . "$(dirname "$0")/_/husky.sh"
      
      npm run test
      

      在项目中我们会使用commit-msg这个git hook来校验我们commit时添加的备注信息是否符合规范。在以前的我们通常是这样配置:

      对于commit-msg hook我们可以使用以下命令来创建git hook所要执行的脚本

      npx husky add .husky/_/commit-msg 'npx --no-install commitlint --edit "$1"' 
      
  • 手动修改 package.json 的 scripts,增加 "prepare": "husky install"

  • 自动配置(推荐)使用 husky-init 命令快速在项目初始化一个 husky 配置。

    npx husky-init && npm install
    

总结

安装过程中主要是要注意webpack版本及其对应插件,如果安装以往命令直接安装而没有指定版本,则很容易出错。 我们还可以通过 babel-polyfill 对一些不支持新语法的客户端提供新语法的实现

参考资料:

# husky使用总结