用ts重构基于rollup的npm包踩坑记录

前言

在之前实现了一个npm包 我的第一个npm包:plugin-zip-pack - 掘金 (juejin.cn)

但源码是js编写的,最近想的使用ts进行重构一下。 最开始直接将源码中原来文件都修改为 .ts后缀后遇到了一系列报错问题、以及打包后出现的报错问题,经过一步步踩坑,最终都成功解决。谨以此篇记录自己的学习的过程,也希望能帮助到其他同学。

npm包地址: plugin-zip-pack - npm (npmjs.com)

文档地址: silin001.github.io/docs/blogs/...

一、ts文件在vscode编辑器中报错问题

编辑器提示找不到 require

根据提示,安装 @types/node 可解决:pnpm i @types/node -D

.ts文件中提示无法重新声明块范围变量

由于之前js版本都是使用的CommonJS 语法, 在 util/index.ts 中声明一个变量使用 module.exports 导出变量:

js 复制代码
const sucess = chalk.green;
module.exports = {
  sucess,
// ...
}

index.ts 中 使用require 引入

js 复制代码
const { sucess } = require('./src/util/index')
// ...

原因: 因为直接修改了文件为 .ts , 当在 TypeScript 中遇到变量重新声明的问题时,通常是因为在不同的文件中重复定义了同一个变量名。

解决: 需要使用 TypeScript 的模块系统,也就是 import、export 的方式来导入导出ts文件中的模块,并避免在不同的文件中重复声明相同的变量名。使用 es6 规范导入导出后问题解决。

Did you mean to set the 'moduleResolution' option to 'nodenext', or to add aliases to the 'paths' option?

引入第三方依赖时报错:

根据提示在 tsconfig.jsoncompilerOptions 字段加入此配置后解决: "moduleResolution": "nodenext"

找不到模块"../package.json"。请考虑使用 "--resolveJsonModule" 导入带 ".json" 扩展的模块

在.ts文件中引入json文件,vscode报错:

解决: tsconfig.jsoncompilerOptions 字段加入如下配置后解决:

js 复制代码
"esModuleInterop": true,
"resolveJsonModule": true

二、rollup 打包遇到的报错

Error: Cannot find module 'typescript'

ps: 找不到模块"typescript"

报错原因: 源码工程中没有安装 ts

解决: 安装ts: pnpm i typescript -D

安装完ts还是不行,打包发现提示:

(plugin typescript) Error: @rollup/plugin-typescript: Could not find module 'tslib', which is required by this plugin. Is it installed?

然后根据提示安装 tslibpnpm i tslib -D

重新使用 rollup 打包成功解决:

Uncaught ReferenceError: require is not defined

Rollup 打包代码时,在代码中使用了CommonJS语法(如:使用了require),但 Rollup 默认使用ES6模块语法(如:import、export

报错原因:

而我这里是因为我的源码中用 require 引入了node环境的一些api,如:fs等。 然后用 Rollup工具打包后生成.js 在浏览器环境(html中script引入)中使用时,此时浏览器就会报这个错: require is not defined

requireCommonJS 规范中用于导入模块的关键字,而浏览器环境下是不认识 require的!

解决方案:

  • 在代码中使用ES6模块语法替换CommonJS语法

  • 在Rollup的配置文件中使用插件解决(例如 @rollup/plugin-commonjs),以便 Rollup 能够识别并正确处理CommonJS语法。

SyntaxError: Cannot use import statement outside a module

ps: SyntaxError:不能在模块外使用 import 语句

报错原因: 在js文件中是无法直接使用 import/export es6语法

解决方案:

  • package.json 中设置type字段 "type":"module"

  • 使用 .mjs 的扩展名(从 Node.js v13.2 版本开始,Node.js 已经默认打开了 ES6 模块支持。Node.js 要求 ES6 模块采用 .mjs 的后缀文件名)

Error [ERR_REQUIRE_ESM]: require() of ES Module

ps: 试图在 index.umd.js 文件中使用了 require() 引入了一个 ES 模块(ES Module),但在这种情况下是不被支持的;

要解决这个问题,你需要调整 xxx/index.umd.js 文件中的代码。

报错原因:

错误 [ERR_REQUIRE_ESM] 表示: require() 函数试图引入一个 ES 模块,但在这个文件的上下文环境中不被支持。

对应到我的这个npm包的源码中是因为我使用 require 引入了 chalk 依赖

解决:require 修改为 import 方式引入后解决

chalk 依赖库

查看 chalk 源码发现是使用 cjs 规范导出的。

Rollup 打包后的项目中,即使 chalk 包只导出了 CommonJS 规范(CJS),仍然需要使用动态 import 引入的主要原因是为了确保代码的兼容性和可靠性

Error: Cannot find module '../package.json'

源码中使用 require 引入package.json 文件后打包后报错

报错原因: 默认情况下rollup.js 不支持导入 json 模块, 无论是 require 还是 import 方式

解决方案:

  • 安装@rollup/plugin-json插件支持使用 import 导入json文件 pnpm i -D @rollup/plugin-json

  • 使用 node的 fs.readFileSync 读取文件

使用node模块的 resolve 获取真实的json文件的路径,然后使用fs模块的readFileSync方法读取文件内容,从而获取到json中name、version等内容。

js 复制代码
const { name, version } = getPackJson()
function getPackJson () {
  const pkg = {
    name: "",
    version: "",
  };
  // 使用 resolve 获取真实的json文件 path路径
  const packageJsonPath = resolve(__dirname, "package.json");
  try {
    // 读取文件内容
    const packageJsonString = fs.readFileSync(packageJsonPath, "utf8");
    const { name, version } = JSON.parse(packageJsonString);
    pkg.name = name;
    pkg.version = version;
  } catch (err) {
    console.error("无法读取npm包的 package.json 文件:", err);
  }
  console.log("pkg--", pkg);
  return pkg;
}

三、其他

rollup打包ts类型文件

使用pnpm i -D rollup-plugin-dts插件来生成ts类型文件

js 复制代码
import { dts } from "rollup-plugin-dts";

const config = [
  // ...
  {
    input: "./src/index.ts",
    output: [{ file: "build/index.d.ts", format: "es" }],
    plugins: [dts()],
  },
];
export default config;

配置完成后 当执行 rollup -c 时会根据配置文件自动打包到 build/index.d.ts

此时,使用es语法导入时就有了智能提示:

当错误使用导出的方法时也会有ts类型提示:

重构前 npm插件在vite中使用警告

使用ts编写源码,给导出的 vite函数 添加一个 type 类型来约束:

js 复制代码
/** 支持vite插件类型 */
export type VitePluginZipPackType = {
  name: string;
  apply: "build";
  closeBundle: () => void;
};

四、npm包发布相关

npm 发布时使用 opt码进行二次验证

由于我设置了npm二次验证,发布时需要输入在手机 Authenticator App 上输入 opt 验证码即可:

发布成功会有邮件通知:

npm login报错

原因: 使用了代理软件网络环境有问题、设置的proxy代理环境有问题,可能会有缓存

解决: 关闭代理软件后重新login尝试(可能需要多次尝试)、清除npm缓存

npm unpublish 删除已发布包的指定版本

npm login 登录后直接删除指定版本: npm unpublish 包名称@版本号

注意:

  • 不允许撤销发布已经超过 24 小时的包,撤销发布 24 小时内的包需要加 --force 参数
  • 撤销之前发布的包,再次发布的时候不能与之前被撤销的包的名称/版本其中之一相同,因为这两者构成的唯一性已经被占用,官方并没有随着撤销而删除

npm deprecate 弃用发布的包

npm unpublish 官方推荐的替代命令 npm deprecate

npm deprecate 包名称@版本号

npm deprecate 命令不会在 npm官网上撤销对应的包,而是会在使用安装该包时给出下面的提示信息:

If you no longer wish to maintain a package, or if you would like to encourage users to update to a new or different version, you can deprecate it. Deprecating a package or version will print a message to the terminal when a user installs it.

npm 发布新版本后使用时版本号不更新

npm包发布新的版本号后,在项目里直接 pnpm install 进行安装时可能暂时还是旧版本号,但是npm官网已经显示有了新版本号,这是因为刚发布的包可能还没更新好,需要等待一段时间(我是当天发布了新版本npm包,次日安装时版本号才自动更新最新的)重新安装查看

五、最终npm包使用

webpack.config.js

在.js配置文件中使用 es模块 import 时会报错: SyntaxError: Cannot use import statement outside a module

所以需要使用cjs模块导入: const { test, pluginZipPackVite } = require('plugin-zip-pack')

vite.config.ts

在.ts配置文件中可以使用时 es、cjs模块引入都支持:

import { test, pluginZipPackVite } from 'test-plugin-zip-pack'

or
const { test, pluginZipPackVite } = require('plugin-zip-pack')

相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
浪浪山小白兔6 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
limit for me7 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者7 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
qq_392794487 小时前
前端缓存策略:强缓存与协商缓存深度剖析
前端·缓存