webpack4搭建vue项目:踩坑及优化(项目总结)

第一次写掘金,以前都是看别人的文章,此次主要是想记录下近期项目中遇到的问题,和本身的一些成长。php

先简述下最近项目的技术选型,公司在两个月前前端技术方面进行升级,以后的项目均要采用主流框架来开发。在作了三个 vue 的中型项目后,有一些坑和爬坑的过程,也是对这三个项目的进行一些系统的总结吧,如文章有哪些不足之处,评论区多多交流,互相学习。更但愿各位同窗看事后能有一些感触和收获。css

一. 项目概述:使用vue全家桶开发,但没有使用vue-cli,至于缘由,下面会详细解释。
二. 项目坑点:作了三个中型项目后,业务逻辑层并无踩什么坑,坑点主要在如下几个方面
复制代码
  • webpack4 + vue搭建配置踩坑
  • webpack打包性能检测和优化
  • 涉及权限系统,前端要作一套权限验证,生成动态路由表

1. 为何不用vue-cli脚手架?

公司主项目仍是最传统的jQ + php的架构,坐标在帝都的互联网公司,技术上其实已经与大多互联网公司差了一大截。因此在进行新项目选型时,身为公司惟一一个前端,立即决定使用 vue 来作,真正作到先后端分离。但肯定了主框架,那到底使用vue-cli呢,仍是vue+webpack本身搭呢?(产品给的项目排期是5天研发并测试,5天后上线),还得考虑到工期问题。html

通过斟酌,仍是选择了本身搭建,缘由有如下几点:前端

  1. 本身定制的脚手架哪出了问题本身内心清楚,从而也能培养一些前端架构的能力
  2. 更熟练的掌握webpack配置的能力,以及webpack3.0升级为4.0踩坑的能力
  3. 若是后期项目转型为服务端渲染(SSR),能更快的更改配置,这个是 vue-cli不具有的能力

除了以上几点,我的以为,是否具备webpack配置的能力,是衡量一个前端的水平高低的标准,笔者面试不少前端,三年经验的前端能从0配置webpage的几乎不多,更不要说性能优化或是本身写loader和plugin了。vue

2. 配置webpack篇

entryoutputloaderplugins,由于本文不是具体讲如何配置webpack,因此就不一一赘述了,网上的此类教程也是比比皆是。这里主要记录下我在配置过程当中踩过的坑和值得总结的地方。node

先简单聊聊webpack3.0版本和4.0版本的主要的区别吧jquery

1. webpack4必须安装webpack-cli
2. webpack4中设置加了一个mode配置,只有两个值development | production,对不一样的环境会提供不一样的一些默认配置
3. 拆分单独模块使用optimization.splitChunks替代了CommonsChunkPlugin
4. 提取单个css文件使用MiniCssExtractPlugin替代extract-text-webpack-plugin
5. 若是是开发vue项目,基础配置文件必须引入vue-loader/lib/plugin
6. 不在使用UglifyJsPlugin压缩js文件,而是经过optimization.minimize设置为true来压缩代码,mode为production时,其默认为ture
7. 引入了Tree Shaking,不打包无用代码
复制代码

以上就是4.0版本主要的升级,固然还有不少,在此附上官方change logwebpack

注意:
MiniCssExtractPlugin仅仅会把js中的css提取到单独的css文件中,但并不会对其进行压缩
压缩css须要单独使用optimize-css-assets-webpack-plugin,并在optimization选项中进行配置
复制代码
optimization: {
    minimizer: [
      <!--压缩css--> new OptimizeCSSAssetsPlugin({ assetNameRegExp: /\.css$/ }) ] } 复制代码

项目配置的大体思路就是根据不一样的环境配置不一样的config.js,经过webpack-merge合并基础配置,package.json中,根据不一样的命令进行相应操做便可。看图说话: git

"dev": "webpack-dev-server --config build/webpack.dev.config.js",
"build": "webpack --config build/webpack.prod.config.js",
"build:dll": "webpack -p --progress --config build/webpack.dll.config.js"
复制代码

3. webpack优化篇

一. webpack4中production模式自带优化项

1. Tree Shakinggithub

tree shaking 是一个术语一般用于打包时移出Javascript中为引用的代码,它依赖于ES6模块系统中的 importexport的静态结构特性。

开发时引入一个模块后,若是只使用其中一个功能,上线打包时只会把用到的功能打包进对应的bundle,其余没用的功能都不会打包进来,从而实现最基础的优化。

前提是使用了importexport的语法进行导入导出。什么意思呢?意思就是 若是一个模块使用了ES6的导入导出,那在打包线上代码时,就会shaking掉无用代码;可是!注意咯,若是使用的是require这种commonJS规范的导入导出,那么它不会进行shaking

为何require的模块不会被加入shaking行列呢?缘由在于require是动态导入,在webpack打包时,若是是动态导入的模块,它并不知道被导入的模块内是否有无用代码,因此不会被shaking掉。

2. scope hoisting做用于提高

scope hoisting 的做用是将模块之间的关系进行结果推测(预编译),可让webpack打包出来的代码文件更小,运行更快。

scope hoisting的实现原理其实很简单:分析出模块之间的依赖关系,尽量的把打散的模块合并到一个函数中去,但前提是不能形成代码冗余,所以,只有那些被引用了一次的模块才能被合并。

因为scope hoisting须要分析出模块之间的依赖关系,所以源码必须采用ES6模块话语句,这点和tree shaking同样。

3. 代码压缩

production模式下,默认会对js代码进行压缩和提取(SplitChunksPlugin)

二. 自定义优化

1. 尽量的少用loader

webpack打包耗时的大部分时间是由于loader预编译这一阶段,因此尽量的少用loader,以下图

可见,loader耗时占用了总体打包时间的2/3。那么问题来了,什么叫“尽量少用”?

  • 好比,项目中使用到less-loader,那就不要再配置sass-loader, stylus-loader,尽量只使用一种css预处理器
  • 再好比,处理图片的loader,通常会用到file-loader,url-loader,img-loader. 可是url-loader官方声明:url-loader works like file-loader,意思是url-loader相似于file-loader,那就不要再使用file-loader来配置(除非图片过大,超出url-loader中配置的limit值)

2. 动态导入(懒加载)

webpack默认是容许 import 语法动态导入的,可是须要babel的插件支持,即 在.babelrc配置文件中添加@babel/plugin-syntax-dynamic-import插件

动态导入的最大好处就是实现了懒加载,用到哪一个模块才会加载哪一个模块,能够提升SPA应用程序的首屏加载速度

3. noParse

在引入一些第三方模块时,例如jQuery,element-ui等,咱们知道其内部不会再依赖其余模块,由于咱们最终用到的只是一个单独的js文件,因此此时webpack若是再去解析jQuery内部的依赖关系,是很是耗时的。

能够在webpack配置文件中的module节点下加上noParse,并配置正则来告诉webpack,我不须要再去解析这些模块

module: {
    noParse: /jquery|element-ui/
}
复制代码

坑点来啦: element-ui若是 按需引入,注意,这里不能使用 noParse 来作element-ui的优化,由于按需引入的element,内部会有一系列依赖关系,使用noParse,webpack并不会去解析其依赖

下面看看优化结果,打包速度提高了接近4倍

4. IgnorePlugin

项目中使用了element-ui和moment.js,这两个插件内部都有不少语言包,尤为是moment.js。而语言包打包时会比较占用空间,而咱们的项目只须要中文语言包,这时就应该忽略掉全部的语言包,改成按需引入,从而使得构建效率更高,打包生成的文件更小

  • 首先找到第三方库中依赖的语言包是什么(在第三方库中package.json文件中,找到主入口文件,在入口文件中找到引用的语言包)
  • 使用webpack.IgnorePlugin插件忽略其依赖
  • 按需引入所依赖的语言包

下面看看打包耗时和dll包的大小,结果仍是不错的

5. 经过减小文件搜索范围来提升性能

什么叫减小文件搜索范围?这块须要先理解什么是webpack基本原理。webpack经过配置文件,将项目中引入的第三方和公共模块进行提取,每个提取出的模块都有一个id,在引用到该模块的主文件中,经过id进行映射查找。因此若是能提高文件查找速度,对webpack打包性能会有必定提高。

  • 方式一:resolve.modules 经过配置,告诉webpack在解析模块时应该搜索哪些目录。
import vue from 'vue'
import myCommonJs from '../src/myCommonJs'
复制代码

上面代码,分别引用了第三方库和公共js,默认的webpack配置,会在当前路径下向上递归的搜索文件进行打包引用。此时就可使用resolve.modules来告诉webpack,我是要到node_modules目录下和src目录下去找这两个文件。

  • 方式二: include & exclude

在配置loader时,经过配置include 和exclude更精确指定要处理的目录,这能够减小没必要要的遍历,从而减小性能损失。这个是更为简单的方式,这里就不进行赘述了

6. Happypack多进程进行打包构建

webpack打包构建默认是单进程进行打包,当一个babel-loader须要处理多个不一样类型的资源文件时,node的单进程读取文件特性就有耗性能了,这时候就须要用到 Happypack了。但多是项目规模和文件资源较为单一的缘由,笔者经过配置Happypack,实际打包速度并无获得提高,反而速度多了2-3s,以后0须要再仔细研究下。

7. 设置babel-loader 配置项cacheDirectory为true

设置后,给定目录将用于缓存加载器的结果。以后webpack构建将尝试从缓存中读取,以免在每次运行时运行可能昂贵的Babel从新编译过程

8. DllPlugin 和 DllReferencePlugin

DllPlugin为webpack提供的打包动态连接库,通常用来打包一些版本不须要常常更新的第三方库。单独提供一份打包动态连接库的配置文件(即上图中的webpack.dll.config.js),生成环境打包以前先打包动态连接库,打包后会生成vendor_dll.js和vendor-manifest.json,它包含从引入请求到模块ID的映射

DllReferencePlugin,该插件为生产环境配置文件(webpack.prod.config.js)中使用,其中的manifest选项,require DllPlugin打包生成的manifest.json文件,将依赖项名称映射到模块ID,而后使用内部__webpack_require__函数根据须要使用它们

主要思想在于,将一些不作修改的依赖文件提早打包,这样咱们在开发代码发布的时候,就不须要再对这部分代码进行打包,从而节省了打包时间

实际项目中配置此项,可提高6-8s的打包速度

坑点:
1. 生成的vendor_dll.js必须手动的引入index.html中,或者经过add-asset-html-webpack-plugin将vendor_dll.js动态的添加到html文件中
2. 再使用add-asset-html-webpack-plugin时动态引入动态连接库生成映射后的js时,由于打包生成环境时,使用了
   speed-measure-webpack-plugin进行耗时分析,从而致使打包出错,报错以下。
   猜想应该是两个插件不兼容吧,有大佬也遇到过此类问题和解决的方法,求分享
复制代码

9. 引用cdn连接引入第三方库

总结完毕,网上此类的总结有不少,但经过自身配置和经过webpack-bundle-analyzer和speed-measure-webpack-plugin来观测打包性能,并进行优化总结,又一次加深了对webpack配置及原理的理解.

相关文章
相关标签/搜索