美文网首页我爱编程
webpack体积优化

webpack体积优化

作者: 2林子易2 | 来源:发表于2017-08-29 15:36 被阅读0次

    基础

    从webpack文件上来看,主要用到的有entry,output,resolve,module,plugins

    • entry入口
      用来写入口文件,SPA一般是一个入口。当然也有vendor写在这里。
    • output出口
      主要为webpack经过你设计的规则构建后输出的文件,指定输出位置,文件名等配置。
    • resolve解析
      定制你的解析规则,后面会说到。
    • module模块
      主要是装载器loaders书写的地方,webpack2已经改为rules。
    • plugins插件

    详细请看配置

    output

    output除了用来指定输出位置外,还有一些hash和chunk的配置。hash是随机生成的,每一次都会改变。chunk这里指的是webpack分割的代码块,webpack在编译过程中会解析内容,通过内容生成chunkhash,chunkhash相对hash来说是相对不变的,我们也是利用这一点来做浏览器缓存。这里webpack提供了hash生成的算法,chunkhash失效时间等配置,一般来说我们不会用到。

    主要用到的东西就是path,publicpath,filename,chunkFilename
    path指的是webpack构建完成后的输出地址
    publicpath指的是资源的访问地址
    filename是生成文件的名字
    chunkFilename非入口的文件名

    resolve

    resolve是webpack可定制的解析,他的配置决定了你在require或者import一个包的时候,webpack去哪里找这个文件。
    resolve.modules指定查找包的文件夹,可用绝对路径和文件名。文件名的查找规则和node_modules查找规则一致。
    resolve.descriptionFiles指定查找包的描述文件,一般为package.json
    resolve.mainFields指定描述文件中的入口字段,一般为main

    一般的解析就是通过modules查找到包,然后找包内的描述文件package.json,然后根据包内的描述文件入口字段mainFields来引入js文件
    似乎mainFields指定的字段不支持Array类型,也就是说package.json中的main字段得是个String,这样你需要引入多个文件的时候就需要做个入口文件了。

    loader和plugins的区别

    其实他们两没有什么可比性,放在这里只是想说明一下他们在webpack中扮演的角色。
    webpack是一个插件式的架构,采用Tapable事件流。
    loader其实只是在webpack编译过程中的某一个时期执行,他的作用就是对符合规则的文件进行转换,比如常用的less-loader、css-loader、style-loader,less-loader先将less语法转为css,css-loader支持我们require引用css和处理css内部的import和url,style-loader则是将css文件转为style注入到页面中。loader支持链式调用,前面提到的例子就是将less转为style的一个链式调用。除此之外,各个loader之间是互不影响。
    loader的调用方式分为三种,分别是命令行调用,内联调用和在配置文件webpack.config.js中配置。个人比较推荐第三种,这样对源码的影响将会是最小的。
    plugins不同于loader,他贯穿整个webpack编译。利用webpack提供的很多hook,在不同的时期触发相应的操作,功能也多种多样。
    感兴趣的可以了解一下webpack之loader和plugin简介webpack 源码解析

    常用的loader

    样式:style-loader、css-loader、less-loader、sass-loader等
    文件:raw-loader、file-loader 、url-loader、json-loader等
    编译:babel-loader、coffee-loader 、ts-loader等
    校验测试:mocha-loader、jshint-loader 、eslint-loader等

    常用的plugin

    • DefinePlugin
      全局常量定义
    • UglifyJsPlugin
      代码丑化
    • OccurenceOrderPlugin
    • HtmlWebpackPlugin
      自动生成html5文件
    • CommonsChunkPlugin
      公共代码整合
    • CompressionWebpackPlugin
      gzip压缩

    详细请看awesome-webpackwebpack之loader和plugin简介webpack2.2中文文档

    webpack执行流程

    • entry-option
      初始化option
    • run
      开始编译
    • make
      从entry开始递归的分析依赖,对每个依赖模块进行build
    • before-resolve - after-resolve
      对其中一个模块位置进行解析
    • build-module
      开始构建 (build) 这个module,这里将使用文件对应的loader加载
    • normal-module-loader
      对用loader加载完成的module(是一段js代码)进行编译,用 acorn 编译,生成ast抽象语法树。
    • program
      开始对ast进行遍历,当遇到require等一些调用表达式时,触发call require
      事件的handler执行,收集依赖,并。如:AMDRequireDependenciesBlockParserPlugin等
    • seal
      所有依赖build完成,下面将开始对chunk进行优化,比如合并,抽取公共模块,加hash
    • bootstrap
      生成启动代码
      emit
      把各个chunk输出到结果文件

    包体积优化

    包分析

    通过插件webpack-bundle-analyzer进行分析。

    npm i webpack-bundle-analyzer --save

    这个插件在使用后会开启一个网页,一般为localhost:8888,当然这个可以配置。通过图像展示我们打包的每个文件组成,各个部分体积,总体积等一些信息。

    详细的配置可以查看npm上面的文档,这里我也是用了npm的案例配置。

    PS:个人认为优化还是要基于对项目的熟悉上,否则可能会无从下手。

    lodash 优化

    npm install babel-plugin-lodash lodash-webpack-plugin --save

    const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
    
    const config = {
      plugins: [
        new LodashModuleReplacementPlugin({
          path: true,
          flattening: true
        })
      ]
    };
    
    .babelrc
    plugins: ['transform-runtime', 'lodash'],
    

    懒加载

    npm i bundle-loader --save

    require("bundle-loader?lazy&name=my-chunk!./file.js");
    OR
    import XXX from "bundle-loader?lazy&[name=[name]]!./file.js"
    

    CDN优化

    CDN优化依赖一个包管理器Bower

    Bower算是一个很老的前端包管理器,虽说它叫包管理器,其实他只是提供了扁平化的下载和记录功能。

    目前Bower已宣告终止开发,前端模块管理全面移向npm。

    这里npm3已经号称是JavaScript的包管理器,而不仅仅是node的包管理器了。:)

    安装Bower

    npm i -g bower

    Bower部分命令

    bower的命令和npm大同小异,以下是几个常用的命令:

    • 初始化,生成bower.json文件,功效和package.json差不多
      bower init
    • 查找包,当然也可以通过官网查找
      bower search XXX
    • 安装包,规则和npm一致,可以下载对应版本的包
      bower install XXX@XX --save

    webpack和bower的连接

    通过插件bower-webpack-plugin进行webpack和bower的连接。

    npm i bower-webpack-plugin --save

    这里其实他做的很类似resolve的alise,就是通过插件指定了require/import一个bower包的时候的地址和文件。

    以下是它的配置:

    var BowerWebpackPlugin = require("bower-webpack-plugin");
    new BowerWebpackPlugin({
      modulesDirectories: ["bower_components"],
      manifestFiles:"bower.json",
      excludes: /.*\.less/
    }),
    

    通过modulesDirectories指向bower的依赖文件夹,manifestFiles指向入口文件。这里一般配置一般都是固定的,详细的配置可以查看NPM文档。
    下面是bootstrap的bower.json文件,可以看出它是通过main字段来引入对应文件的。

    bower包的引入和正常的npm包一样引入,通过import或者require,测试发现还是require效果好一点,少一点坑。

    在升级到webpack2之后,发现这个插件已经不支持了,转采用bower-resolve-webpack-plugin
    它的配置参考github文档,发现只能加载js文件,废弃!不过可以借鉴一下它写插件

    bootstrap

    bootstrap-loader用来解决bootstrap加载
    查找网上webpack引入bootstrap一致推荐bootstrap-loader,测试后发现引入这个东西bootstrap会占用将近150kb的空间,记录一下
    vendor占用544kb
    app占用158kb

    安装
    npm install bootstrap-loader --save
    npm install bootstrap-sass --save
    npm install css-loader node-sass resolve-url-loader sass-loader style-loader url-loader --save

    加载
    require('bootstrap-loader')

    详细请看如何把bootstrap用webpack打包

    另一种办法是通过bower引入,但是bower中bootstrap给的入口文件有一个less,无法解决,只能修改less为css。这样bootstrap占用会只有不到50kb
    vendor占用390kb
    app占用190kb


    webpack2 tree-shaking

    node的import语法允许我们只引入我们需要的方法,这对于js的内存占用是一种极大的提升。同时在webpack打包的时候也利用了这种特性,只打包我们引入的方法。但是这一点和babel的转码会有冲突,具体原因看这里如下:

    tree-shaking 是指借助es6 import export 语法静态性的特点来删掉export但是没有import过的东西,babel会在编译转化es6代码时把import export转换为cmd的module.export
    原文请看Tree-shaking with webpack 2 and Babel 6

    我们为了利用webpack2的这种特性,需要做一些配置,见原文。
    经过测试,我发现这个特性能减少的包体积量几乎可以忽略不计。难怪会有此讨论->如何评价 Webpack 2 新引入的 Tree-shaking 代码优化技术?

    打包速度优化

    flag

    webpack2入坑

    1. 入口和出口其实改动不大
    2. resolve改动会大一点,不过因为我们不经常用,所以不用太关注,这里需要注意的就是以下几点:
      • resolve.extensions配置,数组不需要在第一位加空字符串了
      • resolve.root, resolve.fallback, resolve.modulesDirectories合并为resolve.modules
    3. module语法改动
      • module.loaders改为module.rules
      • 不再支持简写loader,也就是说css以后要写成css-loader
      • 链式调用style!css!less改为use[]
    4. plugins改动
      这个就需要看各个插件的支持了,有部分插件是只支持1不支持2的,还有webpack内置插件的有部分语法改动,需要用的时候查看。改动最大的就是extract-text-webpack-plugin,不升级无法使用。

    webpack2主要的变更就是对ES6的支持更好了,当然我升级到2以后除了踩了很多语法坑和插件坑之外,并没有体验到所谓的性能提升,很尴尬。利用了tree shaking特性后包的体积也并没有减小多少。只能说webpack2比1更大的规范化,并且目前webpack已经升级到了3.5,语法已经稳定,市面上的各类资料和插件也都是webpack2更完善、支持更好。

    传送门
    webpack之loader和plugin简介
    webpack 源码解析
    webpack中文官网
    webpack入门(一)——webpack 介绍
    [译] Webpack 2 有哪些新东西

    相关文章

      网友评论

        本文标题:webpack体积优化

        本文链接:https://www.haomeiwen.com/subject/vwgldxtx.html