background
Recently, when WRITING the business of the company, I found that there are some reusable modules in each project, such as verification, environmental judgment and so on. Every time I start a new project, I have to copy a copy of the code. If some methods need to be updated, it is even more troublesome
Set up the project
The selection
Choose WebPack + TS, of course you can choose other packaging tools such as Glup, Grunt, Rollup, etc
The directory structure
Util ├ ─ ─ the SRC │ ├ ─ ─ env │ │ └ ─ ─ but ts │ └ ─ ─ valid │ └ ─ ─ but ts ├ ─ ─ tsconfig. Json ├ ─ ─ webpack. Config. Js ├ ─ ─ package.jsonCopy the code
Begin
Install dependencies and configuration commands
"scripts": {
"build": "rimraf lib && webpack"
},
"devDependencies": {
"typescript": "^ 4.2.2." ".// A substitute for ts-loader
"awesome-typescript-loader": "^ 5.2.1." ".// Webpack configures the import/export file line pipe
"fs": "^ 0.0.1 ws-security"."glob": "^ 7.1.6." "."path": "^ 0.12.7".// Delete old packaging files before packaging
"rimraf": "^ 3.0.2." ".// webpack
"webpack": "4"."webpack-cli": "^ 4.5.0." "
// Compress the package
"uglifyjs-webpack-plugin": "^ 2.2.0." ",}Copy the code
Write utility functions
src/valid/index.ts
/ * * *@desc Verify whether the domestic mobile phone number is legitimate *@param {String} PhoneNum Mobile phone number *@return {Boolean}* /
const validatePhoneNum = (phoneNum: string): boolean= > {
const reg = / [0-9] {10} ^ 1 $/;
return reg.test(phoneNum);
};
export default {
validatePhoneNum,
};
Copy the code
Webpack configuration
webpack.config.js
const { CheckerPlugin } = require("awesome-typescript-loader");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const path = require("path");
const glob = require("glob");
const fs = require("fs");
const ENTRY_REG = path.join(__dirname, "./src/*/**/index.ts");
let entries = {}; / / entrance
glob.sync(ENTRY_REG).forEach((entry) = > {
const catalogue = path.dirname(entry); // util/valid/index.ts => util/valid
const fileName = catalogue.split("/").pop(); // util/valid => valid
entries[fileName] = entry;
});
/* entries:{ valid: 'src/valid.index.ts' env: 'src/env/index.ts' } */
glob.sync(ENTRY_REG).forEach((item) = > console.log(item));
const WEBPACK_CONFIG = {
mode: "production".entry: {
...entries, / / entrance
},
output: {
path: path.resolve(__dirname, "./lib"), // Package directory
filename: "[name]/index.js".publicPath: "/".libraryTarget: "umd".// Compatible with ES and Node
umdNamedDefine: true.// libraryTarget uses umD, which must be set
globalObject: "this".// There are no Windows in compatible Nodes
},
// Currently we need to add '.ts' to the resolve.extensions array.
resolve: {
extensions: [".ts".".tsx".".js".".jsx"],},module: {
rules: [{test: /\.ts$/,
loader: "awesome-typescript-loader",}]},plugins: [new CheckerPlugin()],
/ / compression
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
compress: false.mangle: true.output: {
comments: false,}},sourceMap: false,})]},devtool: "hidden-source-map"};module.exports = WEBPACK_CONFIG;
Copy the code
In a WebPack configuration, the main focus is on the Output section
Tsconfig configuration
tsconfig.json
{
"compilerOptions": {
"outDir": "lib".// Output the file name
"module": "esnext"."target": "es6"."declaration": true.By default, index.d.ts is generated in the same directory as ts files
"moduleResolution": "node"."allowSyntheticDefaultImports": true."skipLibCheck": true
},
"include": ["src"]."exclude": []}Copy the code
Perform packaging
yarn build
The package generated directory is as follows
Util ├ ─ ─ lib │ ├ ─ ─ env │ │ ├ ─ ─ the index, which s │ │ └ ─ ─ index. The js │ └ ─ ─ valid │ ├ ─ ─ the index, which s │ └ ─ ─ index. The js ├ ─ ─ the SRC │ ├ ─ ─ env │ ├─ ├─ ├─ ├.txt ├─ ├.txt ├─ ├.txtCopy the code
test
import valid from ".. /lib/valid";
valid.validatePhoneNum("13999999999") // success
valid.validatePhoneNum(1) // error => validatePhoneNum: (phoneNum: string) => boolean
Copy the code
Unit testing
At this point, the library is ready to be referenced, but we need to make sure that the components/methods in the library are correct before we publish, and we will use JEST for unit testing
Introduction of depend on
yarn add jest @types/jest ts-jest -D
Copy the code
Add the configuration file jest. Config.js to the root directory
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
};
Copy the code
Write the test file __test__/valid.test.ts
import valid from ".. /src/valid"; test("valid 12345", () => { expect(valid.validatePhoneNum("12345")).toBe(false); }); test("valid 123123123", () => { expect(valid.validatePhoneNum("123123123")).toBe(false); }); test("valid 13429999999", () => { expect(valid.validatePhoneNum("13429999999")).toBe(true); });Copy the code
Run the test
yarn jest
Copy the code
release
Release build
package.json
{
"name": "util"."version": "0.1.0 from"."description": "v0.1.0"."main": "./lib/main".// It is also possible not to specify the main entry and let the user directly enter the entry of the subdirectory
"files": [
"lib"]."scripts": {
"build": "rimraf lib && webpack"
},
"author": "jensonliu"."license": "ISC"."devDependencies": {
"@types/jest": "^ 26.0.20"."awesome-typescript-loader": "^ 5.2.1." "."fs": "^ 0.0.1 ws-security"."glob": "^ 7.1.6." "."jest": "^ 26.6.3"."path": "^ 0.12.7"."rimraf": "^ 3.0.2." "."ts-jest": "^ 26.5.2"."typescript": "^ 4.2.2." "."uglifyjs-webpack-plugin": "^ 2.2.0." "."webpack": "4"."webpack-cli": "^ 4.5.0." "}}Copy the code
Note: To distinguish devDependencies from dependencies, when you install your NPM package, you will download the package in your dependencies. If you do not need to do this, put the package in devDependencies
Perform the build first
yarn build
Copy the code
And then publish it
npm login
npm publish
Copy the code
Packaged export type
The NPM package doesn’t have to be used in just one environment, it can be used in Both Nodes and browsers, so we need to generate multiple files for developers to import
If developers use WebPack, Webpack will be compatible with the conversion of various module modes, directly using esModule is also no problem
But sometimes we want to use the ESModule directly in the browser, and we need to provide an ESM file like index.esm.js
<script type="module">
import env from 'module/index.esm.js'
</script>
Copy the code
Also, we need to tell the developer webpack/rollup how to find the entry in node_modules, specified in package.json
"main": "lib/index.js"."module": "lib/index.esm.js".Copy the code
When importing NPM packages in node_modules using webpack, you first look for the corresponding entry for module in package.json of that package, and then for main if there is none
Esm -webpack-plugin: EsM -webpack-plugin: EsM -webpack-plugin: EsM -webpack-plugin: ESM
Rollup.config. js configuration file reference
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
import typescript from 'rollup-plugin-typescript2'
import pkg from './package.json'
export default [
// UMD for browser-friendly build
{
input: 'src/index.ts'.output: {
name: 'pkg-umd'.file: pkg.main,
format: 'umd',},plugins: [resolve(), commonjs(), typescript()],
},
{
input: 'src/index.ts'.output: {
name: 'pkg-esm'.file: pkg.module, // for es module like <script type="module"> import EventBus from './lib/index.esm.js'</script>
// or webpack , cause webpack will find npm package in module field
format: 'esm',},plugins: [typescript()],
},
]
Copy the code
Check out juejin.cn/post/684490…
Continuous integration
Speak it pretty full: www.cnblogs.com/gaobw/p/115…
Reference: github.com/liujiapeng/…
👉 github.com/liujiapeng/…