1 Установите vue-cli3.0
0 Зеркало Таобао
npm install -g cnpm --registry=https://registry.npm.taobao.org
1 Установите vue-кли
npm install -g @vue/cli
# OR
yarn global add @vue/cli
2 Посмотреть версию
vue --version
3 проекта сборки vue-cli
vue create vue-demo
Выберите значение по умолчанию и запустите службу
4 Структура каталогов
├── README.md # 说明
|-- dist # 打包后文件夹
├── babel.config.js # babel语法编译
├── package-lock.json
├── package.json
├── public # 静态文件夹
│ ├── favicon.ico
│ └── index.html #入口页面
└── src # 源码目录
├── App.vue - 页面
├── assets - 静态目录
│ └── logo.png
├── components 组件
│ └── HelloWorld.vue
└── main.js # 入口文件,加载公共组件
|-- vue.config.js # 配置文件
|-- .eslintrc.js # ES-lint校验
|-- .gitignore # git忽略上传的文件格式
|-- babel.config.js # babel语法编译
|-- package.json # 项目基本信息
Стандартная структура каталогов vue
2 Переменные среды и шаблоны
0 Введение
При фактическом запуске vue-cli под npm определены переменные окружения и режимы, что удобно для построения кода
После открытия package.json
Среда, которую мы описываем здесь, находится в сценариях
1 режим
Это важная концепция в проекте Vue CLI. По умолчанию проект Vue CLI имеет три режима:
-
developmentрежим используется дляvue-cli-service serve -
productionрежим используется дляvue-cli-service buildа такжеvue-cli-service test:e2e -
testрежим используется дляvue-cli-service test:unit
Вы можете пройти
--modeПараметр options переопределяет режим по умолчанию для командной строки. Например, если вы хотите использовать переменные среды разработки в команде сборки, добавьтеpackage.jsonдобавлено в скрипт
``` "dev-build": "vue-cli-service build --mode development", ```
2 звонка
Итак, как мы называем это в коде и сценарии его применения?
process.env.NODE_ENV
Таким образом, мы можем получить его переменные окружения
3 сцены
Создаем новый конфиг в директории src
Создайте каталог env.js
let baseUrl = '';
const env = process.env
if (env.NODE_ENV == 'development') {
baseUrl = `http://192.168.1.1`; // 开发环境地址
} else if (env.NODE_ENV == 'production') {
baseUrl = `http://192.168.1.2`; //生产环境地址
} else if (env.NODE_ENV == 'test') {
baseUrl = `http://192.168.1.3`; //测试环境地址
}
export {
baseUrl,
env
}
Затем мы можем напрямую использовать различные среды
3 Обработка, совместимая с IE, удалить консоль
npm install @babel/polyfill -s
npm install babel-plugin-transform-remove-console -s
Настроено в babel.config.js следующим образом
const plugins = []
if (process.env.NODE_ENV === 'production') {
// 移除console.log
plugins.push('transform-remove-console')
}
module.exports = {
presets: [
['@vue/app', {
polyfills: [
'es6.array.iterator',
'es6.promise',
'es7.promise.finally',
'es6.symbol',
'es6.array.find-index',
'es7.array.includes',
'es6.string.includes',
'es6.array.find',
'es6.object.assign'
]
}]
],
plugins
}
4 базовая конфигурация vue-cli
Создайте новую папку vue.config.js, чтобы начать настройку vue-cli.
module.exports = {
//部署应用包时的基本 URL
publicPath: process.env.NODE_ENV === 'production' ? '/online/' : './',
//当运行 vue-cli-service build 时生成的生产环境构建文件的目录
outputDir: 'dist',
//放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
assetsDir: 'assets',
// eslint-loader 是否在保存的时候检查 安装@vue/cli-plugin-eslint有效
lintOnSave: true,
//是否使用包含运行时编译器的 Vue 构建版本。设置true后你就可以在使用template
runtimeCompiler: true,
// 生产环境是否生成 sourceMap 文件 sourceMap的详解请看末尾
productionSourceMap: false,
}
5 Добавить псевдоним
Создайте новую папку vue.config.js, чтобы начать настройку vue-cli.
1 Конфигурация псевдонима
const path = require('path'); //引入path模块(node)
const resolve = (dir) => path.join(__dirname, dir); //将文件组成绝对路径
module.exports = {
chainWebpack: config => {
// 添加别名
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('components', resolve('src/components'))
}
}
2 сценария применения
Структура каталогов может быть наложена друг на друга, и после достижения каталога
Например: только каталог env.js
import {baseUrl} from '../config/env'
Но мы не обязательно гарантируем, что каталог находится так близко, так что как с этим быть
// @代表src目录下,即可这样调用
import {baseUrl} from '@/config/env'
7 Оптимизация - внешние параметры конфигурации
Предотвратить упаковку некоторых импортированных пакетов (пакетов) в бандлы, но получить эти зависимости расширения извне во время выполнения (runtime)
### Использование в проекте > Для общих проектов vue мы извлечем некоторые пакеты фреймворка. Например:
- Vue
- ELEMENT
- VueRouter
- Vuex
- axios
1 Знакомство с фреймворком
Мы извлекаем некоторые пакеты, на которые ссылается аутсорсинг, и размещаем их в открытом доступе.
2 Редактировать внешние
Мы находимся в vue.config.
module.exports = {
configureWebpack: config => {
config.externals = {
'vue': 'Vue',
'element-ui': 'ELEMENT',
'vue-router': 'VueRouter',
'vuex': 'Vuex',
'axios': 'axios'
}
}
3 Представляем CDN
Затем в это время нам нужно поместить его в public/index.html.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/element-ui/2.5.4/theme-chalk/index.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/animate/3.5.2/animate.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/1.0.0/index.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/1.0.0/iconfont.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/1.0.0/index.css">
<title>vue-demo</title>
</head>
<body>
<noscript>
<strong>We're sorry but vue-demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script src="<%= BASE_URL %>cdn/vue/2.5.2/vue.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/vuex/2.4.1/vuex.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/vue-router/3.0.1/vue-router.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/axios/1.0.0/axios.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/element-ui/2.5.4/index.js" charset="utf-8"></script>
</body>
</html>
8 Оптимизация - Включите сжатие Gzip
1. Введение
По сравнению с 2.0, vue cli 3.0 претерпел много изменений, наиболее очевидным из которых является исчезновение папки сборки, которая заменена на vue.config.js в корневом каталоге.
Запишите процесс настройки Gzip здесь
npm i -D compression-webpack-plugin
2 Изменить vue.config.js
const CompressionPlugin = require("compression-webpack-plugin")
module.exports = {
configureWebpack:config=>{
if(process.env.NODE_ENV === 'production'){
return{
plugins: [
new CompressionPlugin({
test:/\.js$|\.html$|.\css/, //匹配文件名
threshold: 10240,//对超过10k的数据压缩
deleteOriginalAssets: false //不删除源文件
})
]
}
}
},
}
3 nginx настроить gzip
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
Строка 1: Включите Gzip
Строка 2: Не сжимать критическое значение, сжимаются только те, что больше 1К, вообще менять не нужно
Строка 3: буфер, то есть, гм, забудь, не объясняй, не меняй
Строка 4: Если используется обратный прокси, конечная коммуникация HTTP/1.0.Если вам это нужно, то можете не читать мой научно-популярный текст, если у вас есть это предложение, просто прокомментируйте его>, по умолчанию HTTP /1.1
Строка 5: Уровень сжатия, от 1 до 10, чем больше число, тем лучше сжатие, и чем больше время, вы можете менять его по настроению.
Строка 6: Тип файла для сжатия, просто компенсируйте то, что отсутствует. Есть два способа написать JavaScript. Лучше написать их все. Всегда есть люди, жалующиеся на то, что файлы js не сжимаются. На самом деле это достаточно написать еще один формат.
Строка 7: относится к службам кэширования, таким как Squid. Если она включена, в заголовок будет добавлено «Vary: Accept-Encoding». Мне это не нужно.
Строка 8: IE6 не очень дружелюбен к Gzip, больше не используйте Gzip.
9 Оптимизация - Загрузка выше сгиба
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no">
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/element-ui/2.5.4/theme-chalk/index.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/animate/3.5.2/animate.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/1.0.0/index.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/1.0.0/iconfont.css">
<link rel="stylesheet" href="<%= BASE_URL %>cdn/iconfont/1.0.0/index.css">
<title>vue-demo</title>
<style>
html,
body,
#app {
height: 100%;
margin: 0px;
padding: 0px;
}
.chromeframe {
margin: 0.2em 0;
background: #ccc;
color: #000;
padding: 0.2em 0;
}
#loader-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 999999;
}
#loader {
display: block;
position: relative;
left: 50%;
top: 50%;
width: 150px;
height: 150px;
margin: -75px 0 0 -75px;
border-radius: 50%;
border: 3px solid transparent;
/* COLOR 1 */
border-top-color: #FFF;
-webkit-animation: spin 2s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-ms-animation: spin 2s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-moz-animation: spin 2s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-o-animation: spin 2s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
animation: spin 2s linear infinite;
/* Chrome, Firefox 16+, IE 10+, Opera */
z-index: 1001;
}
#loader:before {
content: "";
position: absolute;
top: 5px;
left: 5px;
right: 5px;
bottom: 5px;
border-radius: 50%;
border: 3px solid transparent;
/* COLOR 2 */
border-top-color: #FFF;
-webkit-animation: spin 3s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-moz-animation: spin 3s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-o-animation: spin 3s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-ms-animation: spin 3s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
animation: spin 3s linear infinite;
/* Chrome, Firefox 16+, IE 10+, Opera */
}
#loader:after {
content: "";
position: absolute;
top: 15px;
left: 15px;
right: 15px;
bottom: 15px;
border-radius: 50%;
border: 3px solid transparent;
border-top-color: #FFF;
/* COLOR 3 */
-moz-animation: spin 1.5s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-o-animation: spin 1.5s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-ms-animation: spin 1.5s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
-webkit-animation: spin 1.5s linear infinite;
/* Chrome, Opera 15+, Safari 5+ */
animation: spin 1.5s linear infinite;
/* Chrome, Firefox 16+, IE 10+, Opera */
}
@-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: rotate(0deg);
/* IE 9 */
transform: rotate(0deg);
/* Firefox 16+, IE 10+, Opera */
}
100% {
-webkit-transform: rotate(360deg);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: rotate(360deg);
/* IE 9 */
transform: rotate(360deg);
/* Firefox 16+, IE 10+, Opera */
}
}
@keyframes spin {
0% {
-webkit-transform: rotate(0deg);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: rotate(0deg);
/* IE 9 */
transform: rotate(0deg);
/* Firefox 16+, IE 10+, Opera */
}
100% {
-webkit-transform: rotate(360deg);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: rotate(360deg);
/* IE 9 */
transform: rotate(360deg);
/* Firefox 16+, IE 10+, Opera */
}
}
#loader-wrapper .loader-section {
position: fixed;
top: 0;
width: 51%;
height: 100%;
background: #7171C6;
/* Old browsers */
z-index: 1000;
-webkit-transform: translateX(0);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: translateX(0);
/* IE 9 */
transform: translateX(0);
/* Firefox 16+, IE 10+, Opera */
}
#loader-wrapper .loader-section.section-left {
left: 0;
}
#loader-wrapper .loader-section.section-right {
right: 0;
}
/* Loaded */
.loaded #loader-wrapper .loader-section.section-left {
-webkit-transform: translateX(-100%);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: translateX(-100%);
/* IE 9 */
transform: translateX(-100%);
/* Firefox 16+, IE 10+, Opera */
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
}
.loaded #loader-wrapper .loader-section.section-right {
-webkit-transform: translateX(100%);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: translateX(100%);
/* IE 9 */
transform: translateX(100%);
/* Firefox 16+, IE 10+, Opera */
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
}
.loaded #loader {
opacity: 0;
-webkit-transition: all 0.3s ease-out;
transition: all 0.3s ease-out;
}
.loaded #loader-wrapper {
visibility: hidden;
-webkit-transform: translateY(-100%);
/* Chrome, Opera 15+, Safari 3.1+ */
-ms-transform: translateY(-100%);
/* IE 9 */
transform: translateY(-100%);
/* Firefox 16+, IE 10+, Opera */
-webkit-transition: all 0.3s 1s ease-out;
transition: all 0.3s 1s ease-out;
}
/* JavaScript Turned Off */
.no-js #loader-wrapper {
display: none;
}
.no-js h1 {
color: #222222;
}
#loader-wrapper .load_title {
font-family: 'Open Sans';
color: #FFF;
font-size: 19px;
width: 100%;
text-align: center;
z-index: 9999999999999;
position: absolute;
top: 60%;
opacity: 1;
line-height: 30px;
}
#loader-wrapper .load_title span {
font-weight: normal;
font-style: italic;
font-size: 13px;
color: #FFF;
opacity: 0.5;
}
</style>
</head>
<body>
<noscript>
<strong>We're sorry but vue-demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
<div id="loader-wrapper">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div class="load_title">正在加载 vue,请耐心等待
<br>
<span>V1.3</span>
</div>
</div>
</div>
<!-- built files will be auto injected -->
<script src="<%= BASE_URL %>cdn/vue/2.5.2/vue.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/vuex/2.4.1/vuex.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/vue-router/3.0.1/vue-router.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/axios/1.0.0/axios.min.js" charset="utf-8"></script>
<script src="<%= BASE_URL %>cdn/element-ui/2.5.4/index.js" charset="utf-8"></script>
</body>
</html>
10 препроцессоров (Sass/Less/Stylus)
# Sass
npm install -D sass-loader node-sass
# Less
npm install -D less-loader less
# Stylus
npm install -D stylus-loader stylus
然后你就可以导入相应的文件类型,或在 *.vue 文件中这样来使用:
<style scoped lang="stylus">
.personal
position relative
.banner-red
width 100%
height 100px
</style>
Автоматическое развертывание 11 узлов
1 Установите scp2
npm install scp2 --save-dev
2 Настройте список серверов
deploy/products.js
/*
*定义多个服务器账号 及 根据 SERVER_ID 导出当前环境服务器账号
*/
const SERVER_LIST = [
{
id: 0,
name: 'A-测试环境',
host: 'xxx.xxx.xxx.xxx', // ip
port: 22,// 端口
username: 'root', // 登录服务器的账号
password: 'root', // 登录服务器的账号
path: 'xxx/xxx/xxx', // 发布至静态服务器的项目路径
del: ['/var/www/jx/admin/js', '/var/www/jx/admin/css'] // 删除这些无法替换的
},
{
id: 1,
name: 'B-生成环境',
host: 'xxx.xxx.xxx.xxx', // ip
port: 22,// 端口
username: 'root', // 登录服务器的账号
password: 'root', // 登录服务器的账号
path: 'xxx/xxx/xxx', // 发布至静态服务器的项目路径
del: ['/var/www/jx/admin/js', '/var/www/jx/admin/css'] // 删除这些无法替换的
},
];
module.exports = SERVER_LIST;
3 Создайте сценарий автоматического развертывания scp2
const scpClient = require('scp2');
const ora = require('ora');
const chalk = require('chalk');
const servers = require('./products');
let server = servers[process.env.NODE_ENV === 'prod' ? 1 : 0];
const spinner = ora('正在发布到' + (process.env.NODE_ENV === 'prod' ? '生产' : '测试') + '服务器...');
var Client = require('ssh2').Client;
var conn = new Client();
conn
.on('ready', function() {
// rm 删除dist文件,\n 是换行 换行执行 重启nginx命令 我这里是用docker重启nginx
let dels = ""
server.del.forEach(item => {
dels += `rm -rf ${item}\n`;
});
conn.exec(dels, function (
err,
stream
) {
if (err) throw err;
stream
.on('close', function(code, signal) {
// 在执行shell命令后,把开始上传部署项目代码放到这里面
spinner.start();
scpClient.scp(
'dist/',
{
host: server.host,
port: server.port,
username: server.username,
password: server.password,
path: server.path
},
function (err) {
spinner.stop();
if (err) {
console.log(chalk.red('发布失败.\n'));
throw err;
} else {
console.log(chalk.green('Success! 成功发布到' + (process.env.NODE_ENV === 'prod' ? '生产' : '测试') + '服务器! \n'));
}
}
);
conn.end();
})
.on('data', function (data) {
console.log('STDOUT: ' + data);
})
.stderr.on('data', function (data) {
console.log('STDERR: ' + data);
});
});
})
.connect({
host: server.host,
port: server.port,
username: server.username,
password: server.password
});
4 Добавить инструкции
Добавить директиву в package.json
"upload-test": "NODE_ENV=test node ./deploy",
"upload-prod": "NODE_ENV=prod node ./deploy"
5 Использование команд
Выпуск тестовой среды
npm run upload-test
12 Node автоматизировал новую страницу
Каждый раз, когда вам нужно написать общую структуру vue, я думаю, что это все еще хлопотное дело. Как правило, вы можете использовать vscode для создания нового, но я думаю, что node более удобен.
1 Настройте свой шаблон
generateTpl.js
Для установки личных привычек можно написать несколько шаблонов, здесь мы демонстрируем только один
exports.table = function(pageName) {
var tpl = `<template>
<basic-container>
<h3>${pageName}-page</h3>
</basic-container>
</template>
<script>
export default {
data() {
return {
};
},
methods: {
}
};
</script>
<style scoped>
</style>
`
return tpl;
}
2 Установить опросник
npm install inquirer --save-dev
3 Создайте автоматический новый скрипт
var path = require('path');
var fs = require('fs');
var generateTpl = require('./generateTpl');
var inquirer = require('inquirer')
const createPage = {
template: "table",
init: function() {
const promptName = [{
type: 'input',
message: '模板的名称',
name: 'templateName',
filter: function (val) {
return val.toLowerCase()
}
}]
const promptList = [{
type: 'list',
message: '请选择一种模版',
name: 'template',
choices: ['表格', '表单'],
filter: function (val) {
return val.toLowerCase()
}
}]
inquirer.prompt(promptName).then(name => {
inquirer.prompt(promptList).then(anwsers => {
this.initParams(name.templateName);
if (anwsers.template==='表格') {
this.template = "table"
}else{
this.template = "form"
}
this.getAllPage();
this.generatePage();
})
})
},
initParams: function (templateName) {
this.pageName = templateName;
this.pageDir = path.join(__dirname, '../src/views');
this.allPages = ""
},
getAllPage: function() {
this.allPages = fs.readdirSync(this.pageDir);
},
generatePage: function(){
if(this.allPages.indexOf(this.pageName) == -1) {
this.toGenerageDir();
} else {
console.error('当前页面已经存在了');
}
},
toGenerageDir: function(){
try{
fs.mkdir(path.join(this.pageDir, this.pageName), function(err){
if(err){
console.error(err);
return;
}
this.toGenerateFiles();
console.log('页面创建完成');
}.bind(this));
}catch(e){
console.error(e);
}
},
toGenerateFiles: function() {
// 选择模板
var vueFile = path.join(this.pageDir, this.pageName, `index.vue`);
var imageDir = path.join(this.pageDir, this.pageName, 'images')
// 创建文件
fs.writeFileSync(vueFile, generateTpl[this.template](this.pageName));
fs.mkdirSync(imageDir)
}
}
createPage.init();
3 Добавить инструкции
Добавить директиву в package.json
"create-page": "node create-page/create-page.js",
4 Использование команд
npm run create-page