This time is very spare, “the leader” to our front end put forward some requirements that we can have our own component library, beautiful name: development to improve efficiency, unified style, reduce the burden. Well, it’s really free!

Holding this is the command of the leadership himself is a small dish chicken want to progress of the idea decided to try, even if play or began the journey; Ramble on the net one morning, blog article a lot, it is anticlimactic, have come to have no return, have no way perhaps all be god note, can oneself do, always want oneself do, perhaps I write return not as good as somebody else! Let’s get started!

The first step is preparation

Create a new folder, go to the command line and say NPM init,

$NPM init name: (wq-components) Version: (1.0.0) 0.1.0 Description: An example component library with React! entry point: (index.js) test command: git repository: keywords: Author: machinish_wq license: (ISC)MIT About to write to /Users/alanbsmith/personal-projects/trash/package.json: { "name": "Wq -components", "version": "0.1.0", "description":" An example component library with React!" , "main": "dist/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": machinish_wq, "license": "MIT" } Is this ok? (yes)Copy the code

Add the following configuration file to the root directory: touch pubilc/index.html script/.babelrc.gitignore.npmignore readme.md

  • Pubilc /index.html stores the root template
  • The script/ folder holds webpack.config files
  • .babelrc contains some useful presets at compile time
  • .gitignore and.npmignore are used to ignore files from Git and NPM, respectively
  • Readme.md is also very important. This is the main way we communicate with the open source community

pubilc/index.html

<! DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>React</title> </head> <body> <div id="root" class="root"></div> </body> </html>Copy the code

script/webpack.dev.config.js

const path = require('path'); const webpack = require('webpack'); const webpackConfigBase = require('./webpack.base.config'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const { merge } = require('webpack-merge'); function resolve(relatedPath) { return path.join(__dirname, relatedPath) } const webpackConfigDev = { mode: 'development', entry: { app: [resolve('../src/index.js')], }, output: { path: resolve('.. // lib'), filename: 'button.js',}, devtool: 'cheap-module-eval-source-map', devServer: {// contentBase: resolve('.. /lib'), hot: true, open: true, host: 'localhost', port: 8080, }, plugins: [ new HtmlWebpackPlugin({template: './public/index.html', }), new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin() ] } module.exports = merge(webpackConfigBase, webpackConfigDev)Copy the code

script/webpack.prod.config.js

const path = require('path'); const webpack = require('webpack'); const nodeExternals = require('webpack-node-externals'); const webpackConfigBase = require('./webpack.base.config'); const TerserJSPlugin = require('terser-webpack-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const { merge } = require('webpack-merge'); function resolve(relatedPath) { return path.join(__dirname, relatedPath) } const webpackConfigProd = { mode: 'production', entry: { app: [resolve('../src/components/index.js')], }, output: { filename: 'index.js', path: resolve('.. // lib'), library: {root: "componentLibrary", AMD: "componentLibrary",}, library target: "umd"}, devTool: Minimizer: {minimizer: {minimizer: {minimizer: {minimizer: {minimizer: {minimizer: {minimizer: [// compress js code new TerserJSPlugin({// compress parallel: 4,// enable parallel compression terserOptions: {compress: {drop_console: True, // Delete all 'console' statements},},}), // Compress CSS code new OptimizeCSSAssetsPlugin()],}, externals: [nodeExternals()], plugins: } module.exports = merge(webpackConfigBase, webpackConfigProd)Copy the code

Note: libraryTarget and Library are required output attributes for library development.

Development libraries can be referenced in the following ways:

  1. Traditional script mode:
<script src="demo.js"></script>
Copy the code
  1. AMD way:
define(['demo'], function(demo) {
demo();
});

Copy the code
  1. Commonjs way:
const demo = require('demo');
demo();

Copy the code
  1. The ES6 module is imported
import demo from 'demo';
Copy the code

Why does the class library support different introductions? This is what webpack.library and output.libraryTarget provide. The output.libraryTarget property controls how webPack packed content is exposed. There are three ways of exposure:

  • Expose a variable

LibraryTarget: the “var” webpack package assigns a value to a variable named output.library. Copies the packaged content to a global variable that is used directly when referencing the class library, which is not supported by the NodeJS environment.

  • Exposure by object properties

LibraryTarget: “this” libraryTarget: “window” libraryTarget: “global” (node is supported in this case) The above three methods export your method functions on public objects. Advantages: Reduced variable conflicts Disadvantages: Not supported in the NodeJS environment

  • Exposure through modules

LibraryTarget: exports “commonjs” directly from exports objects — node supports library variables, browsers do not. “Commonjs2” is exported directly from module.exports, ignoring library variables. Node supports this option, browsers do not support this option. Why doesn’t CommonJS need to introduce RequireJS separately? Commonjs is a server-side modularization language specification that uses requireJS in Node. Amd belongs to the specification of client module language, which requires users to introduce RequireJS to use it. Nodejs is not supported. Browser is supported. This solution supports CommonJS, CommonJs2, AMD, and can be used in browsers and Nodes. Does it determine which environment it belongs to based on the context in which the plug-in is referenced, making it compatible with CommonJS, AMD, or exposing it as a global variable

The script/webpack base. Config. Js loader is pumped from the files here convenient management and configuration

const path = require('path'); function resolve(relatedPath) { return path.join(__dirname, relatedPath) } const webpackConfigBase = { resolve: {alias: {"@": resolve(" SRC ")}, // Extensions: [".js", ".jsx", ".json"], // mainFiles: ["index"]}, //module module: {rules: [{test:], //module module: {rules: [{test:] /\.js[x]?$/, // exclude: /node_modules/, use: {loader: 'babel-loader', options: { presets: ['@babel/preset-react'], } } }, { test: /\.less$/, use: [ 'style-loader', { loader: 'css-loader', options: ImportLoaders: 1, modules: {localIdentName: "[name]__[local]___[hash:base64:5]",}}}, {loader: importLoaders: 1, Modules: {localIdentName: "[name]__[local]___[hash:base64:5]",}}}, {loader: 'less-loader', options: { javascriptEnabled: true, } } ], }, { test: /\.css$/, use: [ 'style-loader', 'css-loader', { loader: 'postcss-loader', options: { ident: 'postcss', plugins: (loader) => [ require('autoprefixer')() ], } } ] } ] } } module.exports = webpackConfigBase;Copy the code

.babelrc Configures antD on demand

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": [
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-proposal-object-rest-spread",
      ["import", {"libraryName": "antd", "libraryDirectory": "lib", "style":"css"
      }],
  ]
}
Copy the code

.gitignore adds files that don’t need push

.DS_Store
dist
node_modules
*.log
Copy the code

.npmignore Is used to ignore files that do not need to be published to NPM

.babelrc
src
CODE_OF_CONDUCT.md
node_modules
.gitignore
webpack.config.js
yarn.lock
.eslintrc
Copy the code

Step 2 Add the configuration

2.1 Configuring Git and NPM

Add the following command to the initialized package.json file

 "scripts": {
    "build": "webpack --config ./scripts/webpack.prod.config.js",
    "dev": "webpack-dev-server --config ./scripts/webpack.dev.config.js",
	"prepublish": "npm run build"
 },
 // "files": [
 //   "lib"
 // ],
Copy the code
  • Build will run the webpack.prod.config.js file in the scripts directory to transcode the content in the SRC directory and export it to webPack’s pre-configured package directory. You need to set the entry SRC /index.js in the webpack.prod.config.js file.
  • NPM will execute this script before we run NPM publish. This will ensure that our resources in DIST are up to date.
  • The value of the “files” property is an array of file names or folders under the module. You can also create a “.npmignore” file in the root directory of the module. Files written inside this file are excluded even if they are written inside the files property, like “.gitignore” ***(I don’t use it)***

2.2 Installation Dependencies

< span style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; word-break: inherit! Important;" "^ 7.2.3 @", "Babel/plugin - proposal - object - the rest - spread" : "^ 7.2.0", "@ Babel/preset - env" : "^ 7.10.4", "@ Babel/preset - react" : "^ 7.10.4 Babel - plugin -", "import" : "^ 1.13.3", "@ hot - loader/react - dom" : "^ 16.13.0", "autoprefixer" : "^ 9.8.4", "Babel - loader" : "^ 8.1.0", "the clean - webpack - plugin" : "^ 3.0.0", "CSS - loader" : "^ 3.6.0", "HTML - webpack - plugin" : "^ 4.3.0", "optimize - CSS - assets - webpack - plugin" : "^ 5.0.3", "postcss - loader" : "^ 3.0.0", "style - loader" : "^ 1.2.1 terser - webpack -", "plugins" : "^ 3.0.6", "less" : "^ 3.10.2", "less - loader" : "^ 5.0.0", "webpack" : "^ 4.43.0 webpack -", "cli" : "^ 3.3.12", "webpack - dev - server" : "^ 3.11.0", "webpack - merge" : "^ 5.0.9 webpack - node -", "externals" : "^ 2.5.0"}, "dependencies" : {" react ":" ^ 16.14.0 ", "the react - dom" : "^ 16.14.0", "antd" : "^ 4.15.1"}, "peerDependencies" : {" prop - types ":" ^ 15.7.2 ", "react" : "^ 16.14.0", "the react - dom" : "^ 16.14.0", "antd" : "^ 4.15.1"},Copy the code
  • The Dependencies field specifies the module on which the project runs. This type of dependency is typically a third-party library on which the project’s business logic runs.
  • DevDependencies specifies the modules needed for project development.
  • The dependencies declared in peerDependencies will not be installed automatically if the project does not have explicit dependencies installed. Instead, NPM will issue warning logs telling the project developer that you need explicit dependencies and that you need to stop relying on me.

2.3 Adding Components

Create a SRC/Components directory and add button.js and button. CSS file button.js in sequence

import React, { useState } from "react"; import { Button } from 'antd' import styles from './button.less; import 'antd/dist/antd.less'; const Index = (props) => { const [btnTxt, setBtnTxt] = useState("Login"); return ( <React.Fragment> <div className={styles.btn} onClick={() => { setBtnTxt(btnTxt === "Login" ? "Logout" : "Login"); }} > < span > {btnTxt} < / span > < / div > < Button type = {} "primary" onClick = {() = > console. The log (" finally came out ")} > hello happy see me < / Button > </React.Fragment> ); }; export default Index;Copy the code

button.less

.button-container {
  width: 100px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: aquamarine;
  border-radius: 5px;
}

.button-container:hover {
  cursor: pointer;
}

Copy the code

src/index.js

import MyButton from './button';

export default MyButton;
Copy the code

2.4 Starting a Project

Run NPM start to start the project,

The project started smoothly, first step local joint investigation

Step 3 Local debugging

Run PWD in the previous component library root to get the project address; Then, we need to use scaffolding locally or manually create a small application project; And run NPM link at the current project root.

Otherwise, you will encounter a Maximum Call Stack size exceeded error! Didn’t meet that when I didn’t say, manual embarrassment! NPM link [component library address] : sudo chown -r 501:20 “/Users/[user name]/.npm” : sudo chown -r 501:20 “/Users/[user name]/. Then you find your own component library in node_modules of your local project;

Here I changed the name of the component library while fixing the problem myself! Ignore small details! Note: there needs to be packaged under the.lib file index after went to the file, or in the following debugging complains can’t find this component library, see the next antd dependence and other there can be no just I didn’t find the corresponding solution After we can normal use as references to other components of our components!

Step 4 Upload NPM

Run the following command to publish the component to NPM

npm publish
Copy the code

Enter the NPM account password, remember to apply for one

Look very simple, operation of various problems frequently, as a note, welcome to exchange correction!