vue-cli3单页构建大型项目方案


Posted in Javascript onApril 07, 2020

一、vue-cli3单页面构建方案

1、在目标文件夹内执行

vue ui ; 一个ui版界面,用于创建vue项目;

2、打开router文件夹内的index,看情况配置router的模式,是默认的hash还是history?ps:个人推介history模式,因为内嵌如app的H5页面的话,有可能某些app是不允许页面上带有'#'的,而hash会在url上利用#来做路由转发。ps:history模式在发布到服务器上需要nginx配置一下。详情请自行百度。

const router = new VueRouter({
 base: '/',
 mode: 'history', //还可设置为'hash'模式
 routes
})

3、在根目录新建vue.config.js,覆盖webpack配置,将如下内容copy到文件中,作为初始配置

// const webpack = require('webpack')

module.exports = {
  lintOnSave: false, // 禁止eslint
  devServer: {
    open: true, // 构建完成自动打开浏览器
  },

  configureWebpack: {
    plugins: [
      // 全局配置node_modules中的模块,使用时无需引入
      new webpack.ProvidePlugin({
        $: "jquery",
        jQuery: "jquery",
        "windows.jQuery": "jquery"
      })
    ]

  },

  // webpack 链接 API,用于生成和修改 webapck 配置
  chainWebpack: (config) => {
    // 取消 chunks,每个页面只对应一个单独的 JS / CSS
    config.optimization.splitChunks({
      cacheGroups: {}
    });

    // config
    //   .plugin('webpack-bundle-analyzer')
    //   .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
  },

  pluginOptions: {

  }
}

4、配置完这些后,npm run serve启动项目,会加载如下两个js

npm run serve

vue-cli3单页构建大型项目方案

app.js:是所有单页面首次渲染都必须加载的js,内部合并了框架及js(如vue、vue-x、vue-router及非异步组件但引用了的node_modules中的模块),及所有页面公用的模块。about.js:是每个页面独立的js,这个跟router中引用模块的方式有关。

具体详解如下:

1、

import Home from '../views/Home.vue'

这种引用方式引用页面模版组件,就不会出现about.js文件,因为属于同步模块,当前件建的js会被打包进app.js。但是此种随着页面的增多,公用的app.js会越来越大。看情况在app.js大小接受的前提下权衡使用;2、

const routes = [
 {
  path: '/',
  name: 'Home',
  // component: Home
  component: () => import(/* webpackChunkName: "home" */ '../views/Home.vue') // webpack的魔法注释,将拆分出的js命名为home
 },
 {
  path: '/about',
  name: 'About',
  // route level code-splitting
  // this generates a separate chunk (about.[hash].js) for this route
  // which is lazy-loaded when the route is visited.
  component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
 }
]

这种引用方式就是异步引用模版组件,不会将当前组建的js打包进app.js,就不会出现1种的问题。因为只要没有加载到对应页面,就不会加载对应页面的js。对应页面的js会最为独立的js单独的动态引入,如同上图的about.js,在进入about页面时才会引入。

3、如果在main.js中引入的node_modules包,则会直接打包进app.js,这个逃不掉。

ps:最终结论,建议每个页面都异步引用页面模版。

5、每个页面如果引了node_mudules就会存在相对应的vendors-home.js,如果没引入node_mudules的话,每个页面按需组件就不会存在vendors-home.js这个文件,如下图:

vue-cli3单页构建大型项目方案

vue-cli3单页构建大型项目方案

6、区分本地、测试、线上环境

ps:官网提供一种方案,但是需要建立多个环境配置的配置文件,嫌麻烦,就不使用官方的方式,使用如下插件拆分环境:

cross-env:https://github.com/kentcdodds/cross-env

cnpm i cress-env --save-dev // 更改node环境变量插件

之后在package.json中加入如下三行配置,即可区分本地、测试、线上环境

"scripts": {
  "serve": "cross-env NODE_ENV=development vue-cli-service serve",
  "test": "cross-env NODE_ENV=test vue-cli-service build",
  "build": "cross-env NODE_ENV=production vue-cli-service build"
 },

在vue.config.js中执行如下代码即可打印出当前环境。

console.log(process.env.NODE_ENV)

在src目录下新建config目录,进入目录,新建gateway.config.js文件用于配置不同环境接口host,代码如下:gateway.config.js文件内容如下:

// 开发环境地址(npm run serve)
const devHost = {
 // 接口地址域名相关
 baseApi: 'https://abc.com',

}

// 测试环境地址(npm run test)
const testHost = {
 // 接口地址域名相关
 baseApi: 'https://abc.com',

}

// 线上环境地址(npm run build)
const proHost = {
 // 接口地址域名相关
 baseApi: 'https://abc1.com',

}

// 区分环境选择静态资源地址
const env = process.env.NODE_ENV

let exportConfig = ''
if (env === 'production') {
 exportConfig = proHost
} else if (env === 'test') {
 exportConfig = testHost
} else {
 exportConfig = devHost
}

export default exportConfig

结束:之后只需要在接口api的js文件中引入此文件即可。发布时区分环境打包。

7、浅谈项目引入第三方插件方案

ps:原则:移动端单个js大小不超过200k;pc端单个js不超过400k;

1.vue模块化引入node_modules包插件:

前提,各个页面都是异步加载,这样的好处是单个页面的js不会被打包进公共app.js中。之后在单个js中引入第三方库。但是据测试:这种模块化引入第三方插件,比cdn模式引入的js体积至少要大2呗,因为webpack内部对每个第三方库进行了二次处理,会增大js体积。权衡js大小使用。

2.cdn模式引入第三方插件:

提供这种方式,是因为有些库是不支持vue的,只支持cdn模式引入,而且比较轻量级,可以选择这种方案,异步cdn模式引入第三方插件,这些方式最下方脚手架示例中都有demo;

8、项目中常用的打包插件及第三方库

1.vue https://cn.vuejs.org
2.vue-router https://router.vuejs.org
3.vue-x https://vuex.vuejs.org
4.sass https://www.sass.hk
5.axios http://www.axios-js.com/
6.normalize.css http://necolas.github.io/normalize.css/
7.n-zepto https://npm.taobao.org/package/n-zepto
8.webpack-bundle-analyzer https://github.com/webpack-contrib/webpack-bundle-analyzer

下方是vue-cli3内置插件(直接在vue.config.js中配置):

如下插件可参考vue-cli3官网配置方法:

https://cli.vuejs.org/zh/config/#css-sourcemap

9.autoprefixer:自动添加浏览器前缀。(如:-webkit-等)
10.url-loader:改变静态资源引用路径

11.ProvidePlugin:全局配置node_modules中的模块

具体配置方法如下(比较全的vue.config.js配置):

const webpack = require('webpack')

const processEnv = process.env.VUE_APP_ENV; // 区分环境(值:production、development、test)
const isPro = processEnv === 'production'; // 判断production环境

const outputDir = 'dist'; // 输出文件目录(默认dist)
const assetsDir = ''; // 配置放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录

// 区分环境选择cdn地址
let publicPath = '' // 静态资源引用路径
let fontPublicPath = '' // 字体图标引用的cdn路径
let imgPublicPath = '' // css引用图片的cdn路径(c2c/static/img)
if (processEnv === 'production') {
  publicPath = 'https://abc.com/c2c/shop' // 正式环境静态资源css、js等cdn路径
  fontPublicPath = `https://abc.com/c2c/shop/${assetsDir ? assetsDir + '/' : '/'}fonts` // 正式环境字体图标引用的cdn路径
  imgPublicPath = `https://abc.com/c2c/shop/${assetsDir ? assetsDir + '/' : '/'}/img` // 正式环境css引用图片的cdn路径
} else if (processEnv === 'test') {
  // publicPath = './' // 正式环境静态资源css、js等cdn路径
  publicPath = 'https://bcd.com/c2c/shop/dist' // 测试环境静态资源css、js等cdn路径
  fontPublicPath = ''
  imgPublicPath = ''
} else {
  publicPath = '/'
  fontPublicPath = ''
  imgPublicPath = ''
}

const devServerHost = 'localhost';
const devServerPort = '8080'; // 端口号
const devServerOpen = true; // 热启动后自动打开浏览器

module.exports = {

  // 配置生成dist里面static的cdn资源路径(测试环境为./,正式环境走cdn路径)
  publicPath: publicPath,

  // 输出文件目录(默认dist)
  outputDir,

  // 配置放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
  assetsDir,

  devServer: {
    host: devServerHost,
    port: devServerPort,
    open: devServerOpen, // 构建完成自动打开浏览器


    // eslint检测影响代码编译,注释调不会影响代码编译
    // overlay: {
    //   warnings: true,
    //   errors: true
    // }
  },
  lintOnSave: processEnv === 'development' ? true : false, // 开发环境开启eslint,测试和线上编辑代码禁止eslint

  // webpack 配置,键值对象时会合并配置,为方法时会改写配置
  configureWebpack: config => {
    // 扩展资源,不将部分资源js等打入包内引用cdn资源
    let externals = {
      // 'swiper': 'Swiper',
    };
    config.externals = externals;

    //警告 webpack 的性能提示
    config.performance = {
      hints: isPro ? 'warning' : false, // 本地开发不显示警告
      // 入口起点的最大体积
      maxEntrypointSize: 512000, // 500kib
      // 生成文件的最大体积
      maxAssetSize: 307200, // 300kib
      // 只给出 js 文件的性能提示
      assetFilter(assetFilename) {
        return assetFilename.endsWith('.js');
      }
    };
  },

  // webpack 链接 API,用于生成和修改 webapck 配置
  chainWebpack: (config) => {
    // 取消 chunks,每个页面只对应一个单独的 JS / CSS
    config.optimization.splitChunks({
      cacheGroups: {}
    });

    // 全局配置node_modules中的模块,使用时无需引入
    config.plugin('provide').use(webpack.ProvidePlugin, [{
      $: "n-zepto",
      Zepto: "n-zepto",
      "window.Zepto": "n-zepto"
    }]);

    config.module
      .rule('images')
      .use('url-loader')
      .loader('url-loader')
      .tap(options => Object.assign(options, {
        limit: 10240, // 小于10k,压缩图片 => base64
        // limit: 3000,
        publicPath: imgPublicPath,
        name: `[name].[hash:8].[ext]`
      }))

    // 设置fonts字体文件引用的路径
    config.module
      .rule('fonts')
      .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
      .use('url-loader')
      .loader('file-loader')
      .tap(options => Object.assign(options, {
        limit: 5000,
        publicPath: fontPublicPath,
        name: '[name].[hash:8].[ext]'
      }))


    // npm run report;打印app.js的模块报告,查看各个模块;
    if (processEnv === 'report') {
      config
        .plugin('webpack-bundle-analyzer')
        .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
    }

  },

  // css配置处理
  css: {
    // 是否使用css分离插件 ExtractTextPlugin;true:页面css独立分割,false:页面css同一打包;
    extract: true,
    // 开启 CSS source maps(默认false)线上关闭,测试和本地开启
    sourceMap: isPro ? false : true,
    // css预设器配置项
    loaderOptions: {
      sass: {
        // sass的公共方法和变量,需要预编译;
        prependData: `
          @import "@/assets/css/global.scss";
          @import "@/assets/css/func.scss";
        `
      },
      postcss: {
        plugins: [
          // 浏览器自动加前缀
          require('autoprefixer')({
            overrideBrowserslist: [
              "Android 4.0",
              "iOS 7",
              "Chrome > 31",
              "ff > 31",
              "ie >= 8"
            ]
          }),
        ]
      }

    },
    // 启用 CSS modules for all css / pre-processor files.
    requireModuleExtension: false
  },

  // 构建时开启多进程处理 babel 编译
  parallel: require('os').cpus().length > 1,

  pwa: {
    iconPaths: {
      favicon32: 'favicon.ico',
      favicon16: 'favicon.ico',
      appleTouchIcon: 'favicon.ico',
      maskIcon: 'favicon.ico',
      msTileImage: 'favicon.ico'
    },

  },

  // 第三方插件配置
  pluginOptions: {
    // ...
  }
}

9、一个基础配置较为完善的基于vue-cli3的单页面项目方案脚手架:
项目脚手架集合project-init
其中的cli-start-spa文件夹,内部readme有项目细节。

到此这篇关于vue-cli3单页构建大型项目方案的文章就介绍到这了,更多相关vue-cli3单页构建 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
IE6/7/8中Option元素未设value时Select将获取空字符串
Apr 07 Javascript
读jQuery之十 事件模块概述
Jun 27 Javascript
使用PHP+JavaScript将HTML页面转换为图片的实例分享
Apr 18 Javascript
AngularJS的ng-repeat指令与scope继承关系实例详解
Jan 21 Javascript
Vue.js实例方法之生命周期详解
Jul 03 Javascript
使用vue的v-for生成table并给table加上序号的实例代码
Oct 27 Javascript
bootstrap table表格插件之服务器端分页实例代码
Sep 12 Javascript
详解微信小程序开发聊天室—实时聊天,支持图片预览
May 20 Javascript
微信小程序在其他页面监听globalData中值的变化
Jul 15 Javascript
Layer.js实现表格溢出内容省略号显示,悬停显示全部的方法
Sep 16 Javascript
浅谈Vue使用Elementui修改默认的最快方法
Dec 05 Vue.js
如何在Vue项目中添加接口监听遮罩
Jan 25 Vue.js
在Chrome DevTools中调试JavaScript的实现
Apr 07 #Javascript
《javascript设计模式》学习笔记四:Javascript面向对象程序设计链式调用实例分析
Apr 07 #Javascript
详解vue中在循环中使用@mouseenter 和 @mouseleave事件闪烁问题解决方法
Apr 07 #Javascript
《javascript设计模式》学习笔记三:Javascript面向对象程序设计单例模式原理与实现方法分析
Apr 07 #Javascript
flexible.js实现移动端rem适配方案
Apr 07 #Javascript
《javascript设计模式》学习笔记一:Javascript面向对象程序设计对象成员的定义分析
Apr 07 #Javascript
详解vue-flickity的fullScreen功能实现
Apr 07 #Javascript
You might like
如何在PHP中使用Oracle数据库(3)
2006/10/09 PHP
PHP中CURL的CURLOPT_POSTFIELDS参数使用细节
2014/03/17 PHP
网页前台通过js非法字符过滤代码(骂人的话等等)
2010/05/26 Javascript
JavaScript创建对象的写法
2013/08/29 Javascript
js实现日期级联效果
2014/01/23 Javascript
javascript中call,apply,bind的用法对比分析
2015/02/12 Javascript
javascript数据结构与算法之检索算法
2015/04/04 Javascript
JavaScript中的闭包
2016/02/24 Javascript
基于Bootstrap实现图片轮播效果
2016/05/22 Javascript
easyui form validate总是返回false的原因及解决方法
2016/11/07 Javascript
jQuery validate 验证radio实例
2017/03/01 Javascript
bootstrap table表格客户端分页实例
2017/08/07 Javascript
一个Vue页面的内存泄露分析详解
2018/06/25 Javascript
Nodejs实现多文件夹文件同步
2018/10/17 NodeJs
微信小程序学习笔记之登录API与获取用户信息操作图文详解
2019/03/29 Javascript
详解Nuxt.js中使用Element-UI填坑
2019/09/06 Javascript
使用p5.js临摹动态图形
2019/10/23 Javascript
[40:55]Liquid vs LGD 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
[01:00:30]完美世界DOTA2联赛循环赛 Inki vs Matador BO2第二场 10.31
2020/11/02 DOTA
带你了解python装饰器
2017/06/15 Python
Python分支结构(switch)操作简介
2018/01/17 Python
mac下pycharm设置python版本的图文教程
2018/06/13 Python
Python 微信爬虫完整实例【单线程与多线程】
2019/07/06 Python
python 使用plt画图,去除图片四周的白边方法
2019/07/09 Python
在PyCharm中控制台输出日志分层级分颜色显示的方法
2019/07/11 Python
python将邻接矩阵输出成图的实现
2019/11/21 Python
纯CSS3代码实现switch滑动开关按钮效果
2016/08/30 HTML / CSS
使用CSS禁止textarea调整大小功能的方法
2015/03/13 HTML / CSS
医药销售自我评价200字
2014/09/11 职场文书
民主生活会对照检查材料
2014/09/22 职场文书
乡领导班子四风问题对照检查材料
2014/09/25 职场文书
2015暑期社会实践通讯稿
2015/07/18 职场文书
2015年度学校应急管理工作总结
2015/10/22 职场文书
2019年朋友圈经典励志语录50条
2019/07/05 职场文书
MySQL 常见的数据表设计误区汇总
2021/06/07 MySQL
Python 避免字典和元组的多重嵌套问题
2022/07/15 Python