一、vue cli
我们使用vue开发项目,我们要书写webpack配置,创建项目,创建文件等需要时间,为了做性能优化,需要大量的配置等等,在开发项目前,要准备大量的工作内容
vue为了简化这一开发方式,提供了vue-cli脚手架。
安装
通过npm安装vue-cli: npm install -g @vue/cli
此时提供了vue指令,输入vue -v可以查看版本号
创建项目
执行‘vue create 项目名称’指令就可以创建项目
创建过程中,可以输入一些选项。
二、目录部署
node_modules 依赖的模块
public 静态资源
index.html 入口文件
manifest.json 离线缓存配置
favicon.ico 网页logo
robots.txt 爬虫配置
img 图片资源目录
src 开发目录
assets 静态资源
components 页面间共享的组件
views 页面组件
App.vue 应用程序组件
router.js 路由文件
store.js vuex文件
main.js 入口文件
registerServiceWorker.js web workers文件
test 单元测试目录
.browserslistrc 浏览器配置
.eslintrc es语法校验
.gitnore 提交配置
babel.config.js babel配置
jest.config.js 单元测试配置
package.json npm包配置
postcss.config.js css配置
readme.rd 项目介绍文件
yarn.lock yarn锁文件
三、指令
ts开发
我们创建项目的时候,可以选择ts语法或者es6语法,
选择ES6会使用.js文件
选择ts会使用.ts文件
指令
serve 启动项目,默认端口号是8080
build 发布项目,默认向dist目录下发布
test:unit 启动单元测试
我们既可以使用yarn指令运行,也可以使用npm run指令运行。
四、配置
插件webpack配置,用inspect指令:vue inspect > 文件路径
我们可在vue.config.js中。自定义配置
在配置文件中,有两个环境,
一个是开发环境,执行yarn serve时候的环境
一个是发布环境,执行yarn build时候的环境
我们通过process.env.NODE_ENV来识别环境:
development表示开发环境
production表示发布环境
在vue.config.js文件中。我们要分别为开发环境和发布环境定义配置
我们可以定义两类配置
一类是webpack语法配置
在configureWebpack中配置
一类是vue cli自身的语法配置
outputDir 静态资源发布位置
indexPath 模板发布位置
publicPath 模板中引入的静态资源相对位置
五、PWA
是一个渐进式的web应用,介于web应用与源生应用之间的一类应用、
可以像web应用一样开发。
可以具有源生应用的一些功能,
其中以下文件就是为了实现这些功能的。
manifest.json 离线缓存配置
registerServiceWorker.js web workers文件
六、单元测试
测试就是描述一段话,判断是否正确(断言)。基于文件或者模块(组件)的测试,我们称之为单元测试。
6.1 单元测试
在vue cli中,我们使用的是jest框架。测试结果有两种
一种是测试成功,所有的单元测试都成功。
一种是测试失败,有一个测试是失败的。
启动测试:yarn test:unit npm run test:unit
测试文件:在单元测试中,有三类文件可以被测试
1 放在test目录中的文件
2 文件的名添加.test.后缀的文件
3 文件的名添加.spec.后缀的文件
命名规范:通常与被测试的文件同名
6.2 测试方法
describe 测试整体描述
第一个参数表示描述
第二个参数是函数,表示测试内容
it 一次测试的描述
第一个参数表示描述
第二个参数是函数,表示本次测试的内容
expect 断言方法
参数就是描述
我们要对返回值做判断(断言)
6.3 断言方法
常见的断言方法有:
toBe 表示===
toEqual 字面量形式是否相等
toMatch 是否正则匹配
toContain 是否包含
toBeTruthy 是否为真
toBefalsy 是否为假
…
6.4 周期方法
beforeEach 每一个it语句执行前
afterEach 每一个it语句执行后
beforeAll 所有的it语句执行前
afterAll 所有的it语句执行后
只对当前文件的it语句生效,其它文件无效。
6.5 测试 store
由于store中有包含修改数据的逻辑(mutations以及action中),因此要对它们进行测试。
此时store的这些组成部分要单独定义出来,这样才能测试。
6.6 测试组件
我们在vue文件中,定义的组件只是Vue.extend方法的参数对象。因此我们不能直接使用,要转成实例化对象再使用,有两种方式
第一种:new Vue(obj)返回的是vue实例化对象
第二种: 通过组件类的方式,
第一步 let Comp = Vue.extend(obj);
第二步 实例化 new Comp()
不论是哪一种方式,都可以得到组件,但是组件没有上树,无法获取$el容器元素。
为了获取$el容器元素,我们要使用 $mount 方法。
$nextTick
会检测视图的更新,更新完毕,执行回调函数。
该方法实现了Promise规范。
所以我们可以通过then方法监听结果。
shallowMount
vue cli为了方便我们测试组件,提供了一个 shallowMount 方法。
该方法可以将组件实例化,并且执行$mount方法上树。
我们通过该方法,我们就可以得到一个组件实例化对象。
第一个参数是组件对象
第二个参数是配置对象(propsData: 传递给组件的属性数据)
提供了text方法,可以获取其视图中的内容。
注意:使用单元测试,去测试视图等很麻烦,效率低,因此工作中慎用。我们用单元测试,去测试一些业务逻辑收益还是很大的。
七、实现 Vue cli
我们基于webpack来实现一个vue cli的功能
实现vue cli的目录部署
实现一些性能优化的功能。
静态资源压缩,打包,添加指纹等等。
资源发布
将静态资源发布到外面的dzx/static目录中
将模板资源发布到外面的dzx/views/index.html文件中
发布模板
发布html文件用html-webpack-plugin插件
template 定义模板文件位置
filename 模板文件发布位置
hash 是否添加指纹(添加在query上)
inject 是否注入静态资源(默认是注入的)
压缩资源
压缩js,压缩html,压缩css
拆分文件
将模块文件打包在一起:main.js
将样式文件打包在一起: style.css
我们使用mini-css-extract-plugin插件
vue组件中样式拆分: extractCSS: true
css和scss|less样式拆分,使用该插件加载机
我们通过插件的filename属性定义文件发布位置。
对资源添加指纹:css资源,js资源等
压缩css使用optimize-css-assets-webpack-plugin插件
压缩js: mode: ‘production’
拆分库文件
将库文件打包在一起:lib.js
optimization: {
splitChunks: { 拆分文件
cacheGroup: { 公用缓存分组
lib: {
name: 库文件名称
chunks ‘initial’,
test: 库文件特征
}
}
}
}
目录显示
webpack.config.js
// 引入 path
let path = require('path');
// 引入 vue插件-loader
const { VueLoaderPlugin } = require('vue-loader');
// 引入 html 插件
let HtmlWebpackPlugin = require('html-webpack-plugin');
// 拆分 css
let MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 压缩 css
let OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
// 引入 根目录
const root = process.cwd();
// 定义配置
module.exports = {
// 模式
// 发布模式
mode: 'production',
// 解决问题
resolve: {
// 定义别名
alias: {
vue$: 'vue/dist/vue.js',
'@': path.join(root, './src'),
'@v': path.join(root, './src/views'),
'@c': path.join(root, './src/compoments'),
},
// 拓展名
extensions: ['.js', '.vue'],
},
// 入口
entry: './src/main.js',
// 发布
output: {
// "文件名"
// 第一种添加 hash 指纹的方式
// filename:'./static/[name].[hash:8].js',
// 第二种方式 在 插件中添加
filename: './static/[name].js',
// 发布位置
path: path.join(root, './dzx/'),
// 修改静态文件的相对位置
publicPath: '../'
},
// 模块
module: {
// 加载机
rules: [
// vue
{
test: /\.vue$/,
loader: 'vue-loader',
// 在以前的版本中,打包 css 还需要传递配置
// use:[
// {
// loader:'vue-loader',
// options:{
// extractCSS:true
// }
// }
// ]
},
// css
{
test: /\.css$/,
use: [
"style-loader",
// 在样式文件的 style-loader 后天添加 loader
MiniCssExtractPlugin.loader,
"css-loader"
]
},
// less
{
test: /\.less$/,
use: [
"style-loader",
// 在样式文件的 style-loader 后天添加 loader
MiniCssExtractPlugin.loader,
"css-loader",
"less-loader"
]
},
// scss
{
test: /\.scss$/,
use: [
"style-loader",
// 在样式文件的 style-loader 后天添加 loader
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
}
]
},
// vue 插件
plugins: [
// 使用 vue-loader
new VueLoaderPlugin(),
// 处理模板
new HtmlWebpackPlugin({
// 模板位置
template: './public/index.html',
// 发布位置
filename: './views/index.html',
// 添加指纹
hash: true
}),
// 2 定义文件的发布位置
new MiniCssExtractPlugin({
filename: './static/style.css'
}),
// 压缩 css
new OptimizeCssAssetsWebpackPlugin()
],
// 优化
optimization: {
// 拆分文件
splitChunks: {
cacheGroups: {
lib: {
name: 'lib',
chunks: 'initial',
test: /node_modules/
}
}
}
}
}
public/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>Document</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
src/App.vue
<template>
<div id="app">
<h1>app page</h1>
<router-link to="/">home</router-link>
<router-link to="/list/1">list</router-link>
<router-link to="/detail/2">detail</router-link>
<br>
<router-view></router-view>
</div>
</template>
src/demo.less
@color:pink;
h1{
color: @color;
}
src/main.js
import Vue from 'vue';
import App from './App';
import store from './store';
import router from './router';
import './demo.less';
new Vue({
// 订阅
store,
// 安装路由
router,
// 渲染应用程序
render: h => h(App)
}).$mount("#app")
src/router.js
import Vue from 'vue';
import Router from 'vue-router';
// 引入首页
import Home from '@v/Home';
// 安装
Vue.use(Router);
// 实例化
export default new Router({
routes: [
// 列表页
{ path: '/list/:page', component: () => import('@v/List') },
// 详情页
{ path: '/detail/:id', component: () => import('@v/Detail') },
// 默认页面
{ path: '*', component: Home }
]
})
src/store.js
import Vue from 'vue';
import Vuex,{ Store } from 'vuex';
// 安装
Vue.use(Vuex);
// 实例化
export default new Store({
state:{
num:0
},
mutations:{
},
actions:{
}
})
src/views/Home.vue
<template>
<div>
<h1>Home page --- {{$store.state.num}} --- {{msg}}</h1>
</div>
</template>
<style lang="less" scoped>
@color:blue;
h1{
color:@color,
}
</style>
<script>
export default{
data(){
return{
msg:"dazhaxie"
}
}
}
</script>
src/views/List.vue
<template>
<div>
<h1>List page</h1>
</div>
</template>
src/views/Detail.vue
<template>
<div>
<h1>Detail page</h1>
</div>
</template>
注意 运行时 运行 发布 文件中的 html 例如 dzx/views/index.html
效果图