Webpack 最佳实践总结(三)

还未看的,能够点击查看上两篇文章哟:Webpack 最佳实践总结(一)Webpack 最佳实践总结(二)javascript

好了,这篇是第三篇,也是完结篇,我感受这一篇是最乱的一篇,凑合着看吧,不会让你失望的php

整合 CSS 加工流

有时候,前端项目中除了 JavaScript 外,还有一个更重要的 CSS 须要咱们花点精力进去。这里主要陈述一下如何将 CSS 加工流整合到 webpack 中,由于 CSS Modules 的状况比较复杂,全部暂还未打算介绍更多关于 CSS Modules 的内容css

CSS 工做流指什么?好的工做流能够提供开发效率,节约开发成本。这里要介绍的是 CSS 工做流中的一种很广泛的代码加工流程:正常的 CSS 业务逻辑开发流程须要通过 CSS 预处理器(如 Sass 或 Less),而后再通过后处理器(如 PostCSS)进行深加工。Sass 和 less 让咱们吃上'语法糖'去快捷编写 CSS,PostCSS 可让咱们再也不关心每条语句是否兼顾不一样和不一样版本的浏览器html

在 webpack 上整合 CSS 加工流实现方式以下:前端

配置预处理器java

这里以 Sass 做为预处理器,以下:node

// webpack.config.js
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  module: {
    rules: [
      // ...
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
            { loader: 'css-loader', options: { minimize: true } },
            'postcss-loader',
            'sass-loader'
          ]
        })
      }
    ]
  }
}

配置后处理器webpack

这里以 PostCSS 做为后处理器,以下:git

// webpack.config.js
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');

module.exports = {
  plugins: [
    new webpack.LoaderOptionsPlugin({
      options: {
        postcss: [
          autoprefixer({
            browsers: [
              'last 3 version',
              'ie >= 10'
            ]
          })
        ],
        context: staticSourcePath
      }
    })
  ]
}

设置外联github

// webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');

// 存放静态资源,诸如图片或者是 normalize.css
const staticSourcePath = path.join(__dirname, 'static');

module.exports = {
  // ...
  entry: {
    // 设置入口文件,顺序是静态资源 -> custom.scss -> 项目里其余 scss
    base: path.resolve(staticSourcePath, 'src/public/custom.scss')
  },
  // ...
  plugins: [
    // 建立 <link> 标签,并将 src 指向最终生成的 CSS 文件,须要 html-webpack-plugin
    new ExtractTextPlugin({
      filename: '[name].[contenthash].css',
      allChunks: true
    })
  ]
}

压缩第三方库

以 Moment.js 和 Lodash 为例

Moment.js

Moment.js(v2.18.1) 是一个用于日期的 JavaScript 库,默认状况下,只有你安装它到你的项目中,即便压缩后,也会占据217kb大小。相对于在2017年8月1日的统计,对比与 JavaScript 的 446kb 的平均大小,这是实在是太大了。不过 webpack 能够去掉 Moment.js 其中无用的代码。

其中有 165kb 的大小是用于本地化的语言包,即使你不去用它们,它们在默认的状况下也会被包含进来。以下代码来自 moment 的 gitihub

// moment/src/lib/locale/locales.js
function loadLocale(name) {
    var oldLocale = null;
    // TODO: Find a better way to register and load all the locales in Node
    if (!locales[name] && (typeof module !== 'undefined') &&
            module && module.exports) {
        try {
            oldLocale = globalLocale._abbr;
            require('./locale/' + name);
            // because defineLocale currently also sets the global locale, we
            // want to undo that for lazy loaded locales
            getSetGlobalLocale(oldLocale);
        } catch (e) { }
    }
    return locales[name];
}

上面的代码会使 Moment.js 在运行期间动态地选择相应文件去加载。

要解决它须要用到 ContextReplacementPlugin,一款替换上下文的插件,例子以下:

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.ContextReplacementPlugin(
      // 须要被处理的文件目录位置
      /moment[\/\\]locale/,
      // 正则匹配须要被包括进来的文件
      /(en|zh-cn)\.js/
    )
  ]
};

Lodash

Lodash 是一款方便开发 JavaScript 的工具集合,测试版本为4.17.4。

当你项目包含有 Lodash 的时候,你打包出来的文件至少增长 75kb,多出来的大小包含了 316 个 Lodash 的函数。若是你只是使用了其中少数,例如 20 个,那么大概有 65 kb 是多余的。下面将列出两种去掉这些多余的代码的方法:

方法1:

还记得 webpack最佳实践(一) 说起的 Tree-shaking 吗?正由于有它,咱们能够利用这个特性很是容易作到按需引用,以下:

import _ from 'lodash';
_.get();

修改成

import get from 'lodash/get';
get();

代码量从 72kb 压缩到 8.27kb

方法2:

方法1只适合刚开始玩一个项目的时候,并不怎么适合玩开了的项目,除非重写一次,这工做量太大了,另一个缘由是 lodash 的方法名会容易跟自定义的函数名冲突,形成隐藏性bug。方法2就是解决这两个问题,那就是使用babel-plugin-lodash

babel-plugin-lodash 是一款经过 babel 去实现将 lodash 的import用法编译为最佳实践的插件,配置以下:

打开.babelrc,添加下面配置

{
  "plugins": ["lodash"]
}

更多的配置方式能够查看文档,这里再也不做太多介绍。更具体的优化效果看下面:

import _ from 'lodash';
_.get({ a: { b: 5 } }, 'a.b');

上面的代码是没有使用babel-plugin-lodash,使用以后,会被从新编译为下面:

import _get from 'lodash/get';
_get({ a: { b: 5 } }, 'a.b');

跟方法1同样,代码量从 72kb 压缩到 8.27kb

固然若是你想更进一步压缩代码,能够尝试与lodash-webpack-plugin搭配,它会更深一步地去删除一些lodash的方法里的代码。例如_.get默认支持深路径查询,若是你不须要支持深路径查询,你能够开启这个插件,这个方法就会被去掉这个支持:

只使用babel-plugin-lodash

import _ from 'lodash';
_.get({ a: { b: 5 } }, 'a.b');
// → returns 5

使用babel-plugin-lodashlodash-webpack-plugin 以后

import _get from 'lodash/get';
_get({ a: { b: 5 } }, 'a.b');
// → returns undefined

代码量从72kb 压缩到 772b

启用 scope hoisting

scope hoisting 对于 webpack 来讲,就是将之前的模块引用链拍扁为一个但又不会影响到已有的代码。更好理解scope hoisting推荐阅读:here

目前只有 webpack v3 以上版本才支持scope hoisting,开启它是须要手动配置,以下:

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
};

其余好用的插件

preload-webpack-plugin 让静态资源支持 DNS 预解析和预加载,配置以下:

// webpack.config.js
const PreloadWebpackPlugin = require('preload-webpack-plugin');
module.exports = {
  // ...
  plugins: [
    new PreloadWebpackPlugin({
      rel: 'preload',
      as: 'script',
      include: 'all',
      fileBlacklist: [/\.(css|map)$/, /base?.+/]
    })
  ]
}

script-ext-html-webpack-plugin 让 js 加载方式支持 Async 或 defer,配置以下:

// webpack.config.js
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
module.exports = {
  // ...
  plugins: [
    new ScriptExtHtmlWebpackPlugin({
      defaultAttribute: 'defer'
    })
  ]
}

总结

有点乱,很差总结,大概就是整合 CSS 代码加工流程到 webpack 中、压缩第三方库(Moment.js 和 Lodash )、启用scope hoisting和其余好用的插件

大概就这样,内容较多~

文章首发于:https://www.linpx.com/p/webpa...
欢迎访问个人博客:https://www.linpx.com

相关文章
相关标签/搜索