前两章已经将开发和测试环境搭建好了,并且也封装了基本的操作流程,总体来说在后续开发流程中已经足够方便,同时我们也感受到了混用ESM
和CJS
带来的麻烦,所以我们提前来将发布环境也搭建起来,看看发布后能不能正常在项目中使用。
这里我们将直接使用babel
来编译,不使用father
、rollup
等打包工具。
使用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
,会报如下错误:
这个错误很熟悉,又是说require不能引入ESM的问题,而且在报错内容中,还提醒我们使用dynamic import。前面分析过我们在CommonJS中是不能使用require的,我们打开编译后的文件看看:
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
,依然报错,我们再次打开编译出来的文件看看
可以看到babel将dynamic import给转成了require。查阅文档后发现,是因为这个插件造成的,所以我们直接将其禁用。
修改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
能够顺利运行
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可看到打印信息即引入成功
发布npm包
# 先在浏览器登录
npm login --registry https://registry.npmjs.org/
# 发布
npm publish --registry https://registry.npmjs.org/
复制代码
项目中应用npm包
pnpm install -w unified-md
复制代码
自此项目的开发环境、测试环境、发布都已经走通,总体还是比较流畅,接下来就可以开始正式开发代码了。