Skip to content

Commit 4ac84a5

Browse files
committed
feat: support mf
1 parent 3eeafe1 commit 4ac84a5

20 files changed

+1990
-207
lines changed

examples/mf/build.config.mts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { defineConfig } from '@ice/pkg';
2+
import { PluginOptions } from '@ice/pkg-plugin-mf'
3+
4+
// https://pkg.ice.work/reference/config-list
5+
export default defineConfig({
6+
plugins: [
7+
['@ice/pkg-plugin-mf', {
8+
name: 'ice_pkg_mf',
9+
exposes: {
10+
'.': './src/index.ts',
11+
'./Counter': './src/Counter.tsx',
12+
},
13+
getPublicPath: 'return "http://localhost:4444/"',
14+
shared: {
15+
16+
}
17+
}],
18+
],
19+
bundle: {
20+
formats: ['mf'],
21+
externals: {
22+
23+
'react-dom': '[email protected]'
24+
}
25+
}
26+
});

examples/mf/package.json

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"name": "example-pkg-mf",
3+
"version": "0.0.0",
4+
"private": true,
5+
"files": [
6+
"esm",
7+
"cjs",
8+
"es2017",
9+
"dist",
10+
"build"
11+
],
12+
"exports": {
13+
".": {
14+
"es2017": {
15+
"types": "./es2017/index.d.ts",
16+
"default": "./es2017/index.js"
17+
},
18+
"default": {
19+
"types": "./esm/index.d.ts",
20+
"default": "./esm/index.js"
21+
}
22+
},
23+
"./*": "./*"
24+
},
25+
"sideEffects": [
26+
"dist/*",
27+
"*.scss",
28+
"*.less",
29+
"*.css"
30+
],
31+
"scripts": {
32+
"start": "ice-pkg start",
33+
"build": "ice-pkg build",
34+
"prepublishOnly": "npm run build",
35+
"vitest": "vitest",
36+
"jest": "jest"
37+
},
38+
"dependencies": {
39+
"@ice/jsx-runtime": "catalog:example",
40+
"@swc/helpers": "^0.5.15",
41+
"babel-runtime-jsx-plus": "^0.1.5",
42+
"core-js": "^3.38.1"
43+
},
44+
"devDependencies": {
45+
"@ice/pkg": "workspace:*",
46+
"@ice/pkg-plugin-jsx-plus": "workspace:*",
47+
"@ice/pkg-plugin-mf": "workspace:^",
48+
"@testing-library/jest-dom": "^5.16.5",
49+
"@testing-library/react": "^14.0.0",
50+
"@types/react": "^18.0.0",
51+
"@types/react-dom": "^18.0.0",
52+
"@types/testing-library__jest-dom": "^5.14.5",
53+
"identity-obj-proxy": "^3.0.0",
54+
"jest": "^29.0.0",
55+
"jest-environment-jsdom": "^29.0.0",
56+
"jsdom": "^21.1.0",
57+
"prop-types": "^15.8.1",
58+
"react": "^18.2.0",
59+
"react-dom": "^18.2.0",
60+
"sass": "catalog:",
61+
"sass-loader": "catalog:",
62+
"style-unit": "^3.0.4",
63+
"ts-jest": "^29.0.0",
64+
"vitest": "catalog:"
65+
},
66+
"peerDependencies": {
67+
"react": "^17 || ^18"
68+
},
69+
"publishConfig": {
70+
"access": "public"
71+
},
72+
"license": "MIT"
73+
}

examples/mf/src/Counter.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react';
2+
// import { useState } from 'react';
3+
4+
export default function Counter() {
5+
// const [count, setCount] = useState(0)
6+
7+
// return <div onClick={() => setCount(count + 1)}>{count}</div>
8+
return <div>Counter</div>;
9+
}

examples/mf/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function add(a: number, b: number) {
2+
return a + b;
3+
}

examples/mf/tsconfig.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"compilerOptions": {
3+
"module": "ESNext",
4+
"target": "ESNext",
5+
"jsx": "react",
6+
"moduleResolution": "node",
7+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
8+
"strict": true,
9+
"skipLibCheck": true,
10+
"paths": {
11+
"@/*": ["./src/*"],
12+
"example-pkg-react-component": ["./src"],
13+
"example-pkg-react-component/*": ["./src/*"]
14+
},
15+
"allowSyntheticDefaultImports": true
16+
},
17+
"include": ["src"]
18+
}

packages/pkg/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"@rollup/plugin-node-resolve": "^15.2.2",
4444
"@rollup/plugin-replace": "^6.0.0",
4545
"@rollup/pluginutils": "^5.0.5",
46+
"@rslib/core": "^0.9.1",
4647
"@swc/core": "1.7.40",
4748
"acorn": "^8.10.0",
4849
"autoprefixer": "^10.4.2",

packages/pkg/src/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ export const ALIAS_BUNDLE_FORMATS_MAP: Record<AliasBundleFormatString, StandardB
1818
esm: 'esm:es5',
1919
es2017: 'esm:es2017',
2020
cjs: 'cjs:es5',
21+
mf: 'mf:es5',
2122
};
2223

2324
export const NODE_FORMAT_MODULE = ['cjs', 'esm'] as const;
24-
export const ALL_FORMAT_MODULES = [...NODE_FORMAT_MODULE, 'umd'] as const;
25+
export const ALL_FORMAT_MODULES = [...NODE_FORMAT_MODULE, 'umd', 'mf'] as const;
2526
export const ALL_FORMAT_TARGET = ['es5', 'es2017', 'es2022'] as const;

packages/pkg/src/core/registerTasks.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ export function registerTasks(ctx: Context, customFormats: Record<string, Custom
5353

5454
if (groupedFormats.alias?.length) {
5555
const formats = groupedFormats.alias as AliasBundleFormatString[];
56-
const aliasedFormatsGroup = groupBy(formats, (format) => (format === 'es2017' ? 'es2017' : 'es5'));
56+
const aliasedFormatsGroup = groupBy(formats, (format) =>
57+
format === 'mf' ? 'mf' : format === 'es2017' ? 'es2017' : 'es5',
58+
);
5759
const es5Formats = aliasedFormatsGroup.es5 as Array<Exclude<AliasBundleFormatString, 'es2017'>> | undefined;
5860

5961
if (es5Formats?.length) {
@@ -70,6 +72,14 @@ export function registerTasks(ctx: Context, customFormats: Record<string, Custom
7072
formats: es5Formats.map((module) => createFormat(module, 'es2017')),
7173
});
7274
}
75+
76+
if (aliasedFormatsGroup.mf?.length) {
77+
registerTask(`bundle-mf`, {
78+
type: 'bundle',
79+
formats: [createFormat('mf', 'es5')],
80+
engine: 'rslib',
81+
});
82+
}
7383
}
7484

7585
for (const format of groupedFormats.custom ?? []) {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Context, TaskRunnerContext } from '../../types';
2+
import { RslibConfig } from '@rslib/core';
3+
import { merge } from 'es-toolkit/object';
4+
5+
export function getRslibConfig(context: Context, taskRunnerContext: TaskRunnerContext): RslibConfig {
6+
const taskConfig = taskRunnerContext.buildTask.config;
7+
// const { pkg } = context
8+
let rslibConfig: RslibConfig = {
9+
source: {
10+
// TODO
11+
entry: {
12+
index: './src/index.ts',
13+
},
14+
},
15+
lib: [],
16+
output: {},
17+
performance: {
18+
printFileSize: false,
19+
},
20+
tools: {
21+
rspack: {
22+
stats: false,
23+
},
24+
},
25+
};
26+
if (taskConfig.type === 'bundle') {
27+
taskConfig.formats.map((fmt) => {
28+
rslibConfig.lib.push({
29+
bundle: true,
30+
format: fmt.module,
31+
syntax: fmt.target,
32+
outBase: taskConfig.outputDir,
33+
umdName: taskConfig.name,
34+
autoExternal: false,
35+
output: {
36+
externals: taskConfig.externals,
37+
},
38+
});
39+
});
40+
merge<RslibConfig, Partial<RslibConfig>>(rslibConfig, {
41+
output: {
42+
externals: taskConfig.externals,
43+
},
44+
});
45+
} else if (taskConfig.type === 'transform') {
46+
// TODO
47+
} else {
48+
throw new Error(`Cannot create rslib config of type ${taskConfig.type}`);
49+
}
50+
51+
if (taskConfig.modifyRslibConfig) {
52+
rslibConfig = taskConfig.modifyRslibConfig?.reduce((config, modifier) => modifier(config), rslibConfig);
53+
}
54+
55+
return rslibConfig;
56+
}

packages/pkg/src/helpers/getRollupOptions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ const BUILTIN_EXTERNAL_MAP: Record<string, string[]> = {
216216
'builtin:node': builtinNodeModules,
217217
};
218218

219-
function getExternalsAndGlobals(
219+
export function getExternalsAndGlobals(
220220
bundleTaskConfig: BundleTaskConfig,
221221
pkg: PkgJson,
222222
): [(id?: string) => boolean, Record<string, string>] {

packages/pkg/src/tasks/bundle.ts

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as rollup from 'rollup';
33
import { Watcher } from 'rollup/dist/shared/watch.js';
44
import { toArray } from '../utils.js';
55
import EventEmitter from 'node:events';
6-
import type { OutputFile, OutputResult, TaskRunnerContext, WatchChangedFile } from '../types.js';
6+
import type { EngineType, OutputFile, OutputResult, TaskRunnerContext, WatchChangedFile } from '../types.js';
77
import type {
88
OutputChunk as RollupOutputChunk,
99
OutputAsset as RollupOutputAsset,
@@ -17,23 +17,81 @@ import type {
1717
import type { FSWatcher } from 'chokidar';
1818
import { getRollupOptions } from '../helpers/getRollupOptions.js';
1919
import { Runner } from '../helpers/runner.js';
20+
import { RslibConfig, build as buildRslib, Rspack, logger, rsbuild } from '@rslib/core';
21+
import { getRslibConfig } from '../engine/rslib/config.js';
22+
import { noop } from 'es-toolkit';
2023

2124
export function createBundleTask(taskRunningContext: TaskRunnerContext) {
2225
return new BundleRunner(taskRunningContext);
2326
}
2427

28+
// Hack: disable all logger
29+
logger.override({
30+
ready: noop,
31+
info: noop,
32+
warn: noop,
33+
error: noop,
34+
debug: noop,
35+
success: noop,
36+
log: noop,
37+
});
38+
39+
rsbuild.logger.override({
40+
ready: noop,
41+
info: noop,
42+
warn: noop,
43+
error: noop,
44+
debug: noop,
45+
success: noop,
46+
log: noop,
47+
});
48+
2549
export class BundleRunner extends Runner<OutputResult> {
26-
private rollupOptions: RollupOptions;
50+
private options: RollupOptions | RslibConfig;
51+
private engine: EngineType;
2752
private watcher: Watcher | null = null;
2853
private result: Error | OutputResult | null;
2954
private readonly executors = [];
3055
constructor(taskRunningContext: TaskRunnerContext) {
3156
super(taskRunningContext);
32-
this.rollupOptions = getRollupOptions(taskRunningContext.buildContext, taskRunningContext);
57+
this.engine = taskRunningContext.buildTask.config.engine ?? 'rslib';
58+
switch (this.engine) {
59+
case 'rollup': {
60+
this.options = getRollupOptions(taskRunningContext.buildContext, taskRunningContext);
61+
break;
62+
}
63+
case 'rslib': {
64+
this.options = getRslibConfig(taskRunningContext.buildContext, taskRunningContext);
65+
break;
66+
}
67+
}
3368
}
3469

3570
async doRun(changedFiles: WatchChangedFile[]): Promise<OutputResult> {
36-
const { rollupOptions, context } = this;
71+
switch (this.engine) {
72+
case 'rollup':
73+
return this.handleRollupBuild(changedFiles);
74+
case 'rslib':
75+
return this.handleRslibBuild(changedFiles);
76+
}
77+
}
78+
79+
private getOutputResult(): Promise<OutputResult> {
80+
const { result, executors } = this;
81+
if (result instanceof Error) {
82+
return Promise.reject(result);
83+
} else if (result) {
84+
return Promise.resolve(result);
85+
} else {
86+
return new Promise((resolve, reject) => {
87+
executors.push([resolve, reject]);
88+
});
89+
}
90+
}
91+
92+
private async handleRollupBuild(changedFiles: WatchChangedFile[]): Promise<OutputResult> {
93+
const { context } = this;
94+
const rollupOptions = this.options as RollupOptions;
3795
if (context.watcher) {
3896
if (this.watcher) {
3997
for (const file of changedFiles) {
@@ -90,17 +148,20 @@ export class BundleRunner extends Runner<OutputResult> {
90148
return rawBuild(rollupOptions, context);
91149
}
92150

93-
private getOutputResult(): Promise<OutputResult> {
94-
const { result, executors } = this;
95-
if (result instanceof Error) {
96-
return Promise.reject(result);
97-
} else if (result) {
98-
return Promise.resolve(result);
99-
} else {
100-
return new Promise((resolve, reject) => {
101-
executors.push([resolve, reject]);
102-
});
103-
}
151+
private async handleRslibBuild(changedFiles: WatchChangedFile[]): Promise<OutputResult> {
152+
const { context } = this;
153+
const rslibConfig = this.options as RslibConfig;
154+
const instance = await buildRslib(rslibConfig, {});
155+
156+
// TODO
157+
const stats: Rspack.StatsCompilation = instance.stats?.toJson(true);
158+
159+
return {
160+
taskName: context.buildTask.name,
161+
modules: stats.modules,
162+
outputs: stats.chunks,
163+
outputFiles: stats.assets,
164+
};
104165
}
105166
}
106167

0 commit comments

Comments
 (0)