Part 3 – Packaging: Package the project and publish it to NPM

The original link

The component library is now maintained by our team

The introduction

In the previous section, we built and tested the library using React and other related technologies. Now we are ready to package the previous code and publish it to NPM for others to use.

The tutorial section

This article is the third in a series: project packaging and publishing to NPM

  • Part 1: Undo a background project from 0 to 1
  • Part two: Adding unit tests to components
  • Part three: Project packaging and publishing to NPM

Reliable (document + packaging) tool: father

This is where component library development finally gets to the most important part, solving the (documentation + packaging) problem.

After trying a few packaged libraries (such as create-react-Library) and the React Styleguidist, they didn’t achieve the desired effect.

Until a video of STATION B: Use UMi-Library to do component packaging, the answer becomes simple and obvious, is to use the open source component packaging tool of Yunqian: umiJS /father, to complete the last step.

Because currently the entire packaging tool uses SRC as an entry point. In order to avoid previous routing, the home page and other code are packed in. Here, the project structure has been greatly changed, adding entry as the entry of the route and SRC as the entry of the component. You are advised to refer to the directory structure in DANTD.

Package. json and field details

After the project is initialized, next, open the project with the editor and modify the following properties in package.json:

{ "main": "lib/index.js", "module": "es/index.js", "typings": "lib/index.d.ts",c "files": [ "dist", "lib", "es" ], "scripts": { "start": "father doc dev", "doc:build": "father doc build", "doc:deploy": "Father doc deploy", "lib:build": "father build", "peerDependencies": {"react": ">=16.8.0", "react-dom": "> = 16.8.0 antd", "" :" > = 3.21.0 "}, "devDependencies" : {" Babel - the plugin - import ":" ^ 1.13.0 ", "father" : "^ 2.29.2 fs -", "extra" : "^ 8.1.0", "klaw - sync" : "^ 6.0.0"}, "dependencies" : {" antd ":" ^ 3.21.0 ", "classnames" : ^2.2.6", "lodash": "^4.17.15"},}Copy the code

Once added, run: NPM install to install dependencies. While we wait, let’s take a look at what these attributes mean:

  • “main”: “lib/index.js”To define thenpmPackage entry file, browser and Node environment can be used
  • “module”: “es/index.js”Definition:npmPackage ESM specification entry file, browser and Node environment can be used

We use the import version of the ES6 module specification if it already supports the PKG. module field. This enables Tree Shaking. 2. If it doesn’t already recognize the pkG. module field, it will use the version require(‘package1’) that we’ve compiled into the CommonJS specification and won’t block the packaging process.

  • Typings: type declaration file of the package
  • Files: Describes all the items that a software package contains when installed as dependencies, as explained in the official documentation
  • Scripts /”start”: “father doc dev” : develop components as docZ
  • Scripts /”doc:build”: “father doc build”: builds the document
  • Scripts /”doc:deploy”: “father doc deploy”: publishes the document
  • Scripts /”build”: “father build”: package components
  • peerDependencies: is a special type of dependency that only appears when you distribute your own package. If this property is written, it means that the dependency package that you are developing the software needs to be exactly the same as the dependency set by this property. Here because some components are based onAntdSo, when you use this component library, you also need to install the corresponding versionAntdSuch dependence.
  • Dependencies: These are your regular dependencies, or the dependencies you need to run your code (such as React or ImmutableJS).
  • DevDependencies: These are your development dependencies. Dependencies that are required at some point in the development workflow but not when running code (such as Babel or Flow).

Package the first component

Here, we add the document to: EmptyLine. For ease of reading, all the relevant code for the component is included here.

src/index.tsx
export { default as EmptyLine } from './empty-line';
Copy the code
src/empty-line/index.tsx
import './style/index.less';
import EmptyLine from './EmptyLine';

export default EmptyLine;
Copy the code
src/empty-line/index.mdx
-- name: EmptyLine route: /empty-line menu: component -- import {Playground} from 'docz'; import EmptyLine from './index'; ## EmptyLine > EmptyLine, custom component, Width is 100% demo # # # # # # # code copy information < Playground > < / p > < p > the first line of text < EmptyLine / > < p > the next text line < / p > < / Playground > | # # API parameters | | | | type a default value | : - | : - | : - | : - | | height highly | | empty row number? 20 | |Copy the code
src/empty-line/EmptyLine.tsx
import React from 'react'; import './style/index.less'; export interface IEmptyLineProps { height? : number; } const EmptyLine = ({ height = 20 }: IEmptyLineProps) => { return <div className="empty-line" style={{ height }} />; }; export default EmptyLine;Copy the code
src/empty-line/style/index.less
.empty-line {
    width: 100%;
    height: 20px;
}
Copy the code
.fatherrc.js
Export default {// cssModules: true, // the default is.module. CSS with CSS modules,.css without CSS modules. When cssModules is set to true, all CSS files go to CSS modules. ExtractCSS: true, esm: 'Babel ', CJS:' Babel ', umd: {name: 'dantd', sourcemap: true, globals: {react: 'React', antd: 'antd' }, }, extraBabelPlugins: [ ['import', { libraryName: 'antd', libraryDirectory: 'es', style: True}],], entry: 'SRC /index.tsx', lessInBabelMode: true, doc: {base: '/dantd/', menu: [' home ',' component ']},}Copy the code

For more configuration items, please explore the documentation: umijs/father

tsconfig.json
{
    "compilerOptions": {
      "baseUrl": "./src",
      "paths": {
        "antd": ["src/index.tsx"],
        "antd/es/*": ["src/*"]
      },
      "strictNullChecks": true,
      "moduleResolution": "node",
      "esModuleInterop": true,
      "experimentalDecorators": true,
      "jsx": "preserve",
      "noUnusedParameters": true,
      "noUnusedLocals": false,
      "noImplicitAny": true,
      "target": "es6",
      "lib": ["dom", "es2017"],
      "skipLibCheck": true
    },
    "exclude": ["node_modules", "lib", "es"]
}
Copy the code

After you add these files, run NPM start to see the following interface.

If you want to import Antd, you can import Antd directly. In the above configuration, you have added extraBabelPlugins. Antd can be loaded on demand.

Code introduced in the component:

import { Card, Typography } from 'antd';
Copy the code

ES6 packaging code:

import "antd/es/card/style";
import _Card from "antd/es/card";
import "antd/es/typography/style";
import _Typography from "antd/es/typography";
Copy the code

CommonJS package code:

require("antd/es/card/style");

var _card = _interopRequireDefault(require("antd/es/card"));

require("antd/es/typography/style");

var _typography = _interopRequireDefault(require("antd/es/typography"));
Copy the code

Package the code and publish it to NPM

First, run the Father Build package.

As you can see, father will be packaged according to the three formats: UMd, CJS, es respectively. After packaging, you will see the following files.

├ ─ ─ dist | ├ ─ ─ empty - line | | ├ ─ ─ EmptyLine. Which s | | ├ ─ ─ the index, which s | | └ ─ ─ style | | └ ─ ─ the index, which s | ├ ─ ─ the index, which s | ├ ─ ─ index. The umd. CSS | ├ ─ ─ index. The umd. Js | ├ ─ ─ index. The umd. Js. Map | ├ ─ ─ index. The umd. Min. CSS | ├ ─ ─ index. The umd. Min. Js | └ ─ ─ Index. The umd. Min. Js. Map ├ ─ ─ es | ├ ─ ─ empty - line | | ├ ─ ─ EmptyLine. Js | | ├ ─ ─ index. The js | | └ ─ ─ style | | ├ ─ ─ index. The CSS | | └ ─ ─ index. Js | └ ─ ─ index. The js ├ ─ ─ lib | ├ ─ ─ empty - line | | ├ ─ ─ EmptyLine. Js | | ├ ─ ─ index. The js | | └ ─ ─ style | | ├ ─ ─ Index. CSS | | └ ─ ─ index. The js | └ ─ ─ index, jsCopy the code

At this point, you can see that three types of packages have been successfully typed. Is this the time to upload to NPM?

There are no type files in the es and lib directories after comparing the Antd NPM package. You need to copy the files in the dist directory and change.less to.css. Here are two script hacks to write.

Install dependencies:

npm install klaw-sync fs-extra -D
Copy the code

Add 2 scripts:

  • scripts/moveDeclare.js

    const path = require(‘path’); const klawSync = require(‘klaw-sync’); const fs = require(‘fs’);

    const filesRegex = /.d.ts$/;

    const declarePaths = klawSync(path.resolve(__dirname, ‘.. /dist’), { nodir: true }).filter(pathItem => filesRegex.test(pathItem.path))

    declarePaths.forEach((pathItem) => { const esPath = pathItem.path.replace(‘/dist’, ‘/es’); const libPath = pathItem.path.replace(‘/dist’, ‘/lib’); fs.copyFileSync(pathItem.path, esPath); fs.copyFileSync(pathItem.path, libPath); })

    Console. log(‘.d.ts file copied successfully! ‘);

  • scripts/changeLess2Css.js

    const path = require(‘path’); const klawSync = require(‘klaw-sync’); const fs = require(‘fs’);

    const filesRegex = /(.js|.d.ts)$/;

    const fileFilterFn = item => { const basename = path.basename(item.path); return filesRegex.test(basename) || basename.indexOf(‘.’) < 0; }

    const esPaths = klawSync(path.resolve(__dirname, ‘.. /es’), { filter: fileFilterFn, nodir: true }).map(item => item.path)

    const libPaths = klawSync(path.resolve(__dirname, ‘.. /lib’), { filter: fileFilterFn, nodir: true }).map(item => item.path)

    const allPaths = esPaths.concat(libPaths);

    allPaths.forEach((fileItem) => { const fileContent = fs.readFileSync(fileItem, ‘utf8’); const newFileContent = fileContent.replace(/.less/gi, ‘.css’); fs.writeFileSync(fileItem, newFileContent, ‘utf8’); })

    Console. log(‘.less =>. CSS file suffix changed successfully! ‘);

Modify package command:

"build": "father build && node ./scripts/moveDeclare.js && node ./scripts/changeLess2Css.js"
Copy the code

Run: NPM run build

This time, the packaged files can be uploaded to NPM.

First log in NPM:

Commit all the code with Git, then change the version number and publish the code:

npm version patch
git push
npm publish
Copy the code

If the package name is registered or the NPM source is incorrect, error 403 will be reported

At this point, our first component library has been uploaded to NPM and we can use NPM install dantd to download our installation package and use the components in our project.

Package the document and publish it to GitHub Pages

First, add a Git address to the package.json file to facilitate subsequent documentation:

"repository": {
    "type": "git",
    "url": "https://github.com/jokingzhang/dantd"
},
Copy the code

Run the following command to package the document:

npm run doc:build
Copy the code

Run the following command to publish the document:

npm run doc:deploy
Copy the code

Then access the corresponding address to see the component documentation we have posted online: dantd

conclusion

The first component library of our own was released to NPM. 🎉🎉🎉 However, what components need to be written into the component library is what we need to consider next.

If you enjoyed this series, feel free to comment and share the link to the article. In addition, you are also welcome to ridicule, 🙏 these feedback is very valuable to me, so that I can write better articles in the future.