Skip to content

feat: support mf #680

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions examples/mf/build.config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { defineConfig } from '@ice/pkg';
import { PluginOptions } from '@ice/pkg-plugin-mf'

// https://pkg.ice.work/reference/config-list
export default defineConfig({
plugins: [
['@ice/pkg-plugin-mf', {
name: 'ice_pkg_mf',
exposes: {
'.': './src/index.ts',
'./Counter': './src/Counter.tsx',
},
getPublicPath: 'return "http://localhost:4444/"',
shared: {

}
}],
],
bundle: {
formats: ['mf'],
externals: {
react: '[email protected]',
'react-dom': '[email protected]'
}
}
});
73 changes: 73 additions & 0 deletions examples/mf/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"name": "example-pkg-mf",
"version": "0.0.0",
"private": true,
"files": [
"esm",
"cjs",
"es2017",
"dist",
"build"
],
"exports": {
".": {
"es2017": {
"types": "./es2017/index.d.ts",
"default": "./es2017/index.js"
},
"default": {
"types": "./esm/index.d.ts",
"default": "./esm/index.js"
}
},
"./*": "./*"
},
"sideEffects": [
"dist/*",
"*.scss",
"*.less",
"*.css"
],
"scripts": {
"start": "ice-pkg start",
"build": "ice-pkg build",
"prepublishOnly": "npm run build",
"vitest": "vitest",
"jest": "jest"
},
"dependencies": {
"@ice/jsx-runtime": "catalog:example",
"@swc/helpers": "^0.5.15",
"babel-runtime-jsx-plus": "^0.1.5",
"core-js": "^3.38.1"
},
"devDependencies": {
"@ice/pkg": "workspace:*",
"@ice/pkg-plugin-jsx-plus": "workspace:*",
"@ice/pkg-plugin-mf": "workspace:^",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/testing-library__jest-dom": "^5.14.5",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.0.0",
"jest-environment-jsdom": "^29.0.0",
"jsdom": "^21.1.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"sass": "catalog:",
"sass-loader": "catalog:",
"style-unit": "^3.0.4",
"ts-jest": "^29.0.0",
"vitest": "catalog:"
},
"peerDependencies": {
"react": "^17 || ^18"
},
"publishConfig": {
"access": "public"
},
"license": "MIT"
}
9 changes: 9 additions & 0 deletions examples/mf/src/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
// import { useState } from 'react';

export default function Counter() {
// const [count, setCount] = useState(0)

// return <div onClick={() => setCount(count + 1)}>{count}</div>
return <div>Counter</div>;
}
3 changes: 3 additions & 0 deletions examples/mf/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function add(a: number, b: number) {
return a + b;
}
18 changes: 18 additions & 0 deletions examples/mf/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
"jsx": "react",
"moduleResolution": "node",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"strict": true,
"skipLibCheck": true,
"paths": {
"@/*": ["./src/*"],
"example-pkg-react-component": ["./src"],
"example-pkg-react-component/*": ["./src/*"]
},
"allowSyntheticDefaultImports": true
},
"include": ["src"]
}
1 change: 1 addition & 0 deletions packages/pkg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@rollup/plugin-node-resolve": "^15.2.2",
"@rollup/plugin-replace": "^6.0.0",
"@rollup/pluginutils": "^5.0.5",
"@rslib/core": "^0.9.1",
"@swc/core": "1.7.40",
"acorn": "^8.10.0",
"autoprefixer": "^10.4.2",
Expand Down
3 changes: 2 additions & 1 deletion packages/pkg/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ export const ALIAS_BUNDLE_FORMATS_MAP: Record<AliasBundleFormatString, StandardB
esm: 'esm:es5',
es2017: 'esm:es2017',
cjs: 'cjs:es5',
mf: 'mf:es5',
};

export const NODE_FORMAT_MODULE = ['cjs', 'esm'] as const;
export const ALL_FORMAT_MODULES = [...NODE_FORMAT_MODULE, 'umd'] as const;
export const ALL_FORMAT_MODULES = [...NODE_FORMAT_MODULE, 'umd', 'mf'] as const;
export const ALL_FORMAT_TARGET = ['es5', 'es2017', 'es2022'] as const;
12 changes: 11 additions & 1 deletion packages/pkg/src/core/registerTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export function registerTasks(ctx: Context, customFormats: Record<string, Custom

if (groupedFormats.alias?.length) {
const formats = groupedFormats.alias as AliasBundleFormatString[];
const aliasedFormatsGroup = groupBy(formats, (format) => (format === 'es2017' ? 'es2017' : 'es5'));
const aliasedFormatsGroup = groupBy(formats, (format) =>
format === 'mf' ? 'mf' : format === 'es2017' ? 'es2017' : 'es5',
);
const es5Formats = aliasedFormatsGroup.es5 as Array<Exclude<AliasBundleFormatString, 'es2017'>> | undefined;

if (es5Formats?.length) {
Expand All @@ -70,6 +72,14 @@ export function registerTasks(ctx: Context, customFormats: Record<string, Custom
formats: es5Formats.map((module) => createFormat(module, 'es2017')),
});
}

if (aliasedFormatsGroup.mf?.length) {
registerTask(`bundle-mf`, {
type: 'bundle',
formats: [createFormat('mf', 'es5')],
engine: 'rslib',
});
}
}

for (const format of groupedFormats.custom ?? []) {
Expand Down
56 changes: 56 additions & 0 deletions packages/pkg/src/engine/rslib/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Context, TaskRunnerContext } from '../../types';
import { RslibConfig } from '@rslib/core';
import { merge } from 'es-toolkit/object';

export function getRslibConfig(context: Context, taskRunnerContext: TaskRunnerContext): RslibConfig {
const taskConfig = taskRunnerContext.buildTask.config;
// const { pkg } = context
let rslibConfig: RslibConfig = {
source: {
// TODO
entry: {
index: './src/index.ts',
},
},
lib: [],
output: {},
performance: {
printFileSize: false,
},
tools: {
rspack: {
stats: false,
},
},
};
if (taskConfig.type === 'bundle') {
taskConfig.formats.map((fmt) => {
rslibConfig.lib.push({
bundle: true,
format: fmt.module,
syntax: fmt.target,
outBase: taskConfig.outputDir,
umdName: taskConfig.name,
autoExternal: false,
output: {
externals: taskConfig.externals,
},
});
});
merge<RslibConfig, Partial<RslibConfig>>(rslibConfig, {
output: {
externals: taskConfig.externals,
},
});
} else if (taskConfig.type === 'transform') {
// TODO
} else {
throw new Error(`Cannot create rslib config of type ${taskConfig.type}`);
}

if (taskConfig.modifyRslibConfig) {
rslibConfig = taskConfig.modifyRslibConfig?.reduce((config, modifier) => modifier(config), rslibConfig);
}

return rslibConfig;
}
2 changes: 1 addition & 1 deletion packages/pkg/src/helpers/getRollupOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ const BUILTIN_EXTERNAL_MAP: Record<string, string[]> = {
'builtin:node': builtinNodeModules,
};

function getExternalsAndGlobals(
export function getExternalsAndGlobals(
bundleTaskConfig: BundleTaskConfig,
pkg: PkgJson,
): [(id?: string) => boolean, Record<string, string>] {
Expand Down
91 changes: 76 additions & 15 deletions packages/pkg/src/tasks/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as rollup from 'rollup';
import { Watcher } from 'rollup/dist/shared/watch.js';
import { toArray } from '../utils.js';
import EventEmitter from 'node:events';
import type { OutputFile, OutputResult, TaskRunnerContext, WatchChangedFile } from '../types.js';
import type { EngineType, OutputFile, OutputResult, TaskRunnerContext, WatchChangedFile } from '../types.js';
import type {
OutputChunk as RollupOutputChunk,
OutputAsset as RollupOutputAsset,
Expand All @@ -17,23 +17,81 @@ import type {
import type { FSWatcher } from 'chokidar';
import { getRollupOptions } from '../helpers/getRollupOptions.js';
import { Runner } from '../helpers/runner.js';
import { RslibConfig, build as buildRslib, Rspack, logger, rsbuild } from '@rslib/core';
import { getRslibConfig } from '../engine/rslib/config.js';
import { noop } from 'es-toolkit';

export function createBundleTask(taskRunningContext: TaskRunnerContext) {
return new BundleRunner(taskRunningContext);
}

// Hack: disable all logger
logger.override({
ready: noop,
info: noop,
warn: noop,
error: noop,
debug: noop,
success: noop,
log: noop,
});

rsbuild.logger.override({
ready: noop,
info: noop,
warn: noop,
error: noop,
debug: noop,
success: noop,
log: noop,
});

export class BundleRunner extends Runner<OutputResult> {
private rollupOptions: RollupOptions;
private options: RollupOptions | RslibConfig;
private engine: EngineType;
private watcher: Watcher | null = null;
private result: Error | OutputResult | null;
private readonly executors = [];
constructor(taskRunningContext: TaskRunnerContext) {
super(taskRunningContext);
this.rollupOptions = getRollupOptions(taskRunningContext.buildContext, taskRunningContext);
this.engine = taskRunningContext.buildTask.config.engine ?? 'rslib';
switch (this.engine) {
case 'rollup': {
this.options = getRollupOptions(taskRunningContext.buildContext, taskRunningContext);
break;
}
case 'rslib': {
this.options = getRslibConfig(taskRunningContext.buildContext, taskRunningContext);
break;
}
}
}

async doRun(changedFiles: WatchChangedFile[]): Promise<OutputResult> {
const { rollupOptions, context } = this;
switch (this.engine) {
case 'rollup':
return this.handleRollupBuild(changedFiles);
case 'rslib':
return this.handleRslibBuild(changedFiles);
}
}

private getOutputResult(): Promise<OutputResult> {
const { result, executors } = this;
if (result instanceof Error) {
return Promise.reject(result);
} else if (result) {
return Promise.resolve(result);
} else {
return new Promise((resolve, reject) => {
executors.push([resolve, reject]);
});
}
}

private async handleRollupBuild(changedFiles: WatchChangedFile[]): Promise<OutputResult> {
const { context } = this;
const rollupOptions = this.options as RollupOptions;
if (context.watcher) {
if (this.watcher) {
for (const file of changedFiles) {
Expand Down Expand Up @@ -90,17 +148,20 @@ export class BundleRunner extends Runner<OutputResult> {
return rawBuild(rollupOptions, context);
}

private getOutputResult(): Promise<OutputResult> {
const { result, executors } = this;
if (result instanceof Error) {
return Promise.reject(result);
} else if (result) {
return Promise.resolve(result);
} else {
return new Promise((resolve, reject) => {
executors.push([resolve, reject]);
});
}
private async handleRslibBuild(changedFiles: WatchChangedFile[]): Promise<OutputResult> {
const { context } = this;
const rslibConfig = this.options as RslibConfig;
const instance = await buildRslib(rslibConfig, {});

// TODO
const stats: Rspack.StatsCompilation = instance.stats?.toJson(true);

return {
taskName: context.buildTask.name,
modules: stats.modules,
outputs: stats.chunks,
outputFiles: stats.assets,
};
}
}

Expand Down
Loading
Loading