发布一个属于自己的 npm utils
库
前言
-
在做项目的时候,我们可能需要将自己封装的公共方法在别的项目中使用,一种方式是复制粘贴,但是如果一个项目有添加一些新的方法,两一个项目也想用,那么也需要复制新的方法。
-
问:那么,有木有什么方法可以让我们将多个项目之前的方法进行共用呢?
-
答:我们可以使用
npm
的方式进行管理这些工具函数,达到一份维护,多个项目之间共用,如果有新的方法进行发布的时候,只需要更新npm包的版本。
技术选型
-
TypesScript
-
Rollup
依赖
## rollup
npm install rollup -D
## 生成.d.ts
npm install rollup-plugin-dts -D
## 编译ts插件
npm install rollup-plugin-typescript2 -D
## path模块
npm install path -D
## fs模块
npm install path -D
## ts
npm install typescript -G
设计目标
- 实现命令式一键编译
文件查找工具
-
因为我们的文件可能有多个,现在约定目录结构如下
- src - index.ts - file1.ts - demo - index.ts
-
文件遵循上述约定,可以进行文件之前的嵌套,在使用文件夹的时候,必须使用index.ts做为结尾
添加编译脚本
# package.json
// 生成文件后 进行编译
// 如果不使用 bundleConfigAsCjs 则会报错
"scripts": {
"build": "node ./utils/getFile.js && rollup -c --bundleConfigAsCjs"
},
按照步骤创建
-
创建如下的文件结构
-
编辑内容
# index.ts export * from './string.format.ts'
# string.format.ts /** * @jsonParse 将json串解析为JSON对象 * @param str string 需要解析的JSON串 * @param initValue T 在解析失败时返回的初始值 默认为 {} * @returns */ export const jsonParse = <D, T>(str: string, initValue?: T): T | D | undefined => { try { return JSON.parse(str); } catch { return initValue; } };
-
-
执行
npm init -y
生成package.json
-
执行
tsconfig --init
生成tsconfig.ts
文件 -
修改
tsconfig.json
内module要为ESNext
-
修改
package.json
内的type
要为module
-
package.json
添加script
脚本"scripts": { "build": "node ./utils/getFile.js && rollup -c --bundleConfigAsCjs" },
-
创建文件处理工具函数
## utils_npm/utils/getFile.js import fs from "fs"; const findFile = async (filePath = "src") => { try { const data = await fs.readdirSync(`./${filePath}`); const result = []; for (let i = 0; i < data.length; i++) { const item = data[i]; const targetFilePath = `${filePath}/${item}`; // 如果式src/index.ts 直接跳过 if (targetFilePath === "src/index.ts") { continue; } // 如果式以.ts文件为结尾,则认为是文件 if (item.endsWith(".ts")) { result.push(targetFilePath); } else { // 否则就是文件夹 const r = await findFile(`${filePath}/${item}`); result.push(r); } } return result; } catch (err) { return []; } }; const filePath = await findFile(); let utilsFilePath = filePath.flat(Infinity); const writeFileData = `const utilsFilePath = ${JSON.stringify(utilsFilePath)};export default utilsFilePath `; // 写入文件 fs.writeFile("./utils/file.js", writeFileData, () => {});
-
rollup.config.js 配置
import path from "path"; import ts from "rollup-plugin-typescript2"; import dts from "rollup-plugin-dts"; import utilsFilePath from "./utils/file"; /** 将文件名称转成大写 */ const fileNameToLocaleUppercase = (fileName) => fileName.replace(/(\.\w{1})/g, ($1) => $1.slice(1).toLocaleUpperCase()); const config = utilsFilePath .map((item) => { // 根据获取到的文件,编译成指定文件的文件结构 const fileName = item.split("/").pop().replace(".ts", ""); const filePath = item .split("/") .slice(1, item.split("/").length - 1) .join("/") + (fileName === "index" ? "" : `/${fileName}`); return [ { input: item, output: [ { file: path.join(__dirname, `dist/es/${filePath}/index.js`), format: "es", }, { file: path.join(__dirname, `dist/cjs/${filePath}/index.js`), format: "cjs", }, { file: path.resolve(__dirname, `./dist/umd/${filePath}/index.js`), format: "umd", name: fileNameToLocaleUppercase(fileName), }, ], plugins: [ts()], }, { // 打包声明文件 index.d.ts input: item, output: { file: path.resolve(__dirname, `./dist/es/${filePath}/index.d.ts`), format: "es", }, plugins: [dts.default()], }, ]; }) // 生成全局的cjs es umd 格式的文件结构 .concat([ { input: "src/index.ts", output: [ { file: "./dist/es/index.es.js", format: "es", }, { file: "./dist/cjs/index.cjs.js", format: "cjs", }, { file: path.resolve(__dirname, "./dist/umd/index.umd.js"), format: "umd", name: "laodingtouUtils", }, ], plugins: [ts()], }, { //打包声明文件 input: "./src/index.ts", output: { file: path.resolve(__dirname, "./dist/es/index.d.ts"), format: "es", }, plugins: [dts.default()], }, ]) .flat(); export default config;
发布到npm
-
执行
npm run build
打包文件 -
将编译后的文件
dist
目录可以单独放到一个文件夹,因为发布后的npm包不需要我们没有压缩的文件, -
将我们开发目录下的
tsconfig.json
package.json
package.lock.json
也复制到新的文件夹,修改package.json
内的配置 -
添加如下配置
"main": "dist/cjs/index.cjs.js", "module": "dist/es/index.es.js", "browser": "dist/umd/index.js", "types": "dist/es/index.d.ts",
-
删除
package.json
内的type
字段。 -
将npm包源设置为开源 ,添加如下配置文件
"publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
-
添加git配置
"repository": { "type": "git", "url": "git+https://github.com/z2244713679/laodingtou.utils/tree/master" }, "homepage": "https://github.com/z2244713679/laodingtou.utils/tree/master",
-
执行
npm login
登录npm -
在新建的包文件下执行
npm run publish
进行发布
源码
发布包的 package.json
{
"name": "@laodingtou/utils",
"version": "0.1.1",
"description": "laodingtou Utils",
"main": "dist/cjs/index.cjs.js",
"module": "dist/es/index.es.js",
"browser": "dist/umd/index.js",
"types": "dist/es/index.d.ts",
"scripts": {
"build": "node ./utils/getFile.js && rollup -c --bundleConfigAsCjs"
},
"repository": {
"type": "git",
"url": "git+https://github.com/z2244713679/laodingtou.utils/tree/master"
},
"homepage": "https://github.com/z2244713679/laodingtou.utils/tree/master",
"keywords": [],
"author": "",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"license": "ISC",
"devDependencies": {
"fs": "0.0.1-security",
"path": "^0.12.7",
"rollup": "^3.28.0",
"rollup-plugin-dts": "^6.0.0",
"rollup-plugin-typescript2": "^0.35.0"
}
}
开发文件的 package.json
{
"name": "@laodingtou/utils",
"version": "1.0.0",
"description": "laodingtou Utils",
"type": "module",
"scripts": {
"build": "node ./utils/getFile.js && rollup -c --bundleConfigAsCjs"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"fs": "0.0.1-security",
"path": "^0.12.7",
"rollup": "^3.28.0",
"rollup-plugin-dts": "^6.0.0",
"rollup-plugin-typescript2": "^0.35.0"
}
}
rollup.config.js
import path from "path";
import ts from "rollup-plugin-typescript2";
import dts from "rollup-plugin-dts";
import utilsFilePath from "./utils/file";
/** 将文件名称转成大写 */
const fileNameToLocaleUppercase = (fileName) => fileName.replace(/(\.\w{1})/g, ($1) => $1.slice(1).toLocaleUpperCase());
const config = utilsFilePath
.map((item) => {
// 根据获取到的文件,编译成指定文件的文件结构
const fileName = item.split("/").pop().replace(".ts", "");
const filePath =
item
.split("/")
.slice(1, item.split("/").length - 1)
.join("/") + (fileName === "index" ? "" : `/${fileName}`);
return [
{
input: item,
output: [
{
file: path.join(__dirname, `dist/es/${filePath}/index.js`),
format: "es",
},
{
file: path.join(__dirname, `dist/cjs/${filePath}/index.js`),
format: "cjs",
},
{
file: path.resolve(__dirname, `./dist/umd/${filePath}/index.js`),
format: "umd",
name: fileNameToLocaleUppercase(fileName),
},
],
plugins: [ts()],
},
{
// 打包声明文件 index.d.ts
input: item,
output: {
file: path.resolve(__dirname, `./dist/es/${filePath}/index.d.ts`),
format: "es",
},
plugins: [dts.default()],
},
];
})
// 生成全局的cjs es umd 格式的文件结构
.concat([
{
input: "src/index.ts",
output: [
{
file: "./dist/es/index.es.js",
format: "es",
},
{
file: "./dist/cjs/index.cjs.js",
format: "cjs",
},
{
file: path.resolve(__dirname, "./dist/umd/index.umd.js"),
format: "umd",
name: "laodingtouUtils",
},
],
plugins: [ts()],
},
{
//打包声明文件
input: "./src/index.ts",
output: {
file: path.resolve(__dirname, "./dist/es/index.d.ts"),
format: "es",
},
plugins: [dts.default()],
},
])
.flat();
export default config;
tsconfig.json
{
"compilerOptions": {
"target": "es2016",
"module": "ESNext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}