webpack + vue-cli(v2.xx) 搭建前端脚手架性能优化

1 篇文章 0 订阅
1 篇文章 0 订阅

webpack + vue-cli(v2.xx) 搭建前端脚手架性能优化

路由懒加载

路由懒加载语法如下

component: resolve => require(['@/views/xxx/xxx'], resolve)

例如

{
    path: '/index',
    name: 'index',
    component: resolve => require(['@/views/index/Index'], resolve)
}

iview 按需引入

创建 iview.index.js 文件

import Vue from 'vue'
import {
    Breadcrumb,
    BreadcrumbItem,
    Button,
    ButtonGroup,
    Checkbox,
    CheckboxGroup,
    Circle,
    Collapse,
    DatePicker,
    Dropdown,
    DropdownItem,
    DropdownMenu,
    Form,
    FormItem,
    Icon,
    Input,
    InputNumber,
    Submenu,
    Menu,
    MenuGroup,
    MenuItem,
    Message,
    Modal,
    Option,
    OptionGroup,
    Page,
    Panel,
    Poptip,
    Progress,
    Radio,
    RadioGroup,
    Select,
    Slider,
    Spin,
    Switch,
    Table,
    Tabs,
    TabPane,
    TimePicker,
    Tooltip,
    Upload
} from 'iview'
// iview基础模块
const components = {
    Breadcrumb,
    BreadcrumbItem,
    Button,
    ButtonGroup,
    Checkbox,
    CheckboxGroup,
    Collapse,
    DatePicker,
    Dropdown,
    DropdownItem,
    DropdownMenu,
    Form,
    FormItem,
    Icon,
    Input,
    InputNumber,
    Submenu,
    Menu,
    MenuGroup,
    MenuItem,
    Message,
    Modal,
    Option,
    OptionGroup,
    Page,
    Poptip,
    Progress,
    Radio,
    RadioGroup,
    Select,
    Slider,
    Spin,
    Table,
    Tabs,
    TabPane,
    TimePicker,
    Tooltip,
    Upload
}
​
const iviewModule = {
    ...components,
    // 不能和html标签重复的组件,添加别名(除了Switch、Circle在使用中必须是iSwitch、iCircle,其他都可以不加"i")
    iButton: Button,
    iCircle: Circle,
    iForm: Form,
    iInput: Input,
    iMenu: Menu,
    iOption: Option,
    iProgress: Progress,
    iSelect: Select,
    iSwitch: Switch,
    iTable: Table
}
// 循环注册全局组件
Object.keys(iviewModule).forEach(key => {
    Vue.component(key, iviewModule[key])
})
​

在 main.js 中引入 iview.index.js 文件即可

import "./js/iview.index"

echarts 按需引入

在 main.js 中对 echarts 按需引入

const echarts = require('echarts/lib/echarts')
// 引入折线图等组件
require('echarts/lib/chart/line')
require('echarts/lib/chart/bar')
require("echarts/lib/chart/graph")
require("echarts/lib/chart/pie")
​
// 引入提示框、title、图例
require("echarts/lib/component/title");
require("echarts/lib/component/tooltip");
require("echarts/lib/component/legend");
require("echarts/lib/component/dataZoom");
require("echarts/lib/component/axisPointer");
require("echarts/lib/component/graphic");
require("echarts/lib/component/grid");
​
Vue.config.productionTip = false;
Vue.prototype.$ajax = axios;
Vue.prototype.$echarts = echarts;

在 vue 组件中使用 this.$echarts 代替 echarts 即可

使用 happypack 开启多线程构建

HappyPack可以将原有的 webpack 对 loader 的执行过程,从单一进程的形式扩展为多进程的模式,从而加速代码构建

第一步,安装

npm install happypack --save-dev

第二步,在 webpack.base.conf.js 中使用

const HappyPack = require('happypack')
​
...
module:{
    rules: [
        // 主要针对 js 的编译速度进行优化,其他模块优化力度不大,且有些模块 happypack 会不支持
        {
            test: /\.js$/,
            // id 为 babelJs
            loader: 'happypack/loader?id=babelJs',
            include: [
                resolve("src"),
                resolve("test"),
                resolve("node_modules/webpack-dev-server/client")
            ]
        }
    ]
},
plugins: [
    new HappyPack({
        // id 与 babel-loader 中的 id 一致
        id: 'babelJs',
        // 将 babel-loader 编译后的文件缓存起来,当有文件发生变化时 babel-loader 重新编译
        loaders: ['babel-loader?cacheDirectory'],
        // 开启 4 个线程,默认是 3
        threads: 4
    })
]
​

使用 DllPlugin 优化

在使用 webpack 进行打包的时候,对于依赖的第三方库,如 vue、vuex、vue-router、axios 等这些不会修改的依赖,可以让它和业务代码分开打包。第一次打包时将第三方库打包并生成动态链接库,然后 webpack 就只需要打包项目业务代码,需要导入的模块在动态链接库中,直接去其中获取即可。后续再打包的时候 webpack 只需打包项目业务代码即可,只要不升级依赖库版本,第三方库就不用重新打包。

DllPlugin 插件和 DllReferencePlugin 插件在 webpack 中已内置,不需安装

第一步,新建 dll 文件,作为 package 中打包第三方库命令的入口文件

'use strict'
// 实现 node.js 命令行环境的 loading 效果以及显示各种状态的图标
const ora = require('ora') 
// 以包的形式包装 rm -rf 命令,删除文件和文件夹,无论文件夹是否为空,都可以删除
const rm = require('rimraf') 
// 处理文件与目录的路径
const path = require('path') 
// 修改控制台中字符串的样式 1.字体样式 2.字体颜色 3.背景颜色
const chalk = require('chalk') 
const webpack = require('webpack')
// 引入生产配置
const webpackConfig = require('./webpack.dll.conf') 
​
// 设置loading 文案
const spinner = ora('Dllplugin start...') 
// loading 开始
spinner.start() 
// rm '../static/vendor' 是将该路径下的目录清空,每次打包前都清空以前的文件打包的信息
​
rm(path.join(__dirname, '../static/vendor'), err => {
  if (err) throw err
  
  //开始webpack编译
  webpack(webpackConfig, (err, stats) => {
    //webpack编译成功后的回调函数
    spinner.stop()
    
    if (err) throw err
    
    process.stdout.write(stats.toString({ // process.stdout.write 向屏幕输出提示信息
      colors: true,
      modules: false,
      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
      chunks: false,
      chunkModules: false
    }) + '\n\n')
​
    if (stats.hasErrors()) {
      console.log(chalk.red('  Dllplugin failed with errors.\n'))
      process.exit(1)
    }
​
    console.log(chalk.cyan('  Dllplugin complete.\n'))
  })
})

再打包第三方库时,使用 rm 命令将以前打包的第三方库文件删除,以此保证每次打包的都是最新的第三方库数据

第二步,创建 webpack.dll.conf.js 文件,配置 DllPlugin

const path = require("path");
const webpack = require("webpack");
​
module.exports = {
    // 入口文件
    entry: {
        // g6、visjs 不能放入,g6 中有 es6 代码,visjs 代码太旧
        vendor: ['vue/dist/vue.esm.js', 'lodash', 'vuex', 'axios', 'vue-router', 'iview', 'moment', 'echarts', 'crypto-js']
    },
    output: {
        path: path.join(__dirname, '../static/vendor'), // 打包后文件输出的位置
        filename: '[name].dll.js',
        library: '[name]_library'
        // vendor.dll.js 中暴露出的全局变量名。
        // 主要是给 DllPlugin 中的 name 使用,
        // 故这里需要和 webpack.DllPlugin 中的 `name: '[name]_library',` 保持一致。
    },
    plugins: [
        new webpack.DllPlugin({
            // path 是 manifest.json 生成的文件夹及名字,该项目让它生成在了根目录下的 static/vendor 文件夹中
            path: path.join(__dirname, '../static/vendor', '[name]-manifest.json'),
            // name 和 output.library 保持一致即可
            name: '[name]_library',
            // context 选填,manifest 文件中请求的上下文,默认为该 webpack 文件上下文
            context: __dirname
        }),
        // 压缩打包后的第三方库文件
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            }
        })
    ]
};

第三步,在 index.html 文件中引入外部链接

<!DOCTYPE html>
<html>
​
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="format-detection" content="telephone=no,email=no" />
    <link rel="icon" href="static/theme/favicon.ico" type="image/x-icon" />
​
    <title>欢迎使用xxx平台</title>
</head>
​
<body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script src="./static/vendor/vendor.dll.js"></script>
</body>
​
</html>
主要添加
<script src="./static/vendor/vendor.dll.js"></script>

第一次打包

// 运行

npm run dll

// 然后运行

npm run build

后续打包

// 运行

npm run build

若第三方库文件版本更新,或 DllPlugin 的 entry 入口第三方库增加

// 运行

npm run dll

// 然后运行

npm run build

项目打包时间由 77s 变为 35s ,节省了 54.5% 的时间

项目热更新时间由 23s 变为 19s,节省了 17.4% 的时间

 

性能优化有没考虑到的地方欢迎大家留言评论 ^ _ ^ ~ 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值