diff --git a/.gitignore b/.gitignore index fc678b38..f28bff68 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ package-lock.json pnpm-lock.yaml /packages/**/node_modules +dist diff --git a/packages/inula-reactive/babel.config.js b/packages/inula-reactive/babel.config.cjs similarity index 100% rename from packages/inula-reactive/babel.config.js rename to packages/inula-reactive/babel.config.cjs diff --git a/packages/inula-reactive/bench/index.js b/packages/inula-reactive/bench/index.js new file mode 100644 index 00000000..dd54b97f --- /dev/null +++ b/packages/inula-reactive/bench/index.js @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * openInula is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +/** + * Extracted from: https://github.com/Riim/cellx#benchmark + */ +import chalk from 'chalk'; +import * as solid from './solid-reactive.js'; +import * as reactively from '@reactively/core'; +import Table from 'cli-table'; +import { reactive, computed } from '../dist/index.js'; + +const BATCHED = true; +const RUNS_PER_TIER = 150; +const LAYER_TIERS = [10, 100, 500, 1000, 2000]; + +const med = array => array.sort((a, b) => (a - b < 0 ? 1 : -1))[Math.floor(array.length / 2)] || 0; + +const SOLUTIONS = { + 10: [2, 4, -2, -3], + 100: [-2, -4, 2, 3], + 500: [-2, 1, -4, -4], + 1000: [-2, -4, 2, 3], + 2000: [-2, 1, -4, -4], + // 2500: [-2, -4, 2, 3], +}; + +/** + * @param {number} layers + * @param {number[]} answer + */ +const isSolution = (layers, answer) => answer.every((_, i) => SOLUTIONS[layers][i] === _); + +async function main() { + debugger + const report = {}; + // report.solid = { fn: runSolid, runs: [] }; + // report.reactively = { fn: runReactively, runs: [], avg: [] }; + report.inluaReactive = { fn: runInulaReactive, runs: [], avg: [] }; + // report.inluaDeepReactive = { fn: runInulaDeepReactive, runs: [], avg: [] }; + + for (const lib of Object.keys(report)) { + const current = report[lib]; + + for (let i = 0; i < LAYER_TIERS.length; i += 1) { + let layers = LAYER_TIERS[i]; + const runs = []; + + for (let j = 0; j < RUNS_PER_TIER; j += 1) { + runs.push(await start(current.fn, layers)); + } + // Give cellx time to release its global pendingCells array + await new Promise(resolve => setTimeout(resolve, 0)); + + current.runs[i] = med(runs) * 1000; + } + } + + const table = new Table({ + head: ['', ...LAYER_TIERS.map(n => chalk.bold(chalk.cyan(n)))], + }); + + for (let i = 0; i < LAYER_TIERS.length; i += 1) { + let min = Infinity, + max = -1, + fastestLib, + slowestLib; + + for (const lib of Object.keys(report)) { + const time = report[lib].runs[i]; + + if (time < min) { + min = time; + fastestLib = lib; + } + + if (time > max) { + max = time; + slowestLib = lib; + } + } + + report[fastestLib].runs[i] = chalk.green(report[fastestLib].runs[i].toFixed(2)); + report[slowestLib].runs[i] = chalk.red(report[slowestLib].runs[i].toFixed(2)); + } + + for (const lib of Object.keys(report)) { + table.push([chalk.magenta(lib), ...report[lib].runs.map(n => (typeof n === 'number' ? n.toFixed(2) : n))]); + } + + console.log(table.toString()); +} + +async function start(runner, layers) { + return new Promise(done => { + runner(layers, done); + }).catch(e => { + console.error(e.message); + }); +} + +function runInulaReactive(layers, done) { + const start = { + a: new reactive(1), + b: new reactive(2), + c: new reactive(3), + d: new reactive(4), + }; + + let layer = start; + + for (let i = layers; i--; ) { + layer = (m => { + return { + a: new computed(() => m.b.get()), + b: new computed(() => m.a.get() - m.c.get()), + c: new computed(() => m.b.get() + m.d.get()), + d: new computed(() => m.c.get()), + }; + })(layer); + } + + const startTime = performance.now(); + + start.a.set(4), start.b.set(3), start.c.set(2), start.d.set(1); + + const end = layer; + const solution = [end.a.get(), end.b.get(), end.c.get(), end.d.get()]; + const endTime = performance.now() - startTime; + + done(isSolution(layers, solution) ? endTime : -1); +} + + +function runInulaDeepReactive(layers, done) { + const start = { + a: new reactive({ v: 1 }), + b: new reactive({ v: 2 }), + c: new reactive({ v: 3 }), + d: new reactive({ v: 4 }), + }; + + let layer = start; + + for (let i = layers; i--; ) { + layer = (l => { + return { + a: new computed(() => ({ + v: l.b.v.get(), + })), + b: new computed(() => ({ + v: l.a.v.get() - l.c.v.get(), + })), + c: new computed(() => ({ + v: l.b.v.get() + l.d.v.get(), + })), + d: new computed(() => ({ + v: l.c.v.get(), + })), + }; + })(layer); + } + + const startTime = performance.now(); + + start.a.v.set(4), start.b.v.set(3), start.c.v.set(2), start.d.v.set(1); + + const end = layer; + const solution = [end.a.v.get(), end.b.v.get(), end.c.v.get(), end.d.v.get()]; + const endTime = performance.now() - startTime; + done(isSolution(layers, solution) ? endTime : -1); +} + +function runInulaDeepReactive3Layers(layers, done) { + const start = { + a: new reactive({ v: { v: { v: 1 } } }), + b: new reactive({ v: { v: { v: 2 } } }), + c: new reactive({ v: { v: { v: 3 } } }), + d: new reactive({ v: { v: { v: 4 } } }), + }; + + let layer = start; + + for (let i = layers; i--; ) { + layer = (l => { + return { + a: new computed(() => ({ + v: { + v: { + v: l.b.v.v.v.get(), + }, + }, + })), + b: new computed(() => ({ + v: { + v: { + v: l.a.v.v.v.get() - l.c.v.v.v.get(), + }, + }, + })), + c: new computed(() => ({ + v: { + v: { + v: l.b.v.v.v.get() + l.d.v.v.v.get(), + }, + }, + })), + d: new computed(() => ({ + v: { + v: { + v: l.c.v.v.v.get(), + }, + }, + })), + }; + })(layer); + } + + const startTime = performance.now(); + + start.a.v.v.v.set(4), start.b.v.v.v.set(3), start.c.v.v.v.set(2), start.d.v.v.v.set(1); + + const end = layer; + const solution = [end.a.v.v.v.get(), end.b.v.v.v.get(), end.c.v.v.v.get(), end.d.v.v.v.get()]; + const endTime = performance.now() - startTime; + done(isSolution(layers, solution) ? endTime : -1); +} + +/** + * @see {@link https://github.com/solidjs/solid} + */ +function runSolid(layers, done) { + solid.createRoot(async dispose => { + const [a, setA] = solid.createSignal(1), + [b, setB] = solid.createSignal(2), + [c, setC] = solid.createSignal(3), + [d, setD] = solid.createSignal(4); + + const start = { a, b, c, d }; + + let layer = start; + + for (let i = layers; i--; ) { + layer = (m => { + const props = { + a: solid.createMemo(() => m.b()), + b: solid.createMemo(() => m.a() - m.c()), + c: solid.createMemo(() => m.b() + m.d()), + d: solid.createMemo(() => m.c()), + }; + + return props; + })(layer); + } + + const startTime = performance.now(); + + const run = BATCHED ? solid.batch : fn => fn(); + run(() => { + setA(4), setB(3), setC(2), setD(1); + }); + + const end = layer; + const solution = [end.a(), end.b(), end.c(), end.d()]; + const endTime = performance.now() - startTime; + + dispose(); + done(isSolution(layers, solution) ? endTime : -1); + }); +} + +/** + * @see {@link https://github.com/modderme123/reactively} + */ +function runReactively(layers, done) { + const start = { + a: new reactively.Reactive(1), + b: new reactively.Reactive(2), + c: new reactively.Reactive(3), + d: new reactively.Reactive(4), + }; + + let layer = start; + + for (let i = layers; i--; ) { + layer = (m => { + return { + a: new reactively.Reactive(() => m.b.get()), + b: new reactively.Reactive(() => m.a.get() - m.c.get()), + c: new reactively.Reactive(() => m.b.get() + m.d.get()), + d: new reactively.Reactive(() => m.c.get()), + }; + })(layer); + } + + const startTime = performance.now(); + + start.a.set(4), start.b.set(3), start.c.set(2), start.d.set(1); + + const end = layer; + const solution = [end.a.get(), end.b.get(), end.c.get(), end.d.get()]; + const endTime = performance.now() - startTime; + + done(isSolution(layers, solution) ? endTime : -1); +} + +main(); diff --git a/packages/inula-reactive/bench/solid-reactive.js b/packages/inula-reactive/bench/solid-reactive.js new file mode 100644 index 00000000..845b80da --- /dev/null +++ b/packages/inula-reactive/bench/solid-reactive.js @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * openInula is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +// Extract from SolidJS for benchmark +const equalFn = (a, b) => a === b; +const signalOptions = { + equals: equalFn, +}; +let ERROR = null; +let runEffects = runQueue; +const NOTPENDING = {}; +const STALE = 1; +const PENDING = 2; +const UNOWNED = { + owned: null, + cleanups: null, + context: null, + owner: null, +}; +var Owner = null; +let Listener = null; +let Pending = null; +let Updates = null; +let Effects = null; +let ExecCount = 0; +function createRoot(fn, detachedOwner) { + detachedOwner && (Owner = detachedOwner); + const listener = Listener, + owner = Owner, + root = + fn.length === 0 && !false + ? UNOWNED + : { + owned: null, + cleanups: null, + context: null, + owner, + }; + Owner = root; + Listener = null; + let result; + try { + runUpdates(() => (result = fn(() => cleanNode(root))), true); + } finally { + Listener = listener; + Owner = owner; + } + return result; +} +function createSignal(value, options) { + options = options ? Object.assign({}, signalOptions, options) : signalOptions; + const s = { + value, + observers: null, + observerSlots: null, + pending: NOTPENDING, + comparator: options.equals || undefined, + }; + return [ + readSignal.bind(s), + (value) => { + if (typeof value === 'function') { + value = value(s.pending !== NOTPENDING ? s.pending : s.value); + } + return writeSignal(s, value); + }, + ]; +} +function createComputed(fn, value) { + updateComputation(createComputation(fn, value, true, STALE)); +} +function createMemo(fn, value, options) { + options = options ? Object.assign({}, signalOptions, options) : signalOptions; + const c = createComputation(fn, value, true, 0); + c.pending = NOTPENDING; + c.observers = null; + c.observerSlots = null; + c.comparator = options.equals || undefined; + updateComputation(c); + return readSignal.bind(c); +} + +function batch(fn) { + if (Pending) return fn(); + let result; + const q = (Pending = []); + try { + result = fn(); + } finally { + Pending = null; + } + runUpdates(() => { + for (let i = 0; i < q.length; i += 1) { + const data = q[i]; + if (data.pending !== NOTPENDING) { + const pending = data.pending; + data.pending = NOTPENDING; + writeSignal(data, pending); + } + } + }, false); + return result; +} +function untrack(fn) { + let result, + listener = Listener; + Listener = null; + result = fn(); + Listener = listener; + return result; +} + +function readSignal() { + if (this.state && this.sources) { + const updates = Updates; + Updates = null; + this.state === STALE ? updateComputation(this) : lookDownstream(this); + Updates = updates; + } + if (Listener) { + const sSlot = this.observers ? this.observers.length : 0; + if (!Listener.sources) { + Listener.sources = [this]; + Listener.sourceSlots = [sSlot]; + } else { + Listener.sources.push(this); + Listener.sourceSlots.push(sSlot); + } + if (!this.observers) { + this.observers = [Listener]; + this.observerSlots = [Listener.sources.length - 1]; + } else { + this.observers.push(Listener); + this.observerSlots.push(Listener.sources.length - 1); + } + } + return this.value; +} +function writeSignal(node, value, isComp) { + if (node.comparator) { + if (node.comparator(node.value, value)) return value; + } + if (Pending) { + if (node.pending === NOTPENDING) Pending.push(node); + node.pending = value; + return value; + } + node.value = value; + if (node.observers && node.observers.length) { + runUpdates(() => { + for (let i = 0; i < node.observers.length; i += 1) { + const o = node.observers[i]; + if (!o.state) { + if (o.pure) Updates.push(o); + else Effects.push(o); + if (o.observers) markUpstream(o); + } + o.state = STALE; + } + if (Updates.length > 10e5) { + Updates = []; + throw new Error(); + } + }, false); + } + return value; +} +function updateComputation(node) { + if (!node.fn) return; + cleanNode(node); + const owner = Owner, + listener = Listener, + time = ExecCount; + Listener = Owner = node; + runComputation(node, node.value, time); + Listener = listener; + Owner = owner; +} +function runComputation(node, value, time) { + let nextValue; + nextValue = node.fn(value); + if (!node.updatedAt || node.updatedAt <= time) { + if (node.observers && node.observers.length) { + writeSignal(node, nextValue, true); + } else node.value = nextValue; + node.updatedAt = time; + } +} +function createComputation(fn, init, pure, state = STALE, options) { + const c = { + fn, + state: state, + updatedAt: null, + owned: null, + sources: null, + sourceSlots: null, + cleanups: null, + value: init, + owner: Owner, + context: null, + pure, + }; + if (Owner === null); + else if (Owner !== UNOWNED) { + if (!Owner.owned) Owner.owned = [c]; + else Owner.owned.push(c); + } + return c; +} +function runTop(node) { + if (node.state !== STALE) return lookDownstream(node); + const ancestors = [node]; + while ((node = node.owner) && (!node.updatedAt || node.updatedAt < ExecCount)) { + if (node.state) ancestors.push(node); + } + for (let i = ancestors.length - 1; i >= 0; i--) { + node = ancestors[i]; + if (node.state === STALE) { + updateComputation(node); + } else if (node.state === PENDING) { + const updates = Updates; + Updates = null; + lookDownstream(node); + Updates = updates; + } + } +} +function runUpdates(fn, init) { + if (Updates) return fn(); + let wait = false; + if (!init) Updates = []; + if (Effects) wait = true; + else Effects = []; + ExecCount++; + try { + fn(); + } finally { + completeUpdates(wait); + } +} +function completeUpdates(wait) { + if (Updates) { + runQueue(Updates); + Updates = null; + } + if (wait) return; + if (Effects.length) + batch(() => { + runEffects(Effects); + Effects = null; + }); + else { + Effects = null; + } +} +function runQueue(queue) { + for (let i = 0; i < queue.length; i++) runTop(queue[i]); +} +function lookDownstream(node) { + node.state = 0; + for (let i = 0; i < node.sources.length; i += 1) { + const source = node.sources[i]; + if (source.sources) { + if (source.state === STALE) runTop(source); + else if (source.state === PENDING) lookDownstream(source); + } + } +} +function markUpstream(node) { + for (let i = 0; i < node.observers.length; i += 1) { + const o = node.observers[i]; + if (!o.state) { + o.state = PENDING; + if (o.pure) Updates.push(o); + else Effects.push(o); + o.observers && markUpstream(o); + } + } +} +function cleanNode(node) { + let i; + if (node.sources) { + while (node.sources.length) { + const source = node.sources.pop(), + index = node.sourceSlots.pop(), + obs = source.observers; + if (obs && obs.length) { + const n = obs.pop(), + s = source.observerSlots.pop(); + if (index < obs.length) { + n.sourceSlots[s] = index; + obs[index] = n; + source.observerSlots[index] = s; + } + } + } + } + if (node.owned) { + for (i = 0; i < node.owned.length; i++) cleanNode(node.owned[i]); + node.owned = null; + } + if (node.cleanups) { + for (i = 0; i < node.cleanups.length; i++) node.cleanups[i](); + node.cleanups = null; + } + node.state = 0; + node.context = null; +} +export { createComputed, createMemo, createRoot, createSignal, batch }; diff --git a/packages/inula-reactive/jest.config.js b/packages/inula-reactive/jest.config.js index ab451afc..64494e53 100644 --- a/packages/inula-reactive/jest.config.js +++ b/packages/inula-reactive/jest.config.js @@ -13,7 +13,7 @@ * See the Mulan PSL v2 for more details. */ -module.exports = { +export default { coverageDirectory: 'coverage', resetModules: true, diff --git a/packages/inula-reactive/package.json b/packages/inula-reactive/package.json index 1b5c1c2a..e6aa5452 100644 --- a/packages/inula-reactive/package.json +++ b/packages/inula-reactive/package.json @@ -2,11 +2,20 @@ "name": "inula-reactive", "version": "0.0.1", "description": "reactive core", - "main": "index.ts", + "main": "dist/index.js", + "type": "module", "scripts": { - "test": "jest --config=jest.config.js" + "build": "rollup --config ./rollup.config.js", + "test": "jest --config=jest.config.js", + "bench": "node --experimental-specifier-resolution=node --inspect ./bench/index.js" }, "dependencies": { + "@reactively/core": "^0.0.8", "inula-reactive": "workspace:^0.0.1" + }, + "devDependencies": { + "chalk": "^5.3.0", + "cli-table": "^0.3.11", + "tslib": "^2.6.2" } } diff --git a/packages/inula-reactive/rollup.config.js b/packages/inula-reactive/rollup.config.js new file mode 100644 index 00000000..0ae91f8b --- /dev/null +++ b/packages/inula-reactive/rollup.config.js @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. + * + * openInula is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +import nodeResolve from '@rollup/plugin-node-resolve'; +import babel from '@rollup/plugin-babel'; +import path from 'path'; +import replace from '@rollup/plugin-replace'; + +const extensions = ['.js', '.ts', '.tsx']; + +const getBasicPlugins = mode => { + return [ + nodeResolve({ + extensions, + modulesOnly: true, + }), + babel({ + exclude: 'node_modules/**', + configFile: path.join(__dirname, './babel.config.cjs'), + extensions, + }), + replace({ + values: { + 'process.env.NODE_ENV': `"${mode}"`, + }, + preventAssignment: true, + }), + ]; +}; + +function genConfig(mode) { + return { + input: path.resolve(__dirname, 'src', 'index.ts'), + output: [ + { + file:path.resolve(__dirname, 'dist', 'index.js'), + format: 'esm', + }, + ], + plugins: [ + ...getBasicPlugins(mode), + ], + }; +} + + +export default [genConfig('production')]; diff --git a/packages/inula-reactive/src/RNode.ts b/packages/inula-reactive/src/RNode.ts index fe80e811..a6a0f18f 100644 --- a/packages/inula-reactive/src/RNode.ts +++ b/packages/inula-reactive/src/RNode.ts @@ -187,7 +187,7 @@ export class RNode implements Signal { } // 执行 reactive 函数 - this.execute(); + this._value = this.fn!(); if (calledGets) { // remove all old sources' .observers links to us @@ -239,11 +239,6 @@ export class RNode implements Signal { this.state = Fresh; } - execute() { - // 执行 reactive 函数 - this._value = this.fn!(); - } - /** * 1、如果this是check,就去找dirty的parent * 2、执行dirty的parent后,会 diff --git a/packages/inula-reactive/src/RNodeCreator.ts b/packages/inula-reactive/src/RNodeCreator.ts index 9dd75cb9..580a71ff 100644 --- a/packages/inula-reactive/src/RNodeCreator.ts +++ b/packages/inula-reactive/src/RNodeCreator.ts @@ -15,7 +15,7 @@ import { isPrimitive } from './Utils'; import { RNode } from './RNode'; -import { Fn, NonFunctionType, Signal } from './Types'; +import { Fn, NoArgFn, NonFunctionType, Signal } from './Types'; import { DeepReactive, RProxyNode } from './RProxyNode'; import { getRNodeVal } from './RNodeAccessor'; @@ -35,7 +35,7 @@ export function createReactive(raw?: T): DeepReactive } } -export function createComputed(fn: T) { +export function createComputed(fn: T) { const rNode = new RProxyNode(fn, { isComputed: true }); return rNode.proxy; } diff --git a/packages/inula-reactive/index.ts b/packages/inula-reactive/src/index.ts similarity index 85% rename from packages/inula-reactive/index.ts rename to packages/inula-reactive/src/index.ts index 0e44a8a0..03dbca6f 100644 --- a/packages/inula-reactive/index.ts +++ b/packages/inula-reactive/src/index.ts @@ -13,9 +13,9 @@ * See the Mulan PSL v2 for more details. */ -import { createComputed as computed, createReactive as reactive, createWatch as watch} from './src/RNodeCreator'; -import { isReactiveObj } from './src/Utils'; -import { RNode, untrack } from './src/RNode'; +import { createComputed as computed, createReactive as reactive, createWatch as watch} from './RNodeCreator'; +import { isReactiveObj } from './Utils'; +import { RNode, untrack } from './RNode'; export interface Index { reactive(initialValue: T): RNode; @@ -30,5 +30,6 @@ export { watch, computed, isReactiveObj, + RNode, untrack }; diff --git a/packages/inula-reactive/src/utils/printNode.ts b/packages/inula-reactive/src/utils/printNode.ts index 7eff51f3..b3dba344 100644 --- a/packages/inula-reactive/src/utils/printNode.ts +++ b/packages/inula-reactive/src/utils/printNode.ts @@ -15,7 +15,7 @@ import { RNode } from '../RNode'; -export function printNode(signal: RNode) { +export /*# __PURE__*/function printNode(signal: RNode) { let name: string; if (signal.fn) { if (signal.isEffect) { diff --git a/packages/inula-reactive/tests/reactive.test.ts b/packages/inula-reactive/tests/reactive.test.ts index f3f119ad..76442260 100644 --- a/packages/inula-reactive/tests/reactive.test.ts +++ b/packages/inula-reactive/tests/reactive.test.ts @@ -1,4 +1,4 @@ -import { reactive, computed, watch } from '../index'; +import { reactive, computed, watch } from '../src'; describe('test reactive', () => { it('computation should work with two reactive', () => { diff --git a/packages/inula-reactive/tsconfig.json b/packages/inula-reactive/tsconfig.json new file mode 100644 index 00000000..a7bd7882 --- /dev/null +++ b/packages/inula-reactive/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "module": "esnext", + "outDir": "./dist", + "strict": true, + "skipLibCheck": true, + "declaration": true, + "moduleResolution": "node", + "esModuleInterop": true, + "importHelpers": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "**/*.spec.ts", "./src/template/**/*"], + "ts-node": { + "esm": true, + }, +} diff --git a/packages/inula/scripts/rollup/rollup.config.js b/packages/inula/scripts/rollup/rollup.config.js index 4ab91071..42952ac2 100644 --- a/packages/inula/scripts/rollup/rollup.config.js +++ b/packages/inula/scripts/rollup/rollup.config.js @@ -50,7 +50,7 @@ const getBasicPlugins = mode => { }), babel({ exclude: 'node_modules/**', - configFile: path.join(__dirname, '../../babel.config.js'), + configFile: path.join(__dirname, '../../babel.config.cjs'), babelHelpers: 'runtime', extensions, }), @@ -80,6 +80,11 @@ function genConfig(mode) { sourcemap, format: 'cjs', }, + { + file: outputResolve('esm', getOutputName(mode)), + sourcemap, + format: 'esm', + }, { file: outputResolve('umd', getOutputName(mode)), sourcemap,