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 相关文章推荐
Javascript YUI 读码日记之 YAHOO.util.Dom - Part.3
Mar 22 Javascript
javascript 折半查找字符在数组中的位置(有序列表)
Dec 09 Javascript
js弹出层之1:JQuery.Boxy (二)
Oct 06 Javascript
jQuery元素选择器用法实例
Dec 23 Javascript
Bootstrap 组件之按钮(二)
May 11 Javascript
vue.js+boostrap项目实践(案例详解)
Sep 21 Javascript
使用vue.js实现联动效果的示例代码
Jan 10 Javascript
ES6新特性之模块Module用法详解
Apr 01 Javascript
vue中使用mxgraph的方法实例代码详解
May 17 Javascript
解决layui弹出层layer的area过大被遮挡的问题
Sep 21 Javascript
Node.js API详解之 vm模块用法实例分析
May 27 Javascript
JavaScript语句错误throw、try及catch实例解析
Aug 18 Javascript
在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
javascript模仿msgbox提示效果代码
2008/06/10 Javascript
基于jquery的监控数据是否发生改变
2011/04/11 Javascript
使用coffeescript编写node.js项目的方法汇总
2015/08/05 Javascript
深入学习JavaScript的AngularJS框架中指令的使用方法
2016/03/05 Javascript
AngularJS页面访问时出现页面闪烁问题的解决
2016/03/06 Javascript
jQuery自定义数值抽奖活动代码
2016/06/11 Javascript
用vue和node写的简易购物车实现
2017/04/25 Javascript
vue实现验证码按钮倒计时功能
2018/04/10 Javascript
vue watch普通监听和深度监听实例详解(数组和对象)
2018/08/16 Javascript
element vue validate验证名称重复 输入框与后台重复验证 特殊字符 字符长度 及注意事项小结【实例代码】
2018/11/20 Javascript
uniapp实现可以左右滑动导航栏
2020/10/21 Javascript
[08:08]2014DOTA2国际邀请赛中国区预选赛精彩TOPPLAY
2014/06/25 DOTA
[48:46]完美世界DOTA2联赛PWL S2 SZ vs FTD.C 第二场 11.19
2020/11/19 DOTA
Python入门篇之字符串
2014/10/17 Python
在Python的Django框架中更新数据库数据的方法
2015/07/17 Python
Python验证企业工商注册码
2015/10/25 Python
Python自动发邮件脚本
2017/03/31 Python
Python实现学校管理系统
2018/01/11 Python
Python 使用with上下文实现计时功能
2018/03/09 Python
python+opencv实现霍夫变换检测直线
2020/10/23 Python
分享8个非常流行的 Python 可视化工具包
2019/06/05 Python
python3 批量获取对应端口服务的实例
2019/07/25 Python
简单了解python变量的作用域
2019/07/30 Python
浅谈Python的方法解析顺序(MRO)
2020/03/05 Python
python使用信号量动态更新配置文件的操作
2020/04/01 Python
Jupyter Notebook远程登录及密码设置操作
2020/04/10 Python
python 递归相关知识总结
2021/03/03 Python
HTML5自定义视频播放器源码
2020/01/06 HTML / CSS
爱尔兰领先的在线体育用品零售商:theGAAstore
2018/04/16 全球购物
存储过程和函数的区别
2013/05/28 面试题
工作表扬信的范文
2014/01/10 职场文书
八年级生物教学反思
2014/01/22 职场文书
竞选生活委员演讲稿
2014/04/28 职场文书
Python离线安装openpyxl模块的步骤
2021/03/30 Python
MySQL 数据类型详情
2021/11/11 MySQL
Python的三个重要函数详解
2022/01/18 Python