基于 Webpack 引入公共库的几种方式

时间:2021-11-20 14:45:29

以 jquery 和其插件 jquery-modal 为例,记录下引入公共库的几种方式。

为了方便,首先安装 jquery 和 jquery-modal:

cnpm i jquery jquery-modal --save

0. 直接引入

在具体的 js 文件中:

import $ from 'jquery'
import 'jquery-modal/jquery.modal.min.css'
import 'jquery-modal/jquery.modal.min.js'

$('body').append('<form id="myModal" class="modal"></from>')
$('#myModal').html('this is a modal')
$('#myModal').modal()

优点:方便。

缺点:

  1. 每个需要 jquery 的文件都要写单独引入的代码
  2. 打包的时候 jquery 会被打入每个写引入代码的文件中(代码重复处理)

打包结果:

Version: webpack 3.8.1
Time: 561ms
    Asset    Size  Chunks                    Chunk Names
bundle.js  296 kB       0  [emitted]  [big]  bundle
   [1] ./js/index.js 229 bytes {0} [built]
    + 7 hidden modules

1. ProvidePlugin

每个需要 jquery 的文件入口都需要写一句 import $ from 'jquery' 显然很蛋疼,能不能在需要的时候自动引入?ProvidePlugin 插件就为你做这件事的。

在 webpack.config.js 文件中 plugins 选项中新增配置:

plugins: [
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    'window.jQuery': 'jquery',
    'window.$': 'jquery'
  })
]

ProvidePlugin 的机制是:当 webpack 加载到某个 js 模块里,出现了未定义且名称符合(字符串完全匹配)配置中 key 的变量时,会自动 require 配置中 value 所指定的 js 模块。

这个时候,如果文件中有用到 $ 或者 jQuerywindow.jQuery 以及 window.$ 的情况,就会自动引入 jquery。

具体的 js 文件可以省略包引入步骤了:

import 'jquery-modal/jquery.modal.min.css'
import 'jquery-modal/jquery.modal.min.js'

$('body').append('<form id="myModal" class="modal"></from>')
$('#myModal').html('this is a modal')
$('#myModal').modal()

优点:和直接引入相比,少写了一行代码。

缺点:直接引入中 2 的问题没有解决。

打包结果和 0.直接引入一样。

2. externals

将 jquery 这种库打入每个引入它的文件显然不好,webpack 有个 externals 的配置,可以让指定的包不打包,转而使用 cdn。

在 webpack.config.js 中新增:

externals: {
  'jquery': '$'
}

它的意思就是,当你需要用到 jquery 包的时候,就去全局环境中找找有没有 $ 这玩意。所以我们同时需要引入 jquery 的 cdn

html 文件可能是这样的:

<html>
  <body>
    <script src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>

优点:将库代码分离,需要用的时候通过 cdn 引入,解决了上面所说的第二个问题。

缺点:缺点也很明显,我觉得既然用了 webpack,就干脆不使用外联 script 脚本的方式,而且如果使用的库比较多,就需要引入多个 script 节点。而且,有的地方不能用 cdn,比如开发 chrome 插件,是不允许引入 cdn 的代码的,而且,很多文件并没有 cdn 文件。

打包结果:

Version: webpack 3.8.1
Time: 375ms
    Asset     Size  Chunks             Chunk Names
bundle.js  27.8 kB       0  [emitted]  bundle
   [0] ./js/index.js 232 bytes {0} [built]
    + 7 hidden modules

3. expose-loader

我们理想的结果是,可以把库代码(例如 jquery,react,lodash)打包进入一个文件。我们尝试对 Webpack 进行多入口配置。

将 webpack.config.js 文件修改:

entry: {
  'bundle': './js/index.js',
  'jquery': ['jquery']  // 将多个库文件打包成一个
},
output: {
  filename: '[name].js'
}

理想的情况是用打包生成的 jquery.js 取代 cdn,但是现实很残酷,js 文件中报错了($ is not defined)。原因很简单,配置了 externals 的话,会去全局寻找 $。如果也配上 externals,会发现 jquery.js 文件打包不上了。病急乱投医,配置 ProvidePlugin,但是依旧是之前的逻辑,新打出的 jquery.js 文件根本就没有用武之地了。

这个时候实际上需要的是 expose-loader 这个 loader(特别要注意的是,这个 loader 要尽量放到最前面!):

cnpm i expose-loader --save-dev

在 webpack 中添加如下:

module: {
  rules: [
    {
      test: require.resolve('jquery'),
      use: [{
        loader: 'expose-loader',
        options: 'jQuery'
      },{
        loader: 'expose-loader',
        options: '$'
      }]
    }
  ]
}

这个 loader 会将指定 js 模块 export 的变量声明为全局变量。

这表明 jquery 这个包会向全局暴露 jQuery$ 两个变量。

打个包:

Version: webpack 3.8.1
Time: 628ms
    Asset    Size  Chunks                    Chunk Names
bundle.js  297 kB       0  [emitted]  [big]  bundle
jquery.js  272 kB       1  [emitted]  [big]  jquery
   [0] (webpack)/buildin/global.js 488 bytes {0} {1} [built]
   [4] ./js/index.js 302 bytes {0} [built]
  [11] multi jquery 28 bytes {1} [built]
    + 9 hidden modules

jquery.js 被单独拎出来打包了,但是 bundle.js 这么大,似乎还把 jquery 打进入了。原因很简单,引入的 jquery-modal 文件依赖于 jquery。

可以做个测试,将 index.js 修改如下:

$.each([1, 2, 3], (index, item) => {
  console.log(item)
})

打包:

Version: webpack 3.8.1
Time: 429ms
    Asset     Size  Chunks                    Chunk Names
jquery.js   272 kB       0  [emitted]  [big]  jquery
bundle.js  2.79 kB       1  [emitted]         bundle
   [0] (webpack)/buildin/global.js 488 bytes {0} [built]
   [1] ./js/index.js 308 bytes {1} [built]
   [2] multi jquery 28 bytes {0} [built]
    + 3 hidden modules

缺点:无法解决 jquery 插件引入的 jquery 打包的问题(这个方案其实是要手动去掉类似 import $ from 'jquery' 的代码)。而且,jquery/react 这类的库,一般是不动的(所以 cdn 引入其实是一个好方案),不需要频繁打包。

另外,ProvidePlugin 和 expose-loader 做的事情看起来非常相似,如果你所有的 jQuery 插件都是用 webpack 来加载的话,的确用 ProvidePlugin 就足够了;但理想是丰满的,现实却是骨感的,总有那么些需求是只能用 <script> 来加载的。

4. DllPlugin

最后是终极操作。

新建 webpack.dll.config.js 文件:

const webpack = require('webpack')

module.exports = {
  entry: {
    "jquery": ['jquery'],
  },
  output: {
    filename: '[name].js',
    library: '[name]',
  },
  plugins: [
    new webpack.DllPlugin({
      path: 'manifest.json',
      name: '[name]',
      context: __dirname,
    })
  ]
}

然后运行如下命令:

webpack --config webpack.dll.config.js

这个时候会生成 jquery.js 和 manifest.json 两个文件。

webpack.config.js 文件 plugins 选项下新增(需要保留 ProvidePlugin):

plugins: [
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    'window.jQuery': 'jquery',
    'window.$': 'jquery'
  }),
  new webpack.DllReferencePlugin({
    context: __dirname,
    manifest: require('./manifest.json'),
  }),
]

运行 webpack 进行打包:

Version: webpack 3.8.1
Time: 402ms
    Asset     Size  Chunks             Chunk Names
bundle.js  28.2 kB       0  [emitted]  bundle
   [0] delegated ./node_modules/._jquery@3.2.1@jquery/dist/jquery.js from dll-reference jquery 42 bytes {0} [built]
   [1] ./js/index.js 302 bytes {0} [built]
    + 7 hidden modules

成功!不要忘了在 index.html 文件中引入第一步打包出来的 jquery.js 文件!

这个时候,无论代码中有没有类似 import $ from 'jquery',都不再会去打包 jquery。如果需要更新库文件(jquery 更新等),依赖(指 jquery 等)更新后,重新运行 webpack --config webpack.dll.config.js 即可

5. CommonsChunkPlugin

其实还可以用 CommonsChunkPlugin 这个插件,但是总觉得没有 DLL 优雅。

使用方式相当简单,入口配置新增一项:

entry: {
  'bundle': './js/index.js',
  vendor: ["jquery"],
}

然后 plugins 选项新增:

new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' })

运行 webpack 打包结果:

Version: webpack 3.8.1
Time: 957ms
           Asset     Size  Chunks                    Chunk Names
       bundle.js  25.7 kB       0  [emitted]         bundle
vendor.bundle.js   274 kB       1  [emitted]  [big]  vendor
   [1] ./js/index.js 299 bytes {0} [built]
   [8] multi jquery 28 bytes {1} [built]
    + 7 hidden modules

注意要在 html 文件中优先引入打包结果 vendor.bundle.js !

基于 Webpack 引入公共库的几种方式的更多相关文章

  1. 不停止MySQL服务增加从库的两种方式

    不停止MySQL服务增加从库的两种方式 转载自:http://lizhenliang.blog.51cto.com/7876557/1669829 现在生产环境MySQL数据库是一主一从,由于业务量访 ...

  2. 不停止MySQL服务增加从库的两种方式【转载】

    现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库.前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作. ...

  3. 不停mysql服务添加从库的两种方式

    现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库.前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作. ...

  4. 使用pip安装python库的几种方式

    操作系统 : CentOS7.5.1804_x64 Python 版本 : 3.6.8 1.使用pip在线安装 1.1 安装单个package 格式如下: pip install SomePackag ...

  5. 基于 Webpack 引入 jquery 插件的笔记

    如果都是基于 webpack(npm 上有包),那就非常顺利: import $ from 'jquery' import 'jquery-modal/jquery.modal.min.css' im ...

  6. 详解用webpack的CommonsChunkPlugin提取公共代码的3种方式&lpar;注意webpack4&period;0版本已不存在)

    Webpack 的 CommonsChunkPlugin 插件,负责将多次被使用的 JS 模块打包在一起. CommonsChunkPlugin 能解决的问题 在使用插件前,考虑几个问题: 对哪些 c ...

  7. &lbrack;转&rsqb; 用webpack的CommonsChunkPlugin提取公共代码的3种方式

    方式一,传入字符串参数 new webpack.optimize.CommonsChunkPlugin(‘common.js’), // 默认会把所有入口节点的公共代码提取出来,生成一个common. ...

  8. jQuery引入公共库问题

    话说脚本最好放到底部,这样页面既可以逐步呈现,也可以提高下载,但是某些公共模块且有js效果,顺序优先公共库的话,效果是出不来的,所以以后就把公共库最好放在头部,(就是这个而已:http://apps. ...

  9. Android 接入 OpenCV库的三种方式

           OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows.Android和Mac OS操作系统上.它轻量级而且高效——由一系列 C 函数和少 ...

随机推荐

  1. C&plus;&plus;primer 9&period;43

    题目要求:编写一个函数,接受三个string参数s,oldVal和newVal.使用迭代器及insert和erase函数将s中所有oldVal替换为newVal.测试你的程序,用它替换通用的简写形式, ...

  2. Luogu P3731 &lbrack;HAOI2017&rsqb;新型城市化

    题目显然可以转化为求每一条边对二分图最大独立集的贡献,二分图最大独立集\(=\)点数\(-\)最大匹配数,我们就有了\(50pts\)做法. 正解的做法是在原图上跑\(Tarjan\),最开始我想复杂 ...

  3. C&num;多线程编程のTask(任务全面解析)

    Task是.NET4.0加入的,跟线程池ThreadPool的功能类似,用Task开启新任务时,会从线程池中调用线程,而Thread每次实例化都会创建一个新的线程. 我们可以说Task是一种基于任务的 ...

  4. 五子棋(无AI winform gdi&plus;)

    之前无意间在博客园看到一篇用深度学习玩马里奥的文章,于是就想做这个小东西来测试人工智能算法(准备用PYTHON的库,对神经网络的梦已经做了好多年了,但是太难了,一直懒得动它),本来是想用WPF做UI, ...

  5. MSG结构体和WndProc窗口过程详解

    MSG结构体和WndProc窗口过程对于Windows编程非常重要,如果不了解它们,可以说就没有学会Windows编程. MSG结构体 MSG 结构体用来表示一条消息,各个字段的含义如下: typed ...

  6. Mysql基础之 基础知识解释

    Mysql基础知识 RDBMS:关系型数据库管理系统.是将数据组织成相关的行和列的系统 存储过程:是存储在数据库中的一段声明性语句.触发器.java.php等都可以调用其存储过程.早期的mysql版本 ...

  7. yii---进行增删改查

    我们使用yii进行数据的增删改查: 一.新增数据 使用model::save()操作进行新增数据 $user= new User; $user->username =$username; $us ...

  8. POJ 2253 - Frogger - &lbrack;dijkstra求最短路&rsqb;

    Time Limit: 1000MS Memory Limit: 65536K Description Freddy Frog is sitting on a stone in the middle ...

  9. Loadrunner脚本回放 场景运行过程中常见错误分析

    问题一:Loadrunner超时错误问题描述 Loadrunner超时错误:在录制Web协议脚本回放时超时情况经常出现,产生错误的原因也有很多,解决的方法也不同. 问题现象Error -27728: ...

  10. 【BZOJ】1176&colon; &lbrack;Balkan2007&rsqb;Mokia

    [题意]n*n的矩阵,初始值为0(题面有误),m次操作,增加一个格子的权值,或查询子矩阵和.n<=2*10^6.(m应该较题面所述偏大). [算法]CDQ分治(算法知识见数据结构) [题解]三维 ...