The front-end components are developed in javascript, packaged in Node.js and published to NPM. So we want to do component release, first to understand the development and release of NPM package.

NPM package development and release

Project initialization

We often use the NPM init command to initialize node projects; If the default Settings are used, you can add the -y parameter. Next, we create a new nPM-Components folder and initialize the project:

$ mkdir npm-components
$ cd npm-components
$ npm init -y
Copy the code

At this point, a package.json file appears in the project folder:

{
  "name": "npm-components"./ / component name
  "version": "1.0.0".// Component version
  "description": "".// Component description
  "main": "index.js".// Component entry
  "scripts": { // Component scripts
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": []."author": "".// Component author
  "license": "ISC" // Open source protocol
}
Copy the code

Name, version, main, and script in package.json are common configurations.

Name and Version are the package name and version. Name should be lowercase and underlined (-). Refer to the next section for the version specification.

Script is a script that can be run in a command line tool. If you are not familiar with Linux scripts, you can debug them in the command line tool and then copy them to script.

Main acts as the entry point for the entire component. The default is index.js, which can be modified as needed.

In the project folder, create a new index.js with the default Settings:

// index.js
const hello = 'hello';
const world = 'world';
module.exports.log = function() {
	console.log(hello + world);
};
Copy the code

The simplest NPM project is complete, with just two files, index.js and package.json.

Package. json in addition to the above configuration, we may also configure to

  • Private attributes, whether private projects, private projects are generally not public. We will now publish NPM, so we will either remove this private or set it to false. Non-open source projects, plusprivate: falseYou can avoid releasing them to the public network.
  • Files, the files that need to be published to NPM.
  • The Dependencies project depends on the library, as shown herenpm installLibraries installed into the project;
  • DevDependencies The project development environment depends on the library, as shown herenpm install --save-devLibraries installed into the project.

NPM Version and version specification

Once the development is complete, you can give the component a version number.

According to the semantic version control specification SemVer, the version format is major.minor.patch, and the increment rule is as follows:

  1. Major: When you make incompatible API changes,
  2. Minor: When you make backward-compatible feature additions,
  3. Patch: When you make a backward-compatible problem fix.

The prior version number and version build information can be appended to “major.minor.patch” as an extension. Such as: 1.0.0 – alpha. 0

Before each release, you need to confirm the updated content, select the version number, and use NPM Version to type the version number

$ npm version [patch|minor|major]
Copy the code

At this point, version in package.json is incremented by 1, and you can also see the version number change in some command-line tools.

~/ npm-Components ([email protected]) $NPM version Patch V1.0.1 ~/code/ npm-Components ([email protected]) $Copy the code

Published to the NPM

Once the development is complete and the version number is marked, publishing to NPM is a step-by-step process:

  1. If it is an open source project of public network, you need to register an account on NPM official website.

  2. If your company has an internal NPM library, just ask the NPM administrator to add it to you.

  3. If you normally use other sources, you need to switch to NPM (NRM can be installed to manage multiple sources) :

    $ nrm ls
    ​
      npm -------- https://registry.npmjs.org/
      yarn ------- https://registry.yarnpkg.com/
      cnpm ------- http://r.cnpmjs.org/
      taobao ----- https://registry.npm.taobao.org/
    ​
    $ nrm use npm
    Copy the code
  4. In the command line tool in the root directory of the project, run NPM login, prompting you to enter your personal information to complete the login.

  5. Run, will be uploaded;

    $ npm publish
    Copy the code
  6. If the upload process goes smoothly without a red error message, you can see the package you posted at www.npmjs.com/.

  7. Post packages can be deleted for 72 hours, after which they can never be deleted, so don’t post meaningless packages. If uninstallation is required, perform it within 72 hours of release:

    # npm unpublish 
            
             [@
             
              ]
             
            $NPM unpublish [email protected]Copy the code

At this point, the NPM package for a simple project is published.

modular

In real projects, it is often impossible to write only one JS, and it is impossible to write too long a JS, which will be split into multiple JS. This is where encapsulation comes in.

We encapsulate common content together as a simple module. This whole process can be a modular process.

Modularization helps us to achieve code reuse, but also helps us to achieve the data within the module, method private.

Front-end modular Evolution

Front-end modularization is an evolutionary process that goes through four stages:

  • Global function pattern: Encapsulates different functions into different global functions
  • Namespace mode: Simple object encapsulation
  • IIFE mode: Anonymous function self-invocation (closure)
  • IIFE schema enhancement: Introduce dependencies

The basic principle is to mount the module under the Window property. By the IIFE enhancement phase, the current modular specification has basically taken shape, with obvious introduction and export. The following code is introduced to jQuery and exposed to myModule:

/ / module. Js file
(function(window, $) {
  let data = 'www.baidu.com';
  // A function that manipulates data
  function foo() {
    // Used to expose functions
    console.log(`foo() ${data}`);
    $('body').css('background'.'red');
    otherFun(); // Internal call
  }
  function otherFun() {
    // Internal private function
    console.log('otherFun()');
  }
  // Expose behavior
  window.myModule = { foo }; }) (window, jQuery) // jQuery is introduced as an argument
Copy the code

On this basis, gradually evolved AMD, CommonJS, CMD, UMD and other specifications.

AMD (Asynchromous Module Definition – Asynchronous Module Definition)

AMD is more of a browser side, requiring asynchronous loading of modules before executing internal code. It is the standardized output of RequireJS for module definition in the promotion process, advocating dependency predisposition.

Define (function(){return module}); // Define dependent modules (['module1', 'module2'], function(m1, m2){return module}); // Require (['module1', 'module2'], function(m1, m2){use m1/m2});Copy the code

CommonJS specification

CommonJS is the specification for server modules, as node.js is widely known. According to the CommonJS specification, a single file is a module. The module is loaded using the require method, which reads a file and executes, finally returning the module.exports object inside the file.

//module1.js
moudle.exports = { value: 1 };
​
//module2.js
var module1 = require('./module1');
var value2 = module1.value + 2;
module.exports ={ value: value2 };
Copy the code

CommonJS loads modules synchronously, so you can’t perform any operations until the load is complete.

CMD (Common Module Definition – Public Module Definition)

CMD is the canonical output of the SeaJS module definition in the promotion process, and CMD is also derived from the CommonJS Modules/2.0 specification. For module dependencies, CMD is deferring execution, advocating dependency proximity.

define((require.exports.module) = > {
  module.exports = {
    fun1: () = > {
       var$=require('jquery'); // when fun1 is executed, load again
       return $('#test'); }}; });Copy the code

In the code above, only when the fun1 method is actually executed will you go back to executing jquery.

UMD specification

Is there a specification that is compatible with BOTH AMD and CommonJS, either on the browser side or on the server side?

Yes, it is the UMD specification. The UMD specification isn’t even a specification, it’s a mashup of AMD and CommonJS. Is a fixed code. The following factory model:

((root, factory) = > {
  if (typeof define === 'function' && define.amd) {
    //AMD
    define(['jquery'], factory);
  } else if (typeof exports= = ='object') {
    //CommonJS
    var $ = requie('jquery');
    module.exports = factory($);
  } else {
    // Neither, browser global definition
    root.testModule = factory(root.jQuery);
  }
})(this.($) = > {
  //do something... Here is the actual body of the function
});
Copy the code

ES the module specification

Another specification that supports both the server side and the browser side is the ES Module, which is now the most commonly used import and export:

export default. ;import xxx from ' ';

export. ;import { xxx } from ' ';
Copy the code

However, ES modularity is currently supported only in node.js versions greater than 13.2, and it will take a long time for full use.

Therefore, for compatibility reasons, we still choose the UMD specification for development. (UMD, CMD, AMD specifications on the edge of elimination, we do not need to understand, just need to know that there is such a thing can be)

Webpack packaging

The process of writing UMD is repetitive and tedious, and that’s when tools are needed to do it, and that’s where Webpack comes in. Webpack configuration is fairly simple, as in our project.

Install webpack first

$ npm install --save-dev webpack webpack-cli
Copy the code

Create a new webpack configuration file, webpack.config.js. Package the component library with Webpack to output UMD-compliant code with only minor modifications in the basic configuration:

// webpack.config.js
const path = require('path');
​
module.exports = {
    mode: 'production'.entry: './index.js'.externals: 'lodash'.// The library package includes loDash, which is not included in the package. Users need to import LoDash when importing the library, so as to avoid the user importing LoDash repeatedly, which may cause the file size to be too large.
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'library.js'.library: 'library'.// Global mount package reference name
        libraryTarget: 'umd'.// Universal mode: support users to import NPM packages through ES, common.js, AMD
        globalObject: 'this' // This is required when running environments such as node}}Copy the code

The modifications are as follows:

  1. Filename: the name of the packaging product library;
  2. Externals: ‘lodash’, the library package has imported Lodash, which is not included in the package. Users need to import Lodash when importing the library, so that users can avoid importing Lodash repeatedly.
  3. LibraryTarget: ‘umd’ useUMD specificationSupports users to import NPM packages through ES, common.js and AMD.
  4. Library: ‘library’ adds a liabray variable to the global variable, which is used to mount the package. It is mainly used for configuration of global import via scripting;
  5. GlobalObject: ‘this’, a new attribute for WebPack 4, needs to specify the value of global as ‘this’, otherwise it will default to ‘self’ and cannot be used in nodeJS environments.

Add scripts to package.json

{... script: {"build": "webpack"}}Copy the code

Run the script

npm run build
Copy the code

At this point, the Webpack begins to pack. When we open the packaged file library.js, we’ll find our first 10 lines of UMD specification code. Optimization: {minimize: false} can be packed without compression or confusion (webpack.config. js Settings optimization: {minimize: false}) :

(function webpackUniversalModuleDefinition(root, factory) {
        if(typeof exports= = ='object' && typeof module= = ='object')
                module.exports = factory();
        else if(typeof define === 'function' && define.amd)
                define([], factory);
        else if(typeof exports= = ='object')
                exports["library"] = factory();
        else
                root["library"] = factory(); }) (this.function() {
return / * * * * * * / (() = > { // webpackBootstrap
/ * * * * * * / 	var __webpack_modules__ = ({
/ * * * / 10:
/ * * * / ((module) = > {
const hello = 'hello';
const world = 'world';
module.exports.log = function() {
	console.log(hello + world);
};
/ * * * /})...Copy the code

At this point, a component that supports both browser-side and server-side calls is packaged and ready to be released to the NPM library again with a version number.

Local test

We can use the NPM package for testing, or we can introduce a local package for simple testing during development. We comply with the UMD specification, so we can verify this in both the Node and browser environments:

Node Environment Verification

Create a new index.test.js file in the project root directory

let library = require('./dist/library.js');
library.log();
Copy the code

Local implementation

$ node index.test.js
helloworld
Copy the code

Browser Environment Verification

Create a new public folder in the project root directory and create an index.html folder under this folder

<! DOCTYPEhtml>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>The test page</title>
</head>
<body>
<script src='.. /dist/library.js'></script>
<script>
library.log(); // The console outputs helloWorld
</script>
</body>
</html>
Copy the code

At this point, open this folder and you’ll see console output helloWorld.

If you want a more realistic environment, you can also use a local server for authentication.

First, install the WebPack development server:

$ npm install --save-dev webpack-dev-server
Copy the code

Then, modify package.json to add the WebPack server script:

{..."script": {"serve": "webpack serve --open". }}Copy the code

Modify the webpack. Config. Js

const path = require('path');
module.exports = {
    devServer: {
        static: path.join(__dirname, ". /") // Set the project root directory to static},... }Copy the code

Running server

$ npm run serve
Copy the code

Webpack opens the browser by default. You can see the browser console output HelloWorld.

Verification passed. Done!!

Reference:

  • Know AMD, CMD, UMD, CommonJS
  • Do you really know the NPM versioning specification
  • Semantic version 2.0.0
  • Webpack packs the configuration associated with NPM packages developed by itself
  • Use Webpack to package dependencies common to both Web and Node servers