共计 8315 个字符,预计需要花费 21 分钟才能阅读完成。
本文梗概
Vue 是很好用,然而以往的都是单页面利用,这就导致了一些传统的我的项目移植艰难,一些用了 JQ 的插件的等等写法都要扭转。也还用专门找到绝对于的 Vue 的插件才行,这次的 Cli 3.0 能够在原来我的项目的根底上间接移植,十分不便。
在本文中,会讲到如下内容:
Vue 多页面的劣势与劣势
Cli 3.0 的根本配置
Cli 3.0 多页面的打包上线
Cli 3.0 的目录解析
如何晋升构建效率
受众人群:常常用 Vue 单页面开发的人员,对多页面有趣味,且理论工作中有需要。老我的项目想前后端拆散,思考效率又不想用单页面重写的开发人员。
@[toc]
前言
Vue.js 3.0 反对单页面也反对多页面,不过对用久了 2.0 人的来说,开始还会有一点不习惯。创立形式、目录构造、运行命令都有差别。
本文将围绕理论多页面开发案例,分析多页面从构建到上线一条龙的过程。自定义配置有蛮多种,这里只是只说其中一种。供大家参考应用。
本篇文章的目录构造外围如下:
一、简述优劣势
单页面利用开发(SPA)
- 概念:只有一个 HTML 页面,所以跳转的形式是组件之间的切换;
- 长处:跳转晦涩,组件化开发,组件可复用,开发便捷;
- 毛病:首屏加载过慢,SEO 优化不好。
多页面利用开发(MPA)
- 概念:有多个页面,跳转形式是页面之间的跳转;
- 长处:组件化开发,组件可复用,开发便捷,首屏加载快,SEO 优化好;
- 毛病:跳转是整个页面刷新。
以上一比照,多页面还是有蛮多劣势的,特地是在老我的项目想前后端拆散的时候,尤为突出。尽管近几年 Vue 等框架衰亡,然而以前用 JQ、JS、其余插件写的我的项目也不少。大多都是没有拆散的,前后端分工不明确,甚至导致前端只是个写页面的,丢给跟后盾去套数据。艰深点来说就是个页面仔、成果仔了。
多页面(MPA)完满地解决了这个问题,能够疾速地在之前的状况下应用,并存。
二、目录文件解析
新建我的项目,执行:
$ vue create demo
这里选默认第一个就好。
接下来用哪个形式都行,我是习惯用 npm。
期待下载实现,初始化的目录(为了大家分明地比照多页面革新后的,我把初始化跟革新后都列出来来供大家比对剖析):
├── node_modules npm install 生成
└── public 打包所需动态资源
├── index.html 模板文件
└── favicon.ico 浏览器图标
└── src
└── assets 我的项目动态资源
├── logo.png
├── components 业务组件
├── App.vue
├── main.js
├── .gitignore Git 提交时疏忽配置
├── babel.config.js babel 配置
├── package.json
├── package-lock.json
├── README.md
└── vue.config.js (须要自行创立)
跟 2.0 相比,目录简化许多,webpack 配置也集成到 node_modules 去了。
留有一个配置入口,就是 vue.config.js 文件,这须要自行创立,
如没有就会用默认的 http://localhost:8080/。
也就是 2.0 中 config/Index.js 的配置移到这里去了,包含代理都在这写。
这里是曾经革新成多页面的目录:
如上图,目录大体跟初始化的差不多,惟一的就是配置的在 src 中页面,一个目录生产进去就是一个独自的 HTML。
具体对应形容:
├── dist 打包后目录
├── node_modules npm install 生成
└── public 打包所需动态资源
└── favicon.ico 浏览器图标
└── src
└── assets 我的项目动态资源
├── logo.png
├── components 业务组件
├── pages 页面文件
└── index 单个页面目录
└── index.html 单个页面目录
└── index.js 单个页面入口 js (相当于 2. 0 的 main.js)
└── index.vue 此页面页面组件
├── util 配置搁置目录
└── axiosTool.js 申请封装
└── cssCopy.js 多页面 css 配置文件
└── getPages.js 多页面 模板 配置文件
└── htmlReplace.js 多页面 html 生成规定配置文件
└── jsCopy.js 多页面 js 配置文件
├── .gitignore Git 提交时疏忽配置
├── babel.config.js babel 配置
├── package.json
├── package-lock.json
├── postcss.config.js
├── README.md
└── vue.config.js
3.0 的目录构造简洁,多页面的目录能够自行批改。革新后,本来的 public 的 index.html 就不须要了,每个页面都有一个 index.html。
三、革新配置
配置文件
配置分为四个模块,CSS 拷贝、JS 拷贝、HTML 规定以及获取页面。
在 util 中新建 cssCopy.js、jsCopy.js、htmlReplace.js、getPages.js 文件。引入 Node 的 fs 跟 glob 模块:
### 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){console.log(error);
return false;
}
fs.writeFile(dst,data.toString(),'utf8',function(error){if(error){console.log(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 文件地寄存址
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 文件创建胜利 `)
});
}
});
});
### jsCopy.js:var fs = require('fs');
const glob = require('glob');
/**
* JS 文件拷贝
* @param src
* @param dst
*/
let remoevePath = null
var callbackFile = function(src, dst){fs.readFile(src,'utf8',function(error,data){if(error){console.log(error);
return false;
}
fs.writeFile(dst,data.toString(),'utf8',function(error){if(error){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')){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 文件创建胜利 `)
});
}
});
}
});
### 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){console.log(error);
return false;
}
let regCss = new RegExp("\/css\/"+name+"",'g');
let regJs = new RegExp("\/js\/"+name+"",'g');
let htmlContent = data.toString().replace(regCss,`\.\/css\/${name}`).replace(regJs,`\.\/js\/${name}`);
fs.writeFile(dst,htmlContent,'utf8',function(error){if(error){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)
}
});
### getPages.js
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
};
最初在 vue.config.js 中引入:
let pageMethod = require('./util/getPages.js');
pages = pageMethod.pages();
module.exports = {pages}
以上的 jsCopy、cssCopy、htmlReplace 是在打包的时候执行的,在 package.json 中退出。
到这里,多页面的配置批改就完了。
革新的原理就是,利用 Node 的文件系统把生成的文件,进行挪动复制、组合,依照一个页面一个目录,一个页面三个文件,以达到能组件化开发,打包后多个 HTML 文件。
运行
$ npm run serve
1. 查看
上面是 src 目录文件:
一个目录一个 HTML 页面,目录中 index.html 是入口文件,相当于单页面中的 index.html。
index.js 就相当于单页面的 man.js。index.vue 就相当于单页面中的内容组件了。
这里引入:
也就是一个页面一个 Vue 实例,这目录中的三个文件名字最好统一,打包后就是一个页面。
index.html 中能够把老我的项目中的 JS、CSS 全副在这引入。内容局部的就间接复制到 index.vue 中,有专用的局部,头部底部什么的就组件放在 components 中在 index.vue 中调用就行了。
2. 留神
除了 Vue 路由无奈应用之外,其余都是能够应用的。包含 Vuex,用法跟单页面的一样。只是每个入口 JS 文件中要注册一次罢了。
接下来就是页面跳转问题,跳转间接用 a 标签。
目录下记得用绝对路径。多页面构建举荐用绝对路径。因打包后目录起因,开发环境跟生产环境中的路由有差别。也就是开发环境须要加上 .html 后缀,生产环境则不须要。也就是两种写法。
<li><a href="/index.html/?orderNo=2"> index 页面,dev 的时候可用的写法 </a></li>
<li><a href="/index/?orderNo=2"> index 页面,production 可用的写法 </a></li>
就是在 dev 时候就等于这样:
- dev 中页面跳转须要加 .html 文件后缀
- production 跳转不须要文件后缀
这也就产生了一个问题,本人的 dev 调试的时候是不须要后缀的,要上线的时候得把所有的 a 标签跳转链接的后缀加上,这就太麻烦了。
办法有蛮多,我这用的是判断 production 来替换。
/**
* 打包后路由修改
* @returns {string}
*/
export function urlRouter (){
let urlRouters = ".html";
if (process.env.NODE_ENV === "production") {
// 为线上环境批改配置...
urlRouters=""
}
return urlRouters
}
这样就全副对立写法了。反正就线上不须要后缀,在 dev 时候要后缀,大家自行想方法解决这问题。不肯定非用我这办法。
<a :href="`/index${configTool.urlRouter()}/?id=${id}`" >
四、打包上线
先来看一下打包之后的 dist 目录:
这两个目录是页面目录
外面就是该页面的资源文件。
生成环境拜访是这样:
因为每个目录下都有该页面的资源,一个目录下都有 index.html。须要在 dist 中加一个总入口直达文件 index.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
window.location.href="/index/"
</script>
</body>
</html>
到此,上线公布就实现了。把 dist 目录的文件丢到服务器就能够了,举荐用的是放在根目录,不然会找不到资源。官网也举荐多页面利用的状况下防止用相对路径。
官网文档中正告:
五、进步构建效率
进步的形式有很多种,这里举荐应用 webpack-parallel-uglify-plugin 插件。
优化原理
默认状况下 webpack 应用 UglifyJS 插件进行代码压缩,但因为其采纳单线程压缩,速度很慢。
咱们能够改用 webpack-parallel-uglify-plugin 插件,它能够并行运行 UglifyJS 插件,从而更加充沛、正当的应用 CPU 资源,从而大大减少构建工夫。
操作步骤
1. 执行如下命令装置 webpack-parallel-uglify-plugin:
npm i webpack-parallel-uglify-plugin
2. 关上 vue.config.js 文件,并作如下批改:
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
//....
// webpack 提供的 UglifyJS 插件删不删都行,轻易,能够并存
//new UglifyJsPlugin({
// uglifyOptions: {
// compress: {
// warnings: false
// }
// },
// sourceMap: config.build.productionSourceMap,
// parallel: true
//}),
// 减少 webpack-parallel-uglify-plugin 来替换
new ParallelUglifyPlugin({
cacheDir: '.cache/',
uglifyJS:{
output: {comments: false},
compress: {warnings: false}
}
}),
3. 保留后再次构建我的项目,能够感觉到速度有所放慢。
六、总结
多页面开发让前后端拆散更加变得更加不便,对已有我的项目进行拆散,不须要做太多的批改;让该我的项目不再依附后端去套,前期保护也不便。
对于前端来说,角色更加重要,不再会再呈现,前端写好页面丢给后端,后端开发再嵌入我的项目中去,导致成果不一样,后续有扩大加进去又导致款式抵触;对于后端来说,也不须要做前端的事件。二者分清,各司其职。
最初奉上本文测试的 Demo 哦,心愿能帮到大家。有什么疑难可评论喔!
http://download.lllomh.com/cliect/#/product/J417131589328672,获取残缺 demo