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 相关文章推荐
JS 判断undefined的实现代码
Nov 26 Javascript
读jQuery之五(取DOM元素)
Jun 20 Javascript
javascript for-in有序遍历json数据并探讨各个浏览器差异
Nov 30 Javascript
使用JavaScript实现ajax的实例代码
May 11 Javascript
jQuery处理XML文件的几种方法
Jun 14 Javascript
JS实现用特殊符号替换字符串的中间部分区域的实例代码
Jul 24 Javascript
浅析webpack-bundle-analyzer在vue-cli3中的使用
Oct 23 Javascript
微信小程序点击顶部导航栏切换样式代码实例
Nov 12 Javascript
谈一谈vue请求数据放在created好还是mounted里好
Jul 27 Javascript
解决vue net :ERR_CONNECTION_REFUSED报错问题
Aug 13 Javascript
使用webpack5从0到1搭建一个react项目的实现步骤
Dec 16 Javascript
微信小程序实现点赞业务
Feb 10 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
Flash空降上海 化身大魔王接受挑战
2020/03/02 星际争霸
php学习 函数 课件
2008/06/15 PHP
PHP中func_get_args(),func_get_arg(),func_num_args()的区别
2013/09/30 PHP
ExtJS 2.0 实用简明教程之布局概述
2009/04/29 Javascript
Javascript学习笔记8 用JSON做原型
2010/01/11 Javascript
JS中操作JSON总结
2020/12/06 Javascript
JavaScript学习笔记之JS函数
2015/01/22 Javascript
js实现鼠标划过给div加透明度的方法
2015/05/25 Javascript
基于jQuery Circlr插件实现产品图片360度旋转
2015/09/20 Javascript
JS实现淘宝支付宝网站的控制台菜单效果
2015/09/28 Javascript
jQuery与Ajax以及序列化
2016/02/01 Javascript
基于js里调用函数时,函数名带括号和不带括号的区别
2016/07/28 Javascript
深入理解javascript中的 “this”
2017/01/17 Javascript
JS实现搜索关键词的智能提示功能
2017/07/07 Javascript
@angular前端项目代码优化之构建Api Tree的方法
2018/12/24 Javascript
jsonp实现百度下拉框功能的方法分析
2019/05/10 Javascript
vue excel上传预览和table内容下载到excel文件中
2019/12/10 Javascript
详解vue中v-model和v-bind绑定数据的异同
2020/08/10 Javascript
React倒计时功能实现代码——解耦通用
2020/09/18 Javascript
Ant Design Vue table中列超长显示...并加提示语的实例
2020/10/31 Javascript
关于Vue中$refs的探索浅析
2020/11/05 Javascript
vue下拉刷新组件的开发及slot的使用详解
2020/12/23 Vue.js
vue实现可移动的悬浮按钮
2021/03/04 Vue.js
python pandas读取csv后,获取列标签的方法
2018/11/12 Python
Python后台开发Django会话控制的实现
2019/04/15 Python
python设置环境变量的原因和方法
2019/06/24 Python
Django后端接收嵌套Json数据及解析详解
2019/07/17 Python
Tensorflow训练MNIST手写数字识别模型
2020/02/13 Python
python分别打包出32位和64位应用程序
2020/02/18 Python
python实现excel公式格式化的示例代码
2020/12/23 Python
浅谈移动端网页图片预加载方案
2018/11/05 HTML / CSS
Myprotein蛋白粉美国官网:欧洲畅销运动营养品牌
2016/11/15 全球购物
新生入学欢迎词
2015/01/26 职场文书
2015年销售员工作总结范文
2015/04/07 职场文书
防暑降温通知书
2015/04/27 职场文书
分享一个vue实现的记事本功能案例
2022/04/11 Vue.js