资讯专栏INFORMATION COLUMN

Webpack 最佳实践总结(三)

jerryloveemily / 2935人阅读

摘要:这里要介绍的是工作流中的一种很普遍的代码加工流程正常的业务逻辑开发流程需要经过预处理器如或,然后再经过后处理器如进行深加工。

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

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

整合 CSS 加工流

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

CSS 工作流指什么?好的工作流可以提供开发效率,节约开发成本。这里要介绍的是 CSS 工作流中的一种很普遍的代码加工流程:正常的 CSS 业务逻辑开发流程需要经过 CSS 预处理器(如 Sass 或 Less),然后再经过后处理器(如 PostCSS)进行深加工。Sass 和 less 让我们吃上"语法糖"去快捷编写 CSS,PostCSS 可以让我们不再关心每条语句是否兼顾不同和不同版本的浏览器

在 webpack 上整合 CSS 加工流实现方式如下:

配置预处理器

这里以 Sass 作为预处理器,如下:

// 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"
          ]
        })
      }
    ]
  }
}

配置后处理器

这里以 PostCSS 作为后处理器,如下:

// 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
      }
    })
  ]
}

设置外联

// 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: [
    // 创建  标签,并将 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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/112459.html

相关文章

  • Webpack 最佳实践总结()

    摘要:这里要介绍的是工作流中的一种很普遍的代码加工流程正常的业务逻辑开发流程需要经过预处理器如或,然后再经过后处理器如进行深加工。 还未看的,可以点击查看上两篇文章哟:Webpack 最佳实践总结(一)、Webpack 最佳实践总结(二) 好了,这篇是第三篇,也是完结篇,我感觉这一篇是最乱的一篇,凑合着看吧,不会让你失望的 整合 CSS 加工流 有时候,前端项目中除了 JavaScript ...

    pkhope 评论0 收藏0
  • Webpack 最佳实践总结(一)

    摘要:它会代替所有的实例的值为,从而使知道那些判断表达式总是错误的,从而删除相关代码,进一步压缩打包文件模块机制项目中使用的,通过也能通过打包有用的代码,进一步减少大小。 好久没写文章,这次预计会带来3篇的 Webpack 系列文章,将会在这几天内更新完。 Webpack3 自今年6月20日正式发布而来,给我们带来Scope Hoisting和Magic Comments两大功能,可惜不在这...

    jubincn 评论0 收藏0
  • 前端资源系列(4)-前端学习资源分享&前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0
  • 前方来报,八月最新资讯--关于vue2&3的最佳文章推荐

    摘要:哪吒别人的看法都是狗屁,你是谁只有你自己说了才算,这是爹教我的道理。哪吒去他个鸟命我命由我,不由天是魔是仙,我自己决定哪吒白白搭上一条人命,你傻不傻敖丙不傻谁和你做朋友太乙真人人是否能够改变命运,我不晓得。我只晓得,不认命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出处 查看github最新的Vue...

    izhuhaodev 评论0 收藏0
  • Webpack 最佳实践总结(二)

    摘要:默认做法是告诉浏览器这个文件的缓存时间,然后当文件内容被修改,则需要重命名该文件告诉浏览器需要重新下载和缓存,例如也能做类似的工作。 上一篇介绍了 Webpack 优化项目的四种技巧,分别是通过 UglifyJS 插件实现对 JavaScript 文件的压缩,css-loader 提供的压缩功能,配置NODE_ENV可以进一步去掉无用代码,tree-shaking帮助找到更多无用代码 ...

    Stardustsky 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<