Build a js library using webpack

hzc
Release: 2020-07-04 09:54:08
forward
2643 people have browsed it

Preface

In the previous article, I said that the audience of this series of articles is students who are proficient in writing business code under the modern front-end system. Therefore, when introducing webpack configuration, this article only mentions building a library. Unique configuration, please refer to webpack official documentation for other configurations.

Output product

The biggest difference between building a library and building a general application lies in theproduct output after the build is completed.

After the general application is built, it will output:

  • One html file
  • One js entry chunk, several sub-chunks
  • Several css files
  • Several other resources, such as pictures, font files, etc.

Although there are many output resources, in fact all dependencies and loading relationships have started from the html file layer by layer. It's settled, in other words, this html file is actually the entrance to the entire application.

After a library is built, it will output:

  • A js file in CommonJS format
  • An uncompressed js file in UMD format
  • A compressed UMD format js file
  • may include several css files
  • may include several other resource files

The entrances to the library are listed above js file; you may be wondering, how can a library have 3 entry files? Don't be impatient, just listen to me.

CommonJS

CommonJSis a modular specification promoted by Node.js. The main syntax includesmodule.exports,require( ), etc.; when we use webpack to introduce npm packages, we are actually in the Node.js environment. From this, we can see that the entry js file in CommonJS format (.common.js) is used by other applications to introduce npm packages in the Node.js environment. Since the size of the npm package is generally not considered too much when referencing the npm package (you can compress it yourself if necessary when building your own application), and for the convenience of debugging, the js entry file is not compressed.

UMD

UMDis a hodgepodge of modular specifications. In addition to being compatible with CommonJS, it is also compatible with theAMDmodular specification, as well as the most traditional Global variable mode.

Here is a brief introduction to the AMD specification. The full name of AMD isAsyncchronous Module Definition. It is generally used on the browser side (this is the biggest difference from the CommonJS specification). The most famous AMD loader isRequireJS. Currently, due to the popularity of webpack, AMD's modular solution has gradually withdrawn from the market.

Global variable modeis easy to understand, which is to mount the library entry on a global variable (such aswindow.xxx), any The location can be accessed at any time, which is the most traditional js plug-in loading solution.

As can be seen from the above, the entry js file in UMD format can be used to reference npm packages (uncompressed version, that is,.umd.js) , can also be used directly on the browser side (compressed version, i.e..umd.min.js).

How to build library files with different modular specifications

Currently, webpack does not support generating multiple entry js files at the same time, so it needs to be built multiple times.

The key webpack configuration is:

  • CommonJS:output.libraryTarget: "commonjs2"
  • UMD:output.libraryTarget : "umd"

For UMD, we also need to set the global variable name, that is,output.library: "LibraryName".

In order to compress the built files, the simplest way is to call the webpack command in the CLI with themodeparameter, such aswebpack --mode=production; This is because when the value of mode isproduction, webpack will automatically enableUglifyJsPluginto compress the source code.

Output version information

When I worked in a company, the company was very strict about third-party dependencies. All third-party dependencies used in the project must be applied for and approved. It can be used; and the application is accurate to the specific version, and unapplied software versions are not allowed to be used. Some third-party dependencies do not reflect the version number either in the file content or in the file name, which creates obstacles for us to identify such third-party dependencies. This is a warning we need to take when developing our own libraries. of.

When building the library, we can use webpack to directly output the library information into the file content. With this "identity information", users will feel extra at ease when using it.

The method to output library version information is to use webpack.BannerPlugin. The simplest method of use is as follows:

const pgk = require('./package.json'); const banner = ` ${pkg.name} ${pkg.description}\n @version v${pkg.version} @homepage ${pkg.homepage} @repository ${pkg.repository.url}\n (c) 2019 Array-Huang Released under the MIT License. hash: [hash] `; /* webpack 配置 */ { // ...其它配置 plugins: [ // ...其它 plugin 配置 new webpack.BannerPlugin(banner); ] }
Copy after login

The final generated effect is:

/*! * * vue-directive-window * Vue.js directive that enhance your Modal Window, support drag, resize and maximize. * * @version v0.7.5 * @homepage https://github.com/Array-Huang/vue-directive-window * @repository git+https://github.com/Array-Huang/vue-directive-window.git * * (c) 2019 Array-Huang * Released under the MIT License. * hash: dc6c11a1e50821f4444a * */
Copy after login

source map

如果库的用户是直接通过在浏览器里加载你的库来使用的话,那么提供一份source map文件是非常有必要的;这是因为你的库在经过 webpack 构建,甚至压缩后,与源代码已经大相径庭了,用户将难以在浏览器中进行调试;但如果你能为自己的库附上一份 source map ,浏览器开发者工具会调用 source map 来帮助解析,用户的调试体验会更接近于调试库的源码。

相应的 webpack 配置为:

// webpack 配置 { // ...其它配置 devtool: 'cheap-module-source-map' }
Copy after login

webpack 支持多种类型的 source map ,不同类型的 source map 在生成速度、支持功能(如 babel )、调试位置偏移等问题上均有不同表现,我这边只做推荐:

  • 开发环境:cheap-module-eval-source-map
  • 生产环境:cheap-module-source-map

关于其它类型的 source map ,请查看 webpack 官方文档的 devtool 章节。

排除第三方依赖

与一般应用不一样,在开发库的时候,我们应尽量避免引入第三方库(构建过程中使用的工具链除外),因为这些第三方库会让我们写的库的大小猛增;很可能会出现这样的情况:我们自己写的小功能只有几百行代码的逻辑,构建出来的库却有几百k,那这样的库意义就不大了。

但我们的确也很难避免使用第三方库,那该咋办呢?

// webpack 配置 { // ...其它配置 externals: { lodash: { commonjs: 'lodash', commonjs2: 'lodash', amd: 'lodash', root: '_' } } }
Copy after login

使用上述配置后,我们构建出来的库中就不会包含配置中指定的第三方库(例子中为lodash)了,下面来一一详解:

  • commonjscommonjs2项都是指明用户在 node.js 环境下使用当前库时,以CommonJS的方式来加载名为lodash的 npm 包。
  • amd项表示在浏览器中加载运行本库时,本库会试图以AMD的方式来加载名为lodash的 AMD 模块。
  • root项表示在浏览器中加载运行本库时,本库会试图取全局变量window._(通过