vue-cli
# vue-cli介绍
Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供:
- 通过
@vue/cli
实现的交互式的项目脚手架。 - 通过
@vue/cli
+@vue/cli-service-global
实现的零配置原型开发。 - 一个运行时依赖 (@vue/cli-service),该依赖:
- 可升级;
- 基于 webpack 构建,并带有合理的默认配置;
- 可以通过项目内的配置文件进行配置;
- 可以通过插件进行扩展。
- 一个丰富的官方插件集合,集成了前端生态中最好的工具。
- 一套完全图形化的创建和管理 Vue.js 项目的用户界面。
Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。
# CLI
CLI (@vue/cli
) 是一个全局安装的 npm 包,提供了终端里的 vue
命令。它可以通过 vue create
快速搭建一个新项目,或者直接通过 vue serve
构建新想法的原型。你也可以通过 vue ui
通过一套图形化界面管理你的所有项目。我们会在接下来的指南中逐章节深入介绍。
# CLI 服务
CLI 服务 (@vue/cli-service
) 是一个开发环境依赖。它是一个 npm 包,局部安装在每个 @vue/cli
创建的项目中。
CLI 服务是构建于 webpack (opens new window) 和 webpack-dev-server (opens new window) 之上的。它包含了:
- 加载其它 CLI 插件的核心服务;
- 一个针对绝大部分应用优化过的内部的 webpack 配置;
- 项目内部的
vue-cli-service
命令,提供serve
、build
和inspect
命令。
如果你熟悉 create-react-app (opens new window) 的话,@vue/cli-service
实际上大致等价于 react-scripts
,尽管功能集合不一样。
CLI 服务 (opens new window)章节涵盖了它的具体用法。
源码见: @vue/cli-service/lib/commands/serve.js
文件
# CLI 插件
CLI 插件是向你的 Vue 项目提供可选功能的 npm 包,例如 Babel/TypeScript 转译、ESLint 集成、单元测试和 end-to-end 测试等。Vue CLI 插件的名字以 @vue/cli-plugin-
(内建插件) 或 vue-cli-plugin-
(社区插件) 开头,非常容易使用。
当你在项目内部运行 vue-cli-service
命令时,它会自动解析并加载 package.json
中列出的所有 CLI 插件。
# 安装
npm install -g @vue/cli
yarn global add @vue/cli
npm i -g @vue/cli
yarn global upgrade --latest @vue/cli
2
3
4
5
6
升级插件
用法: upgrade [options] [plugin-name]
(试用)升级 Vue CLI 服务及插件
选项:
-t, --to <version> 升级 <plugin-name> 到指定的版本
-f, --from <version> 跳过本地版本检测,默认插件是从此处指定的版本升级上来
-r, --registry <url> 使用指定的 registry 地址安装依赖
--all 升级所有的插件
--next 检查插件新版本时,包括 alpha/beta/rc 版本在内
-h, --help 输出帮助内容
2
3
4
5
6
7
8
9
10
11
# 常用开发库的安装
npm i dayjs animate.css normalize.css lodash qrcode qs vue-i18n web-storage-cache codemirror clipboard nprogress qs element-plus moment axios echarts echarts-wordcloud screenfull vue-cookie mitt vue-count-to vue-splitpane
# 查看完整配置
# 多页面应用
# 1、vue.config.js配置pages
module.exports = {
pages: {
index: {
// page 的入口
entry: 'src/index/main.js',
// 模板来源
template: 'public/index.html',
// 在 dist/index.html 的输出
filename: 'index.html',
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index Page',
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
// 当使用只有入口的字符串格式时,
// 模板会被推导为 `public/subpage.html`
// 并且如果找不到的话,就回退到 `public/index.html`。
// 输出文件名会被推导为 `subpage.html`。
subpage: 'src/subpage/main.js'
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 2、抽离获取所有pages对象的工具类
const glob = require('glob')
let pages = {}
module.exports.pages = function () {
glob.sync('./src/pages/*/*.js').forEach(filepath => {
let fileList = filepath.split('/')
let fileName = fileList[fileList.length - 2]
pages[fileName] = {
entry: `src/pages/${fileName}/${fileName}.js`,
// 模板来源
template: `src/pages/${fileName}/${fileName}.html`,
// 在 dist/index.html 的输出
filename: process.env.NODE_ENV === 'development' ? `${fileName}.html` : `${fileName}/${fileName}.html`,
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', fileName]
}
})
return pages
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 3、拷贝静态文件
# htmlReplace.js
var fs = require('fs')
const glob = require('glob')
/**
* html文件替换
* @param src
* @param dst
*/
var callbackFile = function (src, dst, name, filepath) {
fs.readFile(src, 'utf8', function (error, data) {
if (error) {
// eslint-disable-next-line no-console
console.log(error)
return false
}
let regCss = new RegExp('/dist/css/' + name + '', 'g')
let regJs = new RegExp('/dist/js/' + name + '', 'g')
let htmlContent = data.toString().replace(regCss, `./css/${name}`).replace(regJs, `./js/${name}`)
fs.writeFile(dst, htmlContent, 'utf8', function (error) {
if (error) {
// eslint-disable-next-line no-console
console.log(error)
return false
}
// console.log('html重新写入成功')
if (src.indexOf('/index.html') === -1) {
fs.unlink(src, function () {
// console.log('html删除成功')
})
}
fs.unlink(filepath, function () { // css删除成功
})
fs.unlink(filepath + '.map', function () { // css删除成功
})
})
})
}
// 复制目录
glob.sync('./dist/js/*.js').forEach((filepath, name) => {
let fileNameList = filepath.split('.')
let fileName = fileNameList[1].split('/')[3]// 多页面页面目录
let thisDirectory = `./dist/${fileName}/${fileName}.html`// 多页面JS文件地存放址
let changeDirectory = `./dist/${fileName}/index.html`// 多页面JS文件地存放址
if (!fileName.includes('chunk-vendors')) {
callbackFile(thisDirectory, changeDirectory, fileName, filepath)
}
})
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
# jsCopy.js
var fs = require('fs')
const glob = require('glob')
/**
* JS文件拷贝
* @param src
* @param dst
*/
var callbackFile = function (src, dst) {
fs.readFile(src, 'utf8', function (error, data) {
if (error) {
// eslint-disable-next-line no-console
console.log(error)
return false
}
fs.writeFile(dst, data.toString(), 'utf8', function (error) {
if (error) {
// eslint-disable-next-line no-console
console.log(error)
return false
}
if (dst.includes('.map')) {
// let srcName = src.split('/')[4]
// fs.unlink(`./dist/js/${srcName}.map`,function () { // 删除map
// })
// fs.unlink(`./dist/js/${srcName}`,function () { // 删除js
// })
} else { // JS写入成功
callbackFile(dst, `${dst}.map`)
}
})
})
}
// 复制目录
glob.sync('./dist/js/*.js').forEach((filepath, name) => {
let fileNameList = filepath.split('.')
let fileName = fileNameList[1].split('/')[3]// 多页面页面目录
let copyName = filepath.split('/')[3]
let changeDirectory = `./dist/${fileName}/js`// 多页面JS文件地存放址
if (!fileName.includes('chunk-vendors')) {
// eslint-disable-next-line
fs.exists(changeDirectory, function (exists) {
if (exists) {
// console.log(`${fileName}下JS文件已经存在`)
callbackFile(filepath, `${changeDirectory}/${copyName}`)
} else {
fs.mkdir(changeDirectory, function () {
callbackFile(filepath, `${changeDirectory}/${copyName}`)
// console.log(`${fileName}下JS文件创建成功`)
})
}
})
}
})
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
# cssCopy.js
var fs = require('fs')
const glob = require('glob')
/**
* css文件拷贝
* @param src
* @param dst
*/
var callbackFile = function (src, dst) {
fs.readFile(src, 'utf8', function (error, data) {
if (error) {
// eslint-disable-next-line no-console
console.log(error)
return false
}
let regImage = new RegExp('../img/', 'g');
let cssContent = data.toString().replace(regImage, `../../img/`);
fs.writeFile(dst, cssContent, 'utf8', function (error) {
if (error) {
// eslint-disable-next-line no-console
console.log(error)
PromiseRejectionEvent(error)
return false
}
// console.log('CSS写入成功')
fs.unlink(src, function () { // css删除成功
})
})
})
}
// 复制目录
glob.sync('./dist/css/*.css').forEach((filepath, name) => {
let fileNameList = filepath.split('.')
let fileName = fileNameList[1].split('/')[3]// 多页面页面目录
let copyName = filepath.split('/')[3]
let changeDirectory = `./dist/${fileName}/css`// 多页面JS文件地存放址
if (!fileName.includes('chunk-vendors')) {
/* eslint-disable-next-line */
fs.exists(changeDirectory, function (exists) {
if (exists) {
// console.log(`${fileName}下CSS文件已经存在`)
callbackFile(filepath, `${changeDirectory}/${copyName}`)
} else {
fs.mkdir(changeDirectory, function () {
callbackFile(filepath, `${changeDirectory}/${copyName}`)
// console.log(`${fileName}下CSS文件创建成功`)
})
}
})
}
})
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
# 4、写自动化构建语句
"scripts": {
"serve": "vue-cli-service serve --open ",
"build": "vue-cli-service build && node util/jsCopy.js && node util/cssCopy.js && node util/htmlReplace.js",
"lint": "vue-cli-service lint"
},
2
3
4
5
参考:
pages配置参考 | Vue CLI (vuejs.org) (opens new window)
seizeDev/vue-more-pages: 多页面vue项目,打包后每个页面也单独文件夹 (github.com) (opens new window)
参考: