Vue+ElementUI项目使用webpack输出MPA的方法


Posted in Javascript onAugust 27, 2019

一. 需求分析

为另一个项目提供可嵌入的功能单页,大部分页面使用时都是独立功能页,个别页面带有左侧边栏(相当于3-4个页面的整合形态),由于资源定位地址的限定,每个页面打包为单页后,入口html文件需要定制命名,且脚本和样式文件需要放在指定的路径下,公共资源地址也必须替换成特殊字符以适配母系统的调用逻辑(比如下面结构中应用jquery.min.js的路径可能是{{publicRoot}}/{{publicLib}}/jquery.minjs)。假设原工程中拥有AB这2个旧页面,现在需要开发CDE这3个页面,目录结构要求如下:

Vue+ElementUI项目使用webpack输出MPA的方法

蓝色部分为旧资源,绿色部分为新开发需求。

二. 原方案分析

原方案采用Vue+ElementUI进行开发,构建过程基本是零配置的,开发效率非常高,页面风格也统一,但零配置的构建过程只能生成SPA模式的应用,所以原方案的做法是:

将构建过程中需要定制的量提取到config.js文件中进行统一管理,大致形式如下:

//config.js
module.exports = {
  A:{
    publicPath:'{{publicRoot}}/{{publicLib}}'
    prodFileName:'A.html',
    entryKey:'public/A',
    entryPath:'public/A/A.js'
  },
  B:{
    //...
  }
  //...
}

开发过程中使用统一的路由文件router.js,打包过程中在main.js中引用对应页面的XX.router.spa.js作为路由,而将其他页面注释掉,打包时传入命令行参数--key=XXX,key值在打包脚本中被解析后从config.js中取出打包需要的设置参数,然后将目标页面打包为独立页面,其他页面虽然也在工程中,但并不参与打包。

// 入口文件src/main.js
import router from './pages/C/router.spa';
//import router from './pages/D/router.spa';
//import router from './pages/E/router.spa';

上述打包过程在使用中出现了很多问题:

  • 公共依赖没有剥离,vueElementUI会被打包进每一个单页面,使得每个打包出的index.js几乎有1.2MB大小,这种空间浪费是没必要的。
  • 公共样式没有形成独立文件,这使得每当有样式细节发生变更,就需要手动将每个页面逐一进行重新出包。
  • 页面增多后在main.js中会有很多独立路由,如果开发中进行了跨页面修改,很可能在main.js中激活的路由为C页面路由时,打包时--key参数的值却传成了D,这种情况并不会引起报错,但事实上构建结果确实错误的。
  • 由于入口文件保持main.js没有变化,所以在不同页面打包时,结果都输出在dist目录下,需要手动与母工程中的地址去匹配,操作繁琐。

三. 多页面改造3步走

上面的问题实际上都是因为原方案将一个多页面开发需求按照单页面应用来实现而造成的,需要对自动化构建工程进行一些定制。

1.分离webpack配置

本例中开发环境和最终打包的主要差异在于路由上,开发中由于可能需要进行跨页面开发,可以使用单入口和独立路由,而进行生产环境构建时则需要输出多页面应用,所以首先要做的就是将原本的webpack.config.js文件拆分为webpack.base.js,webpack.dev.js,webpack.prod.js三个文件,webpack.base.js为环境无差别的配置,然后依据构建模式的不同,使用webpack-merge插件将环境相关的配置与基本配置进行合并:

/*webpack.base.js示例*/
const argv = require('yargs-parser')(process.argv.slice(2));
const env_short = argv.env.all ? 'all' : argv.p ? 'prod':'dev';
const webpackConfig = require(`./config/webpack.${env_short}`);//根据-p属性加载webpack的dev配置或prod配置
const merge = require('webpack-merge');

//基本配置
const baseConfig = {
  //....
}

//输出合并后的配置
module.exports = merge(baseConfig, webpackConfig);

webpack.dev.js保持原本的SPA开发的设置即可满足需求。

2. 抽离外部引用

本例中较大的外部应用是vue和ElementUI,很多开发者一直使用自动化脚手架工具,并没有意识到这两个库作为外部依赖该如何引入工程。公共库的抽离需要在webpack配置中将其填写在external配置项中:

module.exports = {
 //...
 externals:{
   vue:'Vue',
   'element-ui':'ELEMENT'
 },
 //...
}

key为引用的模块名,value为这个模块引入后对应的全局命名,external配置项的含义是:请不要将这个模块注入编译后的JS文件里,对于源代码里出现的任何import/require这个模块的语句,请将它保留并根据模块化标准进行依赖方式适配 。

Tips:

Vue做为外部依赖时有很多构建包,本例中因为使用webpack进行了构建,没有在线编译模板的需求,所以不需要引入完整的Vue,而只需要引入压缩后的只包含运行时的版本vue.runtime.min.js即可。外部引入库时需要注意命名,比如上例中的ELEMENT,开发者通常会填写为自己在代码中使用的ElementUI而引起报错,当不确定名称时,有个简单的办法就是找一个CDN的资源看一下,通常代码最开始都是UMD规范的固定结构,很容易看到关键词(如下图所示)。

Vue+ElementUI项目使用webpack输出MPA的方法

然后将资源的CDN地址或是本地公共库地址加入到index.html中,你可以使用模板语法,然后从html-webpack-plugin插件实例化时传入定制参数:

<!--html文件模板-->
<body>
 <div id="app"></div>
 <script src="<%= htmlWebpackPlugin.options.vue_path %>"></script>
 <script src="<%= htmlWebpackPlugin.options.elementUI_path %>"></script>
 <script src="<%= htmlWebpackPlugin.options.tpl_entryPath %>/index.js"></script>
</body>
//webpack.prod.js
module.exports = {
  //...
 plugins: [
  new HtmlWebpackPlugin({
   template: 'src/index.html',//生成index.html时依据的模板
   filename: '.....',
   inject:false,
   tpl_entryPath:'....',
   vue_path:'.....',
   elementUI_path:'.....',
  }),
  //new BundleAnalyzerPlugin()
 ],
}

最终打包后生成的index.html文件大致如下:

<body>
 <div id="app"></div>
 <script src="{{publicRoot}}/{{publicLib}}/vue.min.js"></script>
 <script src="{{publicRoot}}/{{publicLib}}/element-ui.js"></script>
 <script src="public/A/A.js"></script>
</body>

如果第三方库从本地加载,则需要将/node_modules/element-ui/lib/index.js和/node_modules/vue/dist/vue.runtime.min.js两个依赖文件拷贝到lib文件夹中的对应地址,这样访问index.html时就可以以外部依赖的形式将其加载进来。样式文件的剥离直接使用插件完成即可,webpack4以前的版本使用extract-text-webpack-plugin,从4.0版本后统一使用mini-css-extract-plugin。

3. 为webpack定制多入口

多入口的配置是多页面应用打包的关键,由于打包结果存在嵌套目录,所以需要对entry对象的键值进行一些定制,打包后的路径信息是直接通过key值来定制的,同时需要实例化多个HtmlWebpackPlugin来为每一个入口文件生成一个对应的index.html访问入口,定制参数可以在实例化时传入:

//webpack.prod.js
module.exports = {
  entry:{
    'C/index':'./src/pages/C/C.entry.js',
    'DESK/D/index':'./src/pages/D/D.entry.js',
    'DESK/E/index':'./src/pages/E/E.entry.js'
  }
  //...
  plugins:[
    new HtmlWebpackPlugin({...paramsC}),
    new HtmlWebpackPlugin({...paramsD}),
    new HtmlWebpackPlugin({...paramsE}),
  ]
}

当然你可以将entry或plugins数组的组装过程剥离到其他文件中,然后直接引用:

Vue+ElementUI项目使用webpack输出MPA的方法

当然,每个页面的入口文件X.entry.js相当于旧方案中main.js文件中移除被注释掉的未启用路由信息后剩余的部分,它足以支撑每个单页独立被访问。

四. 小结

经上述改造后,在dist目录中输出的结构和需求中public目录下的结构就保持一致了,而且每个页面的index.js文件也缩小到了100K左右。当然你也可以使用node.js去编写一些自动化脚本,将后续的替换过程也自动化,或者继续对webpack的打包过程进行优化,本文就不再赘述了。

以上所述是小编给大家介绍的Vue+ElementUI项目使用webpack输出MPA的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
Locate a File Using a File Open Dialog Box
Jun 18 Javascript
jquery应该如何来设置改变按钮input的onclick事件
Dec 10 Javascript
js获取和设置属性的方法
Feb 20 Javascript
js获取input长度并根据页面宽度设置其大小及居中对齐
Aug 22 Javascript
jQuery实现复选框成对选择及对应取消的方法
Mar 03 Javascript
Bootstrap CSS布局之表单
Dec 17 Javascript
jQuery 表单序列化实例代码
Jun 11 jQuery
利用jQuery+localStorage实现一个简易的计时器示例代码
Dec 25 jQuery
vue 组件开发原理与实现方法详解
Nov 29 Javascript
es6中let和const的使用方法详解
Feb 24 Javascript
微信小程序返回上一级页面的实现代码
Jun 19 Javascript
jquery实现简单每周轮换的日历
Sep 10 jQuery
解决jquery validate 验证不通过后验证正确的信息仍残留在label上的方法
Aug 27 #jQuery
Net微信网页开发 使用微信JS-SDK获取当前地理位置过程详解
Aug 26 #Javascript
javascript实现抢购倒计时程序
Aug 26 #Javascript
VUE路由动态加载实例代码讲解
Aug 26 #Javascript
vue项目部署到nginx/tomcat服务器的实现
Aug 26 #Javascript
vue-router路由模式详解(小结)
Aug 26 #Javascript
vue+moment实现倒计时效果
Aug 26 #Javascript
You might like
Breeze 文章管理系统 v1.0.0正式发布
2006/12/14 PHP
Php Cookie的一个使用注意点
2008/11/08 PHP
php strnatcmp()函数的用法总结
2013/11/27 PHP
淘宝ip地址查询类分享(利用淘宝ip库)
2014/01/07 PHP
php使用ffmpeg向视频中添加文字字幕的实现方法
2016/05/23 PHP
PHP laravel中的多对多关系实例详解
2017/06/07 PHP
Yii2.0多文件上传实例说明
2017/07/24 PHP
Extjs中常用表单介绍与应用
2010/06/07 Javascript
JavaScript中String.prototype用法实例
2015/05/20 Javascript
JavaScript中判断函数、变量是否存在
2015/06/10 Javascript
JavaScript中的acos()方法使用详解
2015/06/14 Javascript
js实现图片旋转 js滚动鼠标中间对图片放大缩小
2017/07/05 Javascript
详解Vue.js Mixins 混入使用
2017/09/15 Javascript
js设置随机切换背景图片的简单实例
2017/11/12 Javascript
教你如何编写Vue.js的单元测试的方法
2018/10/17 Javascript
vue iview多张图片大图预览、缩放翻转
2019/07/13 Javascript
layui 图片上传+表单提交+ Spring MVC的实例
2019/09/21 Javascript
浅谈python中scipy.misc.logsumexp函数的运用场景
2016/06/23 Python
CentOS6.5设置Django开发环境
2016/10/13 Python
python构建深度神经网络(DNN)
2018/03/10 Python
Ubuntu下升级 python3.7.1流程备忘(推荐)
2018/12/10 Python
Centos部署django服务nginx+uwsgi的方法
2019/01/02 Python
Python Numpy 自然数填充数组的实现
2019/11/28 Python
使用Pycharm(Python工具)新建项目及创建Python文件的教程
2020/04/26 Python
Python实现计算图像RGB均值方式
2020/06/04 Python
怎么快速自学python
2020/06/22 Python
微信html5页面调用第三方位置导航的示例
2018/03/14 HTML / CSS
药品质量检测应届生求职信
2013/11/14 职场文书
总经理秘书工作职责
2013/12/26 职场文书
自我推荐信范文
2014/05/09 职场文书
中学教师师德承诺书
2014/05/23 职场文书
三好学生竞选稿范文
2019/08/21 职场文书
Python OpenCV快速入门教程
2021/04/17 Python
基于Python实现流星雨效果的绘制
2022/03/18 Python
Golang 切片(Slice)实现增删改查
2022/04/22 Golang
python解析照片拍摄时间进行图片整理
2022/07/23 Python