unified插件开发【仿dumi项目】- 发布环境搭建

前两章已经将开发和测试环境搭建好了,并且也封装了基本的操作流程,总体来说在后续开发流程中已经足够方便,同时我们也感受到了混用ESMCJS带来的麻烦,所以我们提前来将发布环境也搭建起来,看看发布后能不能正常在项目中使用。

这里我们将直接使用babel来编译,不使用fatherrollup等打包工具。

使用babel编译

由于我们的代码使用的是typescript,所以不能直接发布,我们得将代码编译成对node友好的格式以供别人使用。前面我们已经使用babel用于jest测试,所以我们可以直接使用babel将typescript打包成js。

现在我们要手动执行babel,所以先安装一下babel的命令行工具:

npm install --save-dev @babel/cli
复制代码

在package.json加上babel构建命令

"build": "babel src --out-dir lib --extensions .ts"
复制代码

运行npm run build即可看到/lib目录下已经有打包成js的文件了

创建验证文件

接下来我们创建个js文件看看能不能正常使用

// /index.js
const unifiedChain  = require('./lib/index')
console.log(unifiedChain)
复制代码

运行node ./index.js,会报如下错误: image.png

这个错误很熟悉,又是说require不能引入ESM的问题,而且在报错内容中,还提醒我们使用dynamic import。前面分析过我们在CommonJS中是不能使用require的,我们打开编译后的文件看看:

image.png

babel确实将ts的import语法转为了require,按照错误提示,我们将其改造成为动态引入的形式。

使用dynamic import加载esm

我们定义全局变量来存放加载后的导出函数,由于dynamic import返回的是Promise,所以使用时要等待包被加载完成:

// /src/core/UnifiedChain.ts
// import { unified } from 'unified';
// import remarkParse from 'remark-parse';
// import remarkStringify from 'remark-stringify';
// 引入类型
let unified: typeof import('unified').unified;
let remarkParse: typeof import('remark-parse').default;
let remarkStringify: typeof import('remark-stringify').default;
// 动态加载包
export async function loadPackages() {
    ({ unified } = await import('unified'));
    ({ default: remarkParse } = await import('remark-parse'));
    ({ default: remarkStringify } = await import('remark-stringify'));
};
复制代码
// /src/index.ts
import UnifiedChain, { loadPackages } from './core/UnifiedChain';
import remarkFootnote from './remark/remarkFootnote';

export default async function unifiedChain() {
    // 在调用前先确保包已被加载完成
    await loadPackages()
    return new UnifiedChain()
}
复制代码

更新测试代码

// /index.ts
import unifiedChain, { remarkFootnote } from "./src";
(async () => {
    const chain = await unifiedChain()
    const res = chain
        .parseMarkdown('# hello chain')
        .use(remarkFootnote)
        .toString()
    console.log(res)
})()
复制代码

运行测试后代码可以正常运行

再次编译

再次运行npm run build,更新测试代码

// /index.js
const unifiedChain = require('./lib').default;
console.log(unifiedChain())
复制代码

再次运行node ./index.js,依然报错,我们再次打开编译出来的文件看看

image.png

可以看到babel将dynamic import给转成了require。查阅文档后发现,是因为这个插件造成的,所以我们直接将其禁用。 image.png

修改babel配置文件,该插件对应的名称加入到exclude不使用

// babel.config.js
module.exports = {
    presets: [
      ['@babel/preset-env', {
        targets: {node: 'current'},
        // 这里将动态导入插件禁用
        exclude: ["transform-dynamic-import"]
      }],
      '@babel/preset-typescript',
    ],
};
复制代码

再次编译可以看到import没有被转成require了,运行node ./index.js能够顺利运行 image.png

link到本地dumi项目测试

在dumi项目中链接本地项目

pnpm link D:\project\unified-md
复制代码

将包引入项目,并改变导入方式

// D:\dumi\src\loaders\markdown\transformer.ts
// ...
import unifiedChain, { remarkFootnote } from 'unified-md/lib';
// ...

  const chain = await unifiedChain()
  const res = chain.parseMarkdown('# hello dumi')
    .use(remarkFootnote)
    .toString()
  console.log(res)

  const processor = await unifiedChain()
  processor
    .use(remarkParse)
    .use(remarkEmbed, { fileAbsPath: opts.fileAbsPath, alias: opts.alias })
    .use(remarkFrontmatter)
// ...
复制代码

运行dumi可看到打印信息即引入成功 image.png

发布npm包

# 先在浏览器登录
npm login --registry https://registry.npmjs.org/
# 发布
npm publish --registry https://registry.npmjs.org/
复制代码

项目中应用npm包

pnpm install -w unified-md
复制代码

自此项目的开发环境、测试环境、发布都已经走通,总体还是比较流畅,接下来就可以开始正式开发代码了。

分类:
前端