用git管理代码,先创建好远程库
然后git clone拷到本地库
使用pnpm
npm install pnpm -g
pnpm init创建package.js文件
得到 package.json 初始内容,然后把 package.json 中的 name 属性删掉,并且添加一个 "private": true 属性,因为它是不需要发布的。
{
"private": true,
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
配置 pnpm 的 monorepo 工作区
在这个仓库下,我打算建立多个模块,最基础的组件源码模块、examples示例模块,就可以采用 monorepo 架构。我们在仓库的根目录下创建一个 pnpm-workspace.yaml 文件,可以在 pnpm-workspace.yaml 配置文件中指定这个仓库中有多少个项目。
packages:
# packages/ 直接子目录中的所有包
- 'packages/*'
安装必要依赖
- 支持ts
- babel转换
- 自动更新,实时刷新页面效果
- 打包
pnpm install -w --save-dev @babel/core @babel/cli @babel/preset-env @babel/preset-typescript nodemon lite-server concurrently typescript
| 依赖包 | 作用 |
|---|---|
@babel/core | Babel 核心编译库 |
@babel/cli | Babel 命令行工具 |
@babel/preset-env | 智能转换至目标浏览器 ES |
@babel/preset-typescript | 支持 TS 转 JS |
nodemon | 监听文件变化重启任务 |
lite-server | 轻量静态服务器+自动刷新 |
concurrently | 并行执行多个命令 |
打包与babel
pnpm install rollup --save-dev -w
pnpm i -D -w @rollup/plugin-babel @rollup/plugin-node-resolve @rollup/plugin-typescript rollup-plugin-dts
Rollup 与其它工具的集成 | rollup.js 中文文档 | rollup.js中文网
因为采用monorepo架构,需要各个模块都配置一下rollup配置文件
组件源代码模块,该模块的要求是能实时更新,ts自动打包,并用babel转换为js,生成.d.ts类型声明文件
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import typescript from '@rollup/plugin-typescript';
import dts from 'rollup-plugin-dts';
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 主构建配置(生成 JS 和 .d.ts)
const config = {
input: 'src/index.ts', // 入口文件
output: {
file: 'dist/index.js', // 输出文件
format: 'esm' // 输出格式(ES Module)
},
plugins: [
resolve({
extensions: ['.ts', '.js']
}),
typescript({
tsconfig: path.resolve(__dirname, '../../tsconfig.json'),
outDir: 'dist',
declarationDir: 'dist',
outputToFilesystem: true,
}),
babel({
babelHelpers: 'bundled',
// 关键:指定根目录 .babelrc 绝对路径
configFile: path.resolve(__dirname, '../../.babelrc'),
})
]
};
// 单独生成 .d.ts 的配置(可选)
const dtsConfig = {
input: 'src/index.ts',
output: {
file: 'dist/index.d.ts',
format: 'esm'
},
plugins: [dts()]
};
export default [config, dtsConfig]
examples示例模块,该模块的要求是src有html、css、ts等示例代码,开发是能自动启动开发服务器,自动打包为浏览器能运行的格式,实时更新
在 examples 模块中安装必要的 Rollup 插件和工具:
pnpm add -D -w rollup-plugin-copy rollup-plugin-replace npm-run-all rollup-plugin-postcss @rollup/plugin-image
| 依赖包 | 作用 |
|---|---|
rollup-plugin-copy | 复制静态文件(HTML、CSS等) |
rollup-plugin-replace | 在 HTML 中替换 TS 引用为 JS |
rollup-plugin-postcss | 处理 CSS(提取、压缩、模块化) |
@rollup/plugin-image | 处理图片(Base64 或复制文件) |
npm-run-all | 控制执行顺序 |
// rollup.config.mjs
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import typescript from '@rollup/plugin-typescript';
import copy from 'rollup-plugin-copy';
import postcss from 'rollup-plugin-postcss';
import image from '@rollup/plugin-image';
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
input: 'src/index.ts', // 入口文件
output: {
dir: 'dist',
format: 'esm', // 输出格式(ES Module)
sourcemap: true, // 生成 SourceMap
},
plugins: [
resolve(),
typescript(),
babel({
babelHelpers: 'bundled',
// 关键:指定根目录 .babelrc 绝对路径
configFile: path.resolve(__dirname, '../../.babelrc'),
}),
postcss(),
image(),
// 复制html文件到dist目录
copy({
targets: [
{
src: 'src/**/*.html',
dest: 'dist',
// 替换html中的.ts引用为.js
transform: (content, filePath) => {
return Buffer.from(
content.toString()
.replace(/<script.*src="(.*)\.ts".*<\/script>/g, '<script type="module" src="$1.js"></script>')
);
}
},
{
src: 'src/**/*.{css,jpg,png}',
dest: 'dist',
}
],
flatten: false, // 禁止扁平化路径(关键!)
})
],
watch: { // 监听模式配置
include: 'src/**',
exclude: 'node_modules/**'
}
};
// package.json相关配置
"scripts": {
"build": "rollup -c rollup.config.mjs",
"watch": "rollup -c rollup.config.mjs --watch",
"serve": "lite-server --baseDir=dist",
"dev": "npm-run-all build --parallel watch serve"
},
解决html、css变化未更新复制dist问题
上面的配置解决了大部分问题,但还不够完美,rollup默认只会监听主文件及其依赖变化重新构建,作为静态文件的html、css变化不会触发rollup的复制插件执行
需要手动将html、css等需要监听的静态文件加入rollup的依赖图谱
安装 glob 文件匹配库
pnpm add -D globby -F examples
修改 Rollup 配置
import path from 'path';
import { globbySync } from 'globby';
export default {
plugins: [
// ...其他插件
{
name: 'watch-static-files',
async buildStart() {
// 批量获取所有 HTML/CSS 文件路径
const files = await globbySync([
'src/**/*.html',
'src/**/*.css',
'src/**/*.{jpg,png}' // 可选:监听图片变化
], { absolute: true });
// 将文件添加到 Rollup 监听列表
files.forEach(file => {
this.addWatchFile(file);
});
},
},
copy({
targets: [/* 同上 */],
hook: 'writeBundle',
watch: true,
})
],
};
monorepo架构常用命令
# 安装到根目录
pnpm add @vueapps/utils
# 安装包到指定模块(从公共仓库找)
pnpm add @my-monorepo/core --filter @my-monorepo/app
# 本地模块安装到其他模块
pnpm add @my-monorepo/core --workspace --filter @my-monorepo/app
# 构建 core 模块(若未自动构建)
pnpm --filter @my-monorepo/core run build
# 启动 app 模块
pnpm --filter @my-monorepo/app run dev
子模块已配置好,开发时只需要根目录启动即可
"scripts": {
"dev": "concurrently \"pnpm --filter testComponent run watch\" \"pnpm --filter examples run dev\""
},
pnpm dev
问题
使用CommonJS模块包报错问题
比如使用spark-md5组件,该组件已正确安装了,并且使用方式正确,但实际使用时,报:
Uncaught (in promise) TypeError: undefined is not a constructor
如果通过 import * as SparkMD5 from 'spark-md5' 导入,但库的实际导出方式与 TypeScript 预期不符,会导致 ArrayBuffer 未被正确挂载。
解决方式:确保 rollup.config.js 包含以下插件配置
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
export default {
plugins: [
resolve({
browser: true // 确保浏览器环境解析
}),
commonjs({
requireReturnsDefault: 'predefined', // 关键配置
dynamicRequireTargets: ['node_modules/spark-md5/*']
})
]
};