Vue CLI3基础学习之pages构建多页应用


Posted in Javascript onJune 02, 2019

前言

首先我们可以把多页应用理解为由多个单页构成的应用,而何谓多个单页呢?其实你可以把一个单页看成是一个 html 文件,那么多个单页便是多个 html 文件,多页应用便是由多个 html 组成的应用,如下图所示

Vue CLI3基础学习之pages构建多页应用

既然多页应用拥有多个 html ,那么同样其应该拥有多个独立的入口文件、组件、路由、 vuex 等。没错,说简单一点就是多页应用的每个单页都可以拥有单页应用 src 目录下的文件及功能,我们来看一下一个基础多页应用的目录结构

├── node_modules               # 项目依赖包目录
├── build                      # 项目 webpack 功能目录
├── config                     # 项目配置项文件夹
├── src                        # 前端资源目录
│   ├── images                 # 图片目录
│   ├── components             # 公共组件目录
│   ├── pages                  # 页面目录
│   │   ├── page1              # page1 目录
│   │   │   ├── components     # page1 组件目录
│   │   │   ├── router         # page1 路由目录
│   │   │   ├── views          # page1 页面目录
│   │   │   ├── page1.html     # page1 html 模板
│   │   │   ├── page1.vue      # page1 vue 配置文件
│   │   │   └── page1.js       # page1 入口文件
│   │   ├── page2              # page2 目录
│   │   └── index              # index 目录
│   ├── common                 # 公共方法目录
│   └── store                  # 状态管理 store 目录
├── .gitignore                 # git 忽略文件
├── .env                       # 全局环境配置文件
├── .env.dev                   # 开发环境配置文件
├── .postcssrc.js              # postcss 配置文件
├── babel.config.js            # babel 配置文件
├── package.json               # 包管理文件
├── vue.config.js              # CLI 配置文件
└── yarn.lock                  # yarn 依赖信息文件

二、多入口

在单页应用中,我们的入口文件只有一个, CLI 默认配置的是 main.js ,但是到了多页应用,我们的入口文件便包含了 page1.js 、 page2.js 、 index.js 等,数量取决于 pages 文件夹下目录的个数,这时候为了项目的可拓展性,我们需要自动计算入口文件的数量并解析路径配置到 webpack 中的 entry 属性上,如:

module.exports = {
 ...
 
 entry: {
  page1: '/xxx/pages/page1/page1.js',
  page2: '/xxx/pages/page2/page2.js',
  index: '/xxx/pages/index/index.js',
 },
 
 ...
}

那么我们如何读取并解析这样的路径呢,这里就需要使用工具和函数来解决了。我们可以在根目录新建 build 文件夹存放 utils.js 这样共用的 webpack 功能性文件,并加入多入口读取解析方法

/* utils.js */
const path = require('path');

// glob 是 webpack 安装时依赖的一个第三方模块,该模块允许你使用 * 等符号,
// 例如 lib/*.js 就是获取 lib 文件夹下的所有 js 后缀名的文件
const glob = require('glob');

// 取得相应的页面路径,因为之前的配置,所以是 src 文件夹下的 pages 文件夹
const PAGE_PATH = path.resolve(__dirname, '../src/pages');

/* 
* 多入口配置
* 通过 glob 模块读取 pages 文件夹下的所有对应文件夹下的 js * 后缀文件,如果该文件存在
* 那么就作为入口处理
*/
exports.getEntries = () => {
 let entryFiles = glob.sync(PAGE_PATH + '/*/*.js') // 同步读取所有入口文件
 let map = {}
 
 // 遍历所有入口文件
 entryFiles.forEach(filePath => {
  // 获取文件名
  let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
  
  // 以键值对的形式存储
  map[filename] = filePath 
 })
 
 return map
}

Vue CLI3基础学习之pages构建多页应用

读取并存储完毕后,我们得到了一个入口文件的对象集合,这个对象我们便可以将其设置到 webpack 的 entry 属性上,这里我们需要修改 vue.config.js 的配置来间接修改 webpack 的值

/* vue.config.js */

const utils = require('./build/utils')

module.exports = {
 ...
 
 configureWebpack: config => {
  config.entry = utils.getEntries()
 },
 
 ...
}

这样我们多入口的设置便完成了,当然这并不是 CLI 所希望的操作,后面我们会进行改进。

三、多模板

相对于多入口来说,多模板的配置也是大同小异,这里所说的模板便是每个 page 下的 html 模板文件,而模板文件的作用主要用于 webpack 中 html-webpack-plugin 插件的配置,其会根据模板文件生产一个编译后的 html 文件并自动加入携带 hash 的脚本和样式,基本配置如下

/* webpack 配置文件 */
const HtmlWebpackPlugin = require('html-webpack-plugin') // 安装并引用插件

module.exports = {
 ...
 
 plugins: [
  new HtmlWebpackPlugin({
   title: 'My Page', // 生成 html 中的 title
   filename: 'demo.html', // 生成 html 的文件名
   template: 'xxx/xxx/demo.html', // 模板路径
   chunks: ['manifest', 'vendor', 'demo'], // 所要包含的模块
   inject: true, // 是否注入资源
  })
 ]
 
 ...
}

以上是单模板的配置,那么如果是多模板只要继续往 plugins 数组中添加 HtmlWebpackPlugin 即可,但是为了和多入口一样能够灵活的获取 pages 目录下所有模板文件并进行配置,我们可以在 utils.js 中添加多模板的读取解析方法

/* utils.js */

// 多页面输出配置
// 与上面的多页面入口配置相同,读取 page 文件夹下的对应的 html 后缀文件,然后放入数组中
exports.htmlPlugin = configs => {
 let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
 let arr = []
 
 entryHtml.forEach(filePath => {
  let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
  let conf = {
   template: filePath, // 模板路径
   filename: filename + '.html', // 生成 html 的文件名
   chunks: ['manifest', 'vendor', filename],
   inject: true,
  }
  
  // 如果有自定义配置可以进行 merge
  if (configs) {
   conf = merge(conf, configs)
  }
  
  // 针对生产环境配置
  if (process.env.NODE_ENV === 'production') {
   conf = merge(conf, {
    minify: {
     removeComments: true, // 删除 html 中的注释代码
     collapseWhitespace: true, // 删除 html 中的空白符
     // removeAttributeQuotes: true // 删除 html 元素中属性的引号
    },
    chunksSortMode: 'manual' // 按 manual 的顺序引入
   })
  }
  
  arr.push(new HtmlWebpackPlugin(conf))
 })
 
 return arr
}

Vue CLI3基础学习之pages构建多页应用

  • 以上我们仍然是使用 glob 读取所有模板文件,然后将其遍历并设置每个模板的 config ,同时针对一些自定义配置和生产环境的配置进行了 merge 处理,其中自定义配置的功能我会在下节进行介绍,这里介绍一下生产环境下 minify 配置的作用:将 html-minifier 的选项作为对象来缩小输出。
  • html-minifier 是一款用于缩小 html 文件大小的工具,其有很多配置项功能,包括上述所列举的常用的删除注释、空白、引号等。
  • 当我们编写完了多模板的方法后,我们同样可以在 vue.config.js 中进行配置,与多入口不同的是我们在 configureWebpack 中不能直接替换 plugins 的值,因为它还包含了其他插件
/* vue.config.js */

const utils = require('./build/utils')

module.exports = {
 ...
 
 configureWebpack: config => {
  config.entry = utils.getEntries() // 直接覆盖 entry 配置
  
  // 使用 return 一个对象会通过 webpack-merge 进行合并,plugins 不会置空
  return {
   plugins: [...utils.htmlPlugin()]
  }
 },
 
 ...
}

如此我们多页应用的多入口和多模板的配置就完成了,这时候我们运行命令 yarn build 后你会发现 dist 目录下生成了 3 个 html 文件,分别是 index.html 、 page1.html 和 page2.html

四、使用 pages 配置

其实,在 vue.config.js 中,我们还有一个配置没有使用,便是 pages 。 pages 对象允许我们为应用配置多个入口及模板,这就为我们的多页应用提供了开放的配置入口。官方示例代码如下

/* vue.config.js */
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'
 }
}

我们不难发现, pages 对象中的 key 就是入口的别名,而其 value 对象其实是入口 entry 和模板属性的合并,这样我们上述介绍的获取多入口和多模板的方法就可以合并成一个函数来进行多页的处理,合并后的 setPages 方法如下

// pages 多入口配置
exports.setPages = configs => {
 let entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
 let map = {}

 entryFiles.forEach(filePath => {
  let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
  let tmp = filePath.substring(0, filePath.lastIndexOf('\/'))

  let conf = {
   // page 的入口
   entry: filePath, 
   // 模板来源
   template: tmp + '.html', 
   // 在 dist/index.html 的输出
   filename: filename + '.html', 
   // 页面模板需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本
   chunks: ['manifest', 'vendor', filename], 
   inject: true,
  };

  if (configs) {
   conf = merge(conf, configs)
  }

  if (process.env.NODE_ENV === 'production') {
   conf = merge(conf, {
    minify: {
     removeComments: true, // 删除 html 中的注释代码
     collapseWhitespace: true, // 删除 html 中的空白符
     // removeAttributeQuotes: true // 删除 html 元素中属性的引号
    },
    chunksSortMode: 'manual'// 按 manual 的顺序引入
   })
  }

  map[filename] = conf
 })

 return map
}

上述代码我们 return 出的 map 对象就是 pages 所需要的配置项结构,我们只需在 vue.config.js 中引用即可

/* vue.config.js */

const utils = require('./build/utils')

module.exports = {
 ...
 
 pages: utils.setPages(),
 
 ...
}

这样我们多页应用基于 pages 配置的改进就大功告成了,当你运行打包命令来查看输出结果的时候,你会发现和之前的方式相比并没有什么变化,这就说明这两种方式都适用于多页的构建,但是这里还是推荐大家使用更便捷的 pages 配置

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
深入理解JavaScript中的传值与传引用
Dec 09 Javascript
jQuery使用CSS()方法给指定元素同时设置多个样式
Mar 26 Javascript
《JavaScript高级编程》学习笔记之object和array引用类型
Nov 01 Javascript
js提交form表单,并传递参数的实现方法
May 25 Javascript
Javascript中arguments对象的详解与使用方法
Oct 04 Javascript
利用JQuery阻止事件冒泡
Dec 01 Javascript
JS字符串去除连续或全部重复字符的实例
Mar 08 Javascript
Node.JS段点续传:Nginx配置文件分段下载功能的实现方法
Mar 12 Javascript
jQuery pjax 应用简单示例
Sep 20 jQuery
微信小程序实现登录注册tab切换效果
Dec 29 Javascript
微信小程序自定义tabBar组件开发详解
Sep 24 Javascript
如何检测JavaScript中的死循环示例详解
Aug 30 Javascript
Vue基础学习之项目整合及优化
Jun 02 #Javascript
JavaScript判断对象和数组的两种方法
May 31 #Javascript
vue中node_modules中第三方模块的修改使用详解
May 31 #Javascript
Vuex新手的理解与使用详解
May 31 #Javascript
一文快速了解JQuery中的AJAX
May 31 #jQuery
gulp构建小程序的方法步骤
May 31 #Javascript
jQuery实现动态加载(按需加载)javascript文件的方法分析
May 31 #jQuery
You might like
动漫定律:眯眯眼都是怪物!这些角色狠话不多~
2020/03/03 日漫
把77A收信机改造成收音机
2021/03/02 无线电
967 个函式
2006/10/09 PHP
深入理解curl类,可用于模拟get,post和curl下载
2013/06/08 PHP
探讨:parse url解析URL,返回其组成部分
2013/06/14 PHP
JavaScript 组件之旅(二)编码实现和算法
2009/10/28 Javascript
jQuery学习笔记 操作jQuery对象 文档处理
2012/09/19 Javascript
使用jQuery中的when实现多个AJAX请求对应单个回调的例子分享
2014/04/23 Javascript
jQuery 获取/设置/删除DOM元素的属性以a元素为例
2014/05/23 Javascript
jQuery调用WebMethod(PageMethod) NET2.0的方法
2016/04/15 Javascript
JS实现中英文混合文字溢出友好截取功能
2018/08/06 Javascript
Vue的路由及路由钩子函数的实现
2019/07/02 Javascript
Javascript如何实现双指控制图片功能
2020/02/25 Javascript
js实现鼠标点击飘爱心效果
2020/08/19 Javascript
ant design 日期格式化的实现
2020/10/27 Javascript
python网络编程学习笔记(四):域名系统
2014/06/09 Python
跟老齐学Python之类的细节
2014/10/13 Python
python分割文件的常用方法
2014/11/01 Python
python图像处理之反色实现方法
2015/05/30 Python
python 字典(dict)按键和值排序
2016/06/28 Python
python处理按钮消息的实例详解
2017/07/11 Python
Tensorflow的可视化工具Tensorboard的初步使用详解
2018/02/11 Python
python绘制直方图和密度图的实例
2019/07/08 Python
利用python-docx模块写批量生日邀请函
2019/08/26 Python
PyCharm第一次安装及使用教程
2020/01/08 Python
PyCharm2020.1.2社区版安装,配置及使用教程详解(Windows)
2020/08/07 Python
scrapy redis配置文件setting参数详解
2020/11/18 Python
html5 application cache遇到的严重问题
2012/12/26 HTML / CSS
HTML5 History API 实现无刷新跳转
2016/01/11 HTML / CSS
购买大码女装:Lane Bryant
2016/09/07 全球购物
物业管理员岗位职责范文
2013/11/25 职场文书
小区消防演习方案
2014/02/21 职场文书
妇女工作先进事迹
2014/08/17 职场文书
北京故宫的导游词
2015/01/31 职场文书
北京英语导游词
2015/02/12 职场文书
nginx从安装到配置详细说明(安装,安全配置,防盗链,动静分离,配置 HTTPS,性能优化)
2022/02/12 Servers