webpack external模块的具体使用

这篇文章讨论Webpack打包library时经常需要用到的一个选项external,它用于避免将一些很通用的模块打包进你发布的library里,而是选择把它们声明成external的模块,在你的library被上层使用后,在最后阶段由Webpack统一把这个external的依赖模块打包进来。

external选项一般都是用在打包library上面,如果不是library而是一个最终的app的发布JS文件,那external也没有什么意义。关于Webpack打包library的分析和一些选项的作用,我在前一篇文章做了讨论。

external选项

我们仍然使用前一篇文章的例子,定义一个库util.js:

import $ from 'jquery'

function hideImages() {
 $('img').hide();
}

export default {
 "hideImages": hideImages
}

我们使用Webpack打包发布这个库:

// 入口文件
entry: {
 util: './util.js',
}

// 输出文件
output: {
 path: './dist',
 filename: '[name].dist.js'

 library: 'util',
 libraryTarget: commonjs2,
 targetExport: 'default'
}

这样打包出来的util.dist.js文件会把jquery的代码完整地注入进去,因为你的源代码使用到了它。但是这往往并不是我们希望的,因为jquery是很通用的模块,在一个app中,很可能其它的库也会用到它,最顶层的入口文件app也可能用到它,如果每一个库模块的发布版本都将jquery原封不动地打包进了自己的bundle,最后拼到一起,在最终的app发布代码里就会有很多份jquery的复制,当然这可能并不会影响它的正常功能,但是会占据很大的代码体积。

所以通常情况下当你的库需要依赖到例如jquery,bootstrap这样的通用JS模块时,我们可以不将它打包进bundle,而是在Webpack的配置中声明external:

externals: {
 jquery: {
  root: 'jquery',
  commonjs: 'jquery',
  commonjs2: 'jquery',
  amd: 'jquery',
 },
},

这就是在告诉Webpack:请不要将这个模块注入编译后的JS文件里,对于我源代码里出现的任何import/require这个模块的语句,请将它保留。

我们可以看一下编译后的bundle文件的结构:

module.exports = (function(modules) {
 var installedModules = {};
 function webpack_require(moduleId) {
   // ...
 }
 return webpack_require('./util.js');
}) ({
 './util.js': generated_util,
 // '/path/to/jquery.js': generated_jquery 原本有这一行,现在被删去。
});

可以看到jquery模块没有被打包进bundle文件,而对于util,它的生成代码即generated_util函数中关于import jquery相关的语句也被保留了原意:

function generated_util(module, exports, webpack_require) {
 var $ = require('jquery');
 // util的其它源代码
 // ...
}

当然也并非完全没有修改,例如将import的改回了传统的require关键词,因为我们这里用的是CommonJS风格的打包方式。不过这些都是次要的,关键是它保留了require这个关键词,而没有使用webpack_require将jquery真的引入进来。这就是说,当前的这个JS文件的模块管理系统中是没有jquery的,它是一个external的模块,需要在这个JS文件被其它人引用并且在上层编译时,jquery才可能被真的引入进来,到那个时候这里的require关键词才会被替换为webpack_require。

对于external的依赖模块,通常你可以这样做,例如你使用npm发布你的库,你可以将jquery在package.json文件中添加到dependencies,这样别人npm install你发布的库时,jquery也会被自动下载到node_modules供别人打包使用。

umd格式下的打包

如果我们使用umd格式打包,我们可以看到在不同环境中,external模块是如何发挥作用的:

(function webpackUniversalModuleDefinition(root, factory) {
 if(typeof exports === 'object' && typeof module === 'object') // commonjs2
  module.exports = factory(require('jquery'));
 else if(typeof define === 'function' && define.amd)
  define("util", ['jquery'], factory); // amd
 else if(typeof exports === 'object')
  exports["util"] = factory(require('jquery')); // commonjs
 else
  root["util"] = factory(root['jquery']); // var
}) (window, function(__webpack_external_module_jquery__) {
 return (function(modules) {
  var installedModules = {};
  function webpack_require(moduleId) {
    // ...
  }
  return webpack_require('./util.js');
 }) ({
  './util.js': generated_util,
 });
}

而generated_util也相应地增加一个参数__webpack_external_module_jquery__:

function generated_util(module, exports, webpack_require,
            __webpack_external_module_jquery__) {
 var $ = __webpack_external_module_jquery__;
 // util的其它源代码
 // ...
}

这样的写法似乎结构和上面的CommonJS的编译版本不太一样,但实际上本质是一样的。因为现在umd要照顾到不同的运行环境,所以它把require('jquery')提前了,作为factory的参数传入。对于每种运行环境,各有各的做法:

  1. CommonJS:保留require('jquery')语句。
  2. AMD:在define中将jquery定义为依赖模块。
  3. Var:从全局域中取出jquery变量,这需要jquery在该模块之前就已经被加载。

然后不管是哪种情况,它们都将载入后的jquery模块作为参数传入factory函数,这样就能正确加载util模块了。

以上涉及到Webpack生成代码的部分可能有点绕,需要你比较了解Webpack打包模块的机制和原理,关于这部分我在这篇文章里做了详细讨论。

总结

以上就是关于Webpack的external选项的使用,并且从编译后的JS代码分析了它到底是如何起作用的。我想阅读Webpack相关的生成代码还是很重要的,这样才算是真正地理解了external的机制,在碰到一些坑时才能知道怎么去debug。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • 深入浅出webpack之externals的使用
(0)

相关推荐

  • 深入浅出webpack之externals的使用

    我们通常在做项目时可能会把第三方库打包到bundle中,比如下面这张图 如果不想把第三方库打包到bundle中,这就有了externals.官方的使用externals比较简单 externals 官网文档解释的很清楚,就是webpack可以不处理应用的某些依赖库,使用externals配置后,依旧可以在代码中通过CMD.AMD或者window/global全局的方式访问. 只需三步-- 1.在HTML中引入第三方库的cdn 2.在webpack中配置externals externals: {

  • webpack external模块的具体使用

    这篇文章讨论Webpack打包library时经常需要用到的一个选项external,它用于避免将一些很通用的模块打包进你发布的library里,而是选择把它们声明成external的模块,在你的library被上层使用后,在最后阶段由Webpack统一把这个external的依赖模块打包进来. external选项一般都是用在打包library上面,如果不是library而是一个最终的app的发布JS文件,那external也没有什么意义.关于Webpack打包library的分析和一些选项的

  • 浅谈webpack组织模块的原理

    现在前端用Webpack打包JS和其它文件已经是主流了,加上Node的流行,使得前端的工程方式和后端越来越像.所有的东西都模块化,最后统一编译.Webpack因为版本的不断更新以及各种各样纷繁复杂的配置选项,在使用中出现一些迷之错误常常让人无所适从.所以了解一下Webpack究竟是怎么组织编译模块的,生成的代码到底是怎么执行的,还是很有好处的,否则它就永远是个黑箱.当然了我是前端小白,最近也是刚开始研究Webpack的原理,在这里做一点记录. 编译模块 编译两个字听起来就很黑科技,加上生成的代码

  • 浅谈Webpack核心模块tapable解析

    本文介绍了Webpack核心模块tapable,分享给大家,具体如下: 前言 Webpack 是一个现代 JavaScript 应用程序的静态模块打包器,是对前端项目实现自动化和优化必不可少的工具,Webpack 的 loader (加载器)和 plugin (插件)是由 Webpack 开发者和社区开发者共同贡献的,而目前又没有比较系统的开发文档,想写加载器和插件必须要懂 Webpack 的原理,即看懂 Webpack 的源码, tapable 则是 Webpack 依赖的核心库,可以说不懂

  • webpack组织模块打包Library的原理及实现

    之前一篇文章分析了Webpack打包JS模块的基本原理,所介绍的案例是最常见的一种情况,即多个JS模块和一个入口模块,打包成一个bundle文件,可以直接被浏览器或者其它JavaScript引擎执行,相当于直接编译生成一个完整的可执行的文件.不过还有一种很常见的情况,就是我们要构建发布一个JavaScript的库,比如你在npm社区发布自己的库,这时Webpack就需要相应的配置,编译生成的代码也会略有不同. 和之前一篇文章一样,本文主要分析的是Webpack的生成代码,并结合它来说明编译库时W

  • Webpack常见静态资源处理-模块加载器(Loaders)+ExtractTextPlugin插件

    webpack系列目录 webpack 系列 二:webpack 介绍&安装 webpack 系列 三:webpack 如何集成第三方js库 webpack 系列 四:webpack 多页面支持 & 公共组件单独打包 webpack 系列 五:webpack Loaders 模块加载器 webpack 系列 六:前端项目模板-webpack+gulp实现自动构建部署 基于webpack搭建纯静态页面型前端工程解决方案模板, 最终形态源码见github: https://github.com

  • 详解用webpack把我们的业务模块分开打包的方法

    webpack我自己还在摸索学习中,今天给大家分享个用webpack把我们的业务模块分开打包的方法,顺便留个笔记 如何用webpack打包这3个js? 只需修改webpack的配置文件webpack.config.js: // entry是入口文件,可以多个,代表要编译那些js entry:['./src/main.js','./src/login.js','./src/reg.js'], 这样就可以全部打包,最终生成./build/js/build.js 1,那么如果我们想最后生成不同的文件,

  • 探索webpack模块及webpack3新特性

    本文从简单的例子入手,从打包文件去分析以下三个问题:webpack打包文件是怎样的?如何做到兼容各大模块化方案的?webpack3带来的新特性又是什么? 一个简单的例子 webpack配置 // webpack.config.js module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, }; 简单的js文件 // sr

  • webpack打包优化的几个方法总结

    为什么要优化打包? 项目越做越大,依赖包越来越多,打包文件太大 单页面应用首页白屏时间长,用户体验差 我们的目的 减小打包后的文件大小 首页按需引入文件 优化 webpack 打包时间 优化方式 1. 按需加载 1.1 路由组件按需加载 const router = [ { path: '/index', component: resolve => require.ensure([], () => resolve(require('@/components/index'))) }, { pat

  • 详解如何使用webpack打包Vue工程

    使用webpack打包Vue工程 前言 入行一年,从什么都不懂的小白,到现在什么都懂一点的小白,也算是飞跃了.感叹一下现在的前端,从nodejs出来到现在各种各样的工具如雨后春笋般的出现.大神们疯狂的造轮子,玩的不亦乐乎.我等小白们,疯狂追赶,学的心肝脾肺都快衰竭.而我的精力也仅限浅尝辄止,但是学多一点总有好处的.本篇文章就是介绍如何使用webpack构建前端工程. 目标 本次的工程以Vue.js为主角,Vue.js是一款小巧优雅而且强大的轻量级mvvm框架,配合webpack模块化打包.制作出

  • 详解webpack介绍&安装&常用命令

    webpack系列目录 webpack 系列 二:webpack 介绍&安装 webpack 系列 三:webpack 如何集成第三方js库 webpack 系列 四:webpack 多页面支持 & 公共组件单独打包 webpack 系列 五:webpack Loaders 模块加载器 webpack 系列 六:前端项目模板-webpack+gulp实现自动构建部署 基于webpack搭建纯静态页面型前端工程解决方案模板, 最终形态源码见github: https://github.com

随机推荐