Home >Web Front-end >JS Tutorial >Principle and implementation of using webpack module to package Library

Principle and implementation of using webpack module to package Library

亚连
亚连Original
2018-05-31 13:53:281938browse

This article mainly introduces the principle and implementation of webpack organization module packaging Library. Now I will share it with you and give you a reference.

The previous article analyzed the basic principles of Webpack packaging JS modules. The case introduced is the most common situation, that is, multiple JS modules and an entry module are packaged into a bundle file, which can be directly Executed by a browser or other JavaScript engine, it is equivalent to direct compilation to generate a complete executable file. However, there is another very common situation, that is, we need to build and publish a JavaScript library. For example, if you publish your own library in the npm community, then Webpack needs corresponding configuration, and the compiled code will be slightly different.

Like the previous article, this article mainly analyzes the generated code of Webpack, and combines it to explain the specific role of Webpack's library configuration options when compiling the library. The corresponding official documentation is here.

Library for writing JS

Let’s start with a simple case. We just write a simple library util.js:

import $ from 'jquery'

function sayHello() {
 console.log("Hello");
}

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

export default {
 sayHello: sayHello,
 hideImages: hideImages
}

provides two functions. Of course, they have nothing to do with each other and are actually of no use. They are purely for teaching reference only. . .

Next write the configuration of Webpack:

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

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

But this alone is not enough, the output file is a function that is executed immediately, Finally, the exports of util.js will be returned. Refer to the analysis in the previous article. The final generated bundle code structure is roughly like this:

(function(modules) {
 var installedModules = {};
 
 function webpack_require(moduleId) {
   // ...
 }

 return webpack_require('./util.js');
}) ({
 './util.js': generated_util,
 '/path/to/jquery.js': generated_jquery
});

If it is executed That’s it. We just return the export part of util.js. What we need is to give this return value to module.export of the compiled file, so that the compiled file becomes a file that can be imported by others. library. So the compiled file we hope to get should be like this:

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
});

To get such a result, the library information needs to be added to the output part of the Webpack configuration:

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

 library: 'util',
 libraryTarget: commonjs2
}

The most important thing here is the libraryTarget. If we now use the commonjs2 format, we will get the above compilation results, which means that Webpack will use the library to convert the final output to CommonJS. The form is exported, thus realizing the release of a library.

Other publishing formats

In addition to commonjs2, libraryTarget has other options:

var (默认值,发布为全局变量)
commonjs
commonjs2
amd
umd

Use different options to compile The files can be used in different JavaScript execution environments. Here we directly see what the output of Wanjinbal umd format looks like:

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

is much more complicated than the previous commonjs2 situation, because it needs to process various There are different cases, but in fact the following parts are the same. The most important ones are the first few lines. This is the standard way of writing the umd module. It runs the passed factory function, which is actually the function that loads the module, and then hands the returned result to the corresponding object according to different operating environments. For example, var will set the result as a global variable, which is used by the browser to directly import the JS file through the 3f1c4e4b6b16bbbd69b2ee476dc4f83a tag; if it is CommonJS, it will be handed over to the exports object; if it is an AMD environment, it will also be used Standard AMD writing. In this way, the published JS library can be used by others in any environment.

targetExport controls the output content

If you use umd format to package, there may be a pit that you need to pay attention to. If the source code of your library is output using ES6 format export default, as above Take util.js as an example. If you put the compiled JS library file directly into the browser and use it, it can be <script> or RequireJS, but you may not get the results you want. This is because the object your JS file returns to you is like this: </script>

{
 &#39;default&#39;: {
  sayHello: sayHello,
  hideImages: hideImages
 }
}

instead of what you expected:

{
 sayHello: sayHello,
 hideImages: hideImages
}

This problem will also occur not only in browsers, but also in module systems that do not support ES6, because they do not understand default. So your compiled JS file should actually only output default, which requires using targetExport in the Webpack configuration to control:

library: 'util',
libraryTarget: umd,
targetExport: 'default'

In this way, the module loading function factory above will add ['default'] after the return value, so that only the default part of exports will be returned.

This pitfall is actually quite easy to step on in the umd format. For example, if you publish a Vue component, the JavaScript part in the .vue file usually exports the Component object in the export default format, like Like this:

export default {
 name: &#39;xxx&#39;,
 data: {
  return // ...
 },
 props: {
  // ...
 }
 methods: {
  // ...
 }
}

If you run the compiled JS file directly in the browser, and use CDN to load Vue through 3f1c4e4b6b16bbbd69b2ee476dc4f83a, You will find that Vue cannot recognize this Component because the object you get has an extra layer of unnecessary defaults.

You may ask if I change the output content to default, will it affect the use of this module in the ES6 environment? Generally speaking no. As mentioned in a previous article, when Webpack's generated code introduces a module, it will set and determine whether it is an export in ES6 format through a value called __esModule. Now if only the default part is exported, then this object is Considered non-ES6 because it does not contain __esModule. In this way, when other modules introduce this module through import, the entire object will be imported, which is actually equivalent to importing only the export default part of the original module in disguise.

Of course, the premise of the above discussion is that all the content you need to export is in export default. If you have both default and normal export, then it is obviously not possible for the compiled file to only export the default part.

The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.

Related articles:

200 lines of code to implement blockchain Detailed blockchain example

vue uses facebook twitter sharing example

react creates a project based on create-react-app

##

The above is the detailed content of Principle and implementation of using webpack module to package Library. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn