17

手撕webpack:创建自己的 library

 3 years ago
source link: https://www.limitcode.com/detail/5ebd42b49581af02a004a95a.html?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

什么是 library?

webpack 除了打包应用程序代码,还可以用于打包 JavaScript library。我们在使用 vue 、element 等前端框架(library)时,可以通过 ES6 Modules import 导入使用,也可以通过 script 引入组件库,更或是使用 CommonJS,要支持这么多的使用方式,需要熟悉使用 output.library 和 output.libraryTarget 两个选型的使用。

搭建自己 library 的基础代码

假设我们正在编写一个校验字符串是否为空的 library,如果输入的字符串为空返回 true,反之返回 false。基本的项目结构如下:

1589591696333.png

src/index.js

function isEmpty(str) {
if(str==null || typeof str=='undefined' || str.trim()=="") {
return true
else {
return false
}
}
export {isEmpty}

理想中 library 在使用时为了避免和其他 library 混淆,一般会起一个自己的独有名称,这里我们使用 MyLibrary ,使用方式如下:

// ES2015 模块引入
import * as MyLibrary 'isEmpty';
// CommonJS 模块引入
var MyLibrary = require('MyLibrary');
var name = "暗夜余晖";
// ES2015 和 CommonJS 模块调用
MyLibrary .isEmpty(name );
// AMD 模块引入
require(['MyLibrary'], function ( MyLibrary) {
var name = "暗夜余晖";
// AMD 模块调用
MyLibrary.isEmpty(name );
});

要实现以上目标,library 应该如何打包呢?

打包适用于 script 标签引入的组件库

用户可以通过 script 标签来加载和使用此 library:

<!doctype html>
<html>
<script src="./dist/isEmpty.js"></script>
<script>
var name = "暗夜余晖";
MyLibrary.isEmpty(name );
</script>
</html>

webpack 的配置:

const path = require("path")
module.exports = {
entry: {
main: './src/index.js'
},
output: {
filename: 'isEmpty.js',
path: path.resolve(__dirname, 'dist'),
library: 'MyLibrary',
libraryTarget: "var"
}
}

library 配置我们的库名称,这里是 "MyLibrary",libraryTarget 配置如何对外暴露 library ,不写的时候默认值是 "var"。

libraryTarget: "var"  表示当 library 加载完成,入口起点的返回值将分配给一个变量,向下面这样:

var MyLibrary = _entry_return_;

来看看实际打包后的输出结果(只截取开头一小段):

1589683397486.png

暴露为 window 对象的属性

上面打包出的文件,isEmpty 方法被使用时需要增加 MyLibrary 前缀,即 库名.函数名 的格式,有时我们的函数名可能是一个独一无二的名称,更期望简洁方便的直接使用函数名的方式调用,类似下面这样:

<!doctype html>
<html>
<script src="./dist/isEmpty.js"></script>
<script>
var name = "暗夜余晖";
// 直接使用函数名
isEmpty(name);
// 或是
window.isEmpty(name);
</script>
</html>

想打出这种 library  也很简单,把 output.library 的值配置成空,  output.libraryTarget 值改成 "window" 就可以了:

const path = require("path")
module.exports = {
entry: {
main: './src/index.js'
},
output: {
filename: 'isEmpty.js',
path: path.resolve(__dirname, 'dist'),
library: '',
libraryTarget: "window"
}
}

打包后的 bundle 代码就不贴了,知道它的原理就可以了:

libraryTarget: "window" 会将入口起点的返回值赋值给 window 对象的某个属性,这个属性取决于 library 的值。如果不设置 output.library 将导致由入口起点返回的所有属性,都会被赋值给给定的对象,这里并不会检查现有的属性名是否存在。

打包为模块

打包后的 bundle 能与各种模块系统(commonjs2、ES2015、AMD )兼容。

打包为 CommonJS 模块

用户可以使用 require 引入模块。

// CommonJS 模块引入
var MyLibrary = require('MyLibrary');
var name = "暗夜余晖";
// CommonJS 模块调用
MyLibrary .isEmpty(name );

使用 libraryTarget: "commonjs2" , 入口起点的返回值将分配给 module.exports 对象,这个名称也意味着模块用于 CommonJS 环境。使用  libraryTarget: "commonjs2"  时 output.library 将被忽略,所以我们可以不配置这个属性的值。

const path = require("path")
module.exports = {
entry: {
main: './src/index.js'
},
output: {
filename: 'isEmpty.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: "commonjs2"
}
}

打包后的 bundle 结果:

1590022799180.png

打包为兼容全部环境的 library

libraryTarget: "umd" - 将你的 library 暴露为所有的模块定义下都可运行的方式。它将在 CommonJS, AMD 环境下运行,或将模块导出到 global 下的变量。

const path = require("path")
module.exports = {
entry: {
main: './src/index.js'
},
output: {
filename: 'isEmpty.js',
path: path.resolve(__dirname, 'dist'),
library: 'MyLibrary',
libraryTarget: "umd"
}
}

打包后的 bundle 结果:

1590024215490.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK