In business, many projects need to use the common component library, so we decided to package the component library and upload it to NPM private server management, using the technology of React + Webpack + TS + ANTD +less

1. File structure directory

| - @ lxy/demo. | - babelrc/configuration/Babel. | - gitignore | -- README. Md | -- package - lock. Json | -- package. Json | - Tsconfig. Json / / ts compiler configuration | -- yarn. The lock | - config / / webpack configuration file | | -- webpack. Dev. Config. Js | | -- webpack. Prod. Config. Js | - example/demo/test, run locally yarn start | | - app. Js / / start the entrance to the file | | - index. The HTML | | - | debugging source code TestDemo / / components - lib / / packaging output file | | - SRC / / component source code -- index. TSX / / component entry | - types | - components | - Tag | -- index. Less | -- index. The TSXCopy the code

2.package.json

The following important fields are highlighted for this file:

  • Name: indicates the name of the package uploaded to the NPM

  • Version: indicates the version number required for uploading

  • Main: the output JS path after packaging

  • Types: the d.ts path of packaged output

  • Files: files that need to be uploaded to NPM, here lib is the file I packaged output

  • PeerDependencies: I won’t talk too much about this field. Please refer to this article

    {
      "name": "@tech/components"."version": "0.0.1"."author": Risk Control Development Division."description": "Risk Control Development Department Component"."main": "lib/bundle.js"."types": "lib/index.d.ts"."files": [
        "lib"]."keywords": []."license": "ISC"."scripts": {
        "start": "webpack-dev-server --config ./config/webpack.dev.config.js"."build": "webpack --config ./config/webpack.prod.config.js"
      },
      "dependencies": {
        "@ant-design/icons": "^ 4.6.3." "."@ant-design/pro-form": "^ 1.42.0"."@ant-design/pro-layout": "^ 6.5.0"."@ant-design/pro-table": "^ 2.49.0"
      },
      "devDependencies": {
        "react": "^ 16.4.0"."react-dom": "^ 16.4.0"."antd": "^ 4.16.13"."webpack-dev-server": "^ 3.11.2"."html-webpack-plugin": "^ 4.5.1." "."mini-css-extract-plugin": "^ 2.4.4." "."webpack": "^ 5.18.0"."webpack-cli": "^" 3.3.12."webpack-node-externals": "1.6.0"."@babel/core": "^ 7.2.2." "."@babel/preset-env": 7.2.3 ""."@babel/preset-react": "7.0.0"."@types/react": "^ 17.0.0"."@types/react-dom": "^ 17.0.0"."babel-loader": "8.0.5"."babel-plugin-import": "^ 1.13.3"."css-loader": "0.28.9"."file-loader": "^ 6.2.0"."less": "^ 3.11.1." "."less-loader": "^ 5.0.0"."style-loader": "0.19.1"."ts-loader": "~ 8.2.0"."typescript": "^ 4.4.4." "."url-loader": "^ 4.4.1"
      },
      "peerDependencies": {
        "antd":"4.x"."react": "> = 16.9.0"."react-dom": "> = 16.9.0"}}Copy the code

3.. babelrc file configuration

{"presets": ["@babel/preset-env", "@babel/preset-react"], "plugins": [// ANTD style is loaded on demand ["import", {"libraryName": "antd", "style": true } ] ] }Copy the code

4. Configure the config file

The purpose of webpack.dev.config.js is to be able to preview while developing and respond to the effect in time

const path = require('path'); const htmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'development', entry: path.join(__dirname, ".. Output: {filename: 'bundle.js', path: path.join(__dirname, ".. /lib"), }, module: { rules: [ { test: /\.(ts|tsx)$/, use: [ { loader: 'ts-loader', } ], exclude: /node_modules/ }, { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }, { test: /\.css$/, use: ['style-loader', 'css-loader']}, {// Exclude: / SRC /, use: [ 'style-loader', { loader: 'css-loader', options: { importLoaders: 1, }, }, { loader: 'less-loader', options: {javascriptEnabled: true,},},],}, {// Handle CSS Modules in the project import styles from './index.less' test: /\.less$/, exclude: /node_modules/, use: [ 'style-loader', { loader: 'css-loader', options: { modules: { auto: true } } }, { loader: 'less-loader', options: { javascriptEnabled: true, }, }, ], }, { test: /\.svg$/, use: ['file-loader'] }, ] }, plugins: [ new htmlWebpackPlugin({ filename: "index.html", template: path.join(__dirname, "../example/index.html"), }) ], devServer: { contentBase: path.join(__dirname, '.. /lib'), compress: true, port: 3002, open: true}, resolve: { [".ts", ".tsx", ".js", ".jsx"] }, };Copy the code

webpack.prod.config.js

const path = require('path'); const nodeExternals = require('webpack-node-externals'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { mode: 'production', entry: path.join(__dirname, ".. /src/index.tsx"), output: { filename: 'bundle.js', path: path.resolve(__dirname, '.. /lib'), library: 'laputarednerer', libraryTarget: 'umd', }, module: { rules: [ { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }, { test: /\.(ts|tsx)$/, use: [ "babel-loader", { loader: 'ts-loader', } ], exclude: /node_modules/ }, { test: /\.css$/, use: [MiniCssExtractPlugin. Loader, 'CSS - loader]}, {/ / rule out CSS module for on-demand loaded antd impact test: / \. Less $/, exclude: /src/, use: [ 'style-loader', { loader: 'css-loader', options: { importLoaders: 1, }, }, { loader: 'less-loader', options: { javascriptEnabled: Import styles from './index.less' test: /\. Less $/, exclude: /\. /node_modules/, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { modules: { auto: true }, } }, { loader: 'less-loader', options: { javascriptEnabled: true, }, }, ], }, { test: /\.svg$/, use: ['url-loader'] }, ] }, plugins: [ new MiniCssExtractPlugin({ filename: 'style/[name].css', }), ], resolve: {/ / suffix auto-complete, can need not write when introducing suffix extensions: [", "benchmark" ts ", "js", "JSX", "less", "CSS"]}, externals: ['react', 'react-dom','antd',nodeExternals()] }Copy the code

5.tsconfig.js

{
  "compilerOptions": {
    "outDir": "./lib",
    "target": "ES2015",
    "module": "CommonJS",
    "esModuleInterop": true,
    "declaration": true,
    "jsx": "react",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
  },
  "include": [
    "src/**/*",
  ],
  "exclude": [
    "node_modules"
  ],
}
Copy the code

6. SRC Indicates the body content

SRC create index.ts

import Tag from "./components/Tag";
export { Tag };
Copy the code

SRC /components create a new Tag file: the content is based on your own business implementation, which is not written here

Externals.d. ts is added under SRC /types to handle the problem of undefined less files

declare module '*.less'
declare module '*.png';
declare module '*.svg' {
  export function ReactComponent(
    props: React.SVGProps<SVGSVGElement>,
  ): React.ReactElement;
  const url: string;
  export default url;
}
Copy the code

Note That the previous basic configurations are complete

  • Import styles1 from ‘./index.less’ to introduce less in this manner, style file as follows:

    .aa{
      color:red
    }
    Copy the code
  • Import ‘./index.less’ introduces less in this way, with the following style file:

    :global{
      .aa{
        color:red
      }
    }
    Copy the code

7. Example Preview file configuration

example/index.js

import React, { useState } from 'react'; import ReactDOM from 'react-dom'; import { Tag } from '.. /src/index'; Const Test = () = > {return (< div > < h1 > local Test component < / h1 > < Tag / > < / div >). }; ReactDOM.render(<Test />, document.getElementById("root"));Copy the code

example/index.html

<html> <head> <title>My Component Demo</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,  initial-scale=1, shrink-to-fit=no"> </head> <body> <noscript> You need to enable JavaScript to run this app. </noscript> <div id="root"></div> </body> </html>Copy the code