Skip to content

Commit

Permalink
feat: improve miniapp
Browse files Browse the repository at this point in the history
  • Loading branch information
XGHeaven committed Oct 21, 2024
1 parent 942cb53 commit 4a9c48d
Show file tree
Hide file tree
Showing 71 changed files with 4,881 additions and 592 deletions.
15 changes: 15 additions & 0 deletions .changeset/fresh-pillows-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@ice/plugin-miniapp': minor
'@ice/app': minor
'@ice/miniapp-loader': minor
'@ice/miniapp-react-dom': minor
'@ice/miniapp-runtime': minor
'@ice/shared': minor
'@ice/shared-config': minor
'@ice/webpack-config': minor
'@ice/rspack-config': minor
'@ice/route-manifest': minor
'@ice/runtime': minor
---

feat: improve miniapp runtime
36 changes: 36 additions & 0 deletions .github/workflows/pr-temp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: PR Release

on:
pull_request:

jobs:
release:
name: Release
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18]

steps:
- name: Checkout Branch
uses: actions/checkout@v3

- name: Install pnpm
uses: pnpm/action-setup@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'

- name: Setup
run: pnpm run setup

- name: Config npm
run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

- run: pnpm run release:snapshot
14 changes: 7 additions & 7 deletions packages/ice/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,18 @@
"bugs": "https://github.com/alibaba/ice/issues",
"homepage": "https://v3.ice.work",
"dependencies": {
"@ice/bundles": "0.2.7",
"@ice/route-manifest": "1.2.2",
"@ice/runtime": "^1.4.13",
"@ice/shared-config": "1.2.9",
"@ice/webpack-config": "1.1.16",
"@ice/rspack-config": "1.1.10",
"@ice/bundles": "workspace:*",
"@ice/route-manifest": "workspace:*",
"@ice/runtime": "workspace:^",
"@ice/shared-config": "workspace:*",
"@ice/webpack-config": "workspace:*",
"@ice/rspack-config": "workspace:*",
"@swc/helpers": "0.5.1",
"@types/express": "^4.17.14",
"address": "^1.1.2",
"build-scripts": "^2.1.2-0",
"chalk": "^4.0.0",
"chokidar": "^3.5.3",
"commander": "^9.0.0",
"consola": "^2.15.3",
"cross-spawn": "^7.0.3",
Expand Down Expand Up @@ -89,7 +90,6 @@
"@types/micromatch": "^4.0.2",
"@types/multer": "^1.4.7",
"@types/temp": "^0.9.1",
"chokidar": "^3.5.3",
"esbuild": "^0.17.16",
"jest": "^29.0.2",
"react": "^18.2.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/ice/src/bundler/webpack/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async function bundler(
if (useDevServer) {
devServer = await startDevServer(compiler, webpackConfigs, context, options);
} else {
await invokeCompilerWatch(compiler, context);
await invokeCompilerWatch(compiler, webpackConfigs, context, options);
}
} else if (command === 'build') {
await build(compiler, webpackConfigs, context, options);
Expand Down
26 changes: 24 additions & 2 deletions packages/ice/src/bundler/webpack/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,22 @@ export async function startDevServer(

export async function invokeCompilerWatch(
compiler: webpack.Compiler,
webpackConfigs: Configuration[],
context: Context,
options: BundlerOptions,
) {
const { userConfig, rootDir } = context;
const { userConfig, rootDir, applyHook, commandArgs } = context;
const { outputDir } = userConfig;
const { taskConfigs, hooksAPI } = options;
const absoluteOutputDir = path.resolve(rootDir, outputDir);
let messages: { errors: string[]; warnings: string[] };
await applyHook('before.start.run', {
commandArgs,
taskConfigs,
webpackConfigs,
...hooksAPI,
});
let isFirstCompile = true;
compiler.watch({
aggregateTimeout: 200,
ignored: ['**/node_modules/**', `${absoluteOutputDir}/**`],
Expand All @@ -139,10 +149,22 @@ export async function invokeCompilerWatch(
} else {
messages = formatWebpackMessages(stats.toJson({ all: false, warnings: true, errors: true }));
}

const isSuccessful = !messages.errors.length;
if (messages.errors.length) {
logger.error('Webpack compile error');
throw new Error(messages.errors.join('\n\n'));
}

await applyHook('after.start.compile', {
stats,
isSuccessful,
isFirstCompile,
messages,
taskConfigs,
...hooksAPI,
});
if (isSuccessful) {
isFirstCompile = false;
}
});
}
2 changes: 1 addition & 1 deletion packages/ice/templates/core/env.ts.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const isKuaiShouMiniProgram = isClient && import.meta.target === 'kuaisho
export const isWeChatMiniProgram = isClient && import.meta.target === 'wechat-miniprogram';
export const isKraken = isClient && import.meta.target === 'kraken';
export const isQuickApp = false; // Now ice.js will not implement quick app target.
export const isMiniApp = isAliMiniApp || isByteDanceMicroApp || isBaiduSmartProgram || isKuaiShouMiniProgram || isWeChatMiniProgram;
export const isMiniApp = isAliMiniApp;// in universal-env, isMiniApp is equals to isAliMiniApp

// Following variables are runtime executed envs.
// See also @uni/env.
Expand Down
2 changes: 1 addition & 1 deletion packages/miniapp-loader/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
"sideEffects": false,
"dependencies": {
"@ice/bundles": "^0.2.0"
"@ice/bundles": "workspace:^"
},
"devDependencies": {
"webpack": "^5.88.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/miniapp-loader/src/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export default function (this: webpack.LoaderContext<any>) {
const config = getPageConfig(loaderConfig, this.resourcePath);
const configString = JSON.stringify(config);
const stringify = (s: string): string => stringifyRequest(this, s);
const { loaders } = this;
const { loaders, resourcePath } = this;
const thisLoaderIndex = loaders.findIndex(item => normalizePath(item.path).indexOf('miniapp-loader/lib/page') >= 0);
const componentPath = this.request.split('!').slice(thisLoaderIndex + 1).join('!');
const componentPath = [...loaders.slice(thisLoaderIndex + 1).map(loader => `${loader.path}${loader.query}`), '!', resourcePath].join('!');

const getDataAndConfigString = `${hasExportConfig ? 'pageConfig, ' : ''}${hasExportData ? 'dataLoader' : ''}`;
let instantiatePage = `var inst = Page(createPageConfig(component, '${options.name}', {root:{cn:[]}}, { ${getDataAndConfigString} }, config || {}))`;
Expand Down
4 changes: 2 additions & 2 deletions packages/miniapp-react-dom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
},
"sideEffects": false,
"dependencies": {
"@ice/miniapp-runtime": "^1.1.2",
"@ice/shared": "^1.0.2",
"@ice/miniapp-runtime": "workspace:^",
"@ice/shared": "workspace:^",
"react-reconciler": "0.27.0",
"scheduler": "^0.20.1"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/miniapp-runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
},
"sideEffects": false,
"dependencies": {
"@ice/shared": "^1.0.2",
"@ice/runtime": "^1.2.9",
"@ice/shared": "workspace:^",
"@ice/runtime": "workspace:^",
"miniapp-history": "^0.1.7"
},
"devDependencies": {
Expand Down
22 changes: 11 additions & 11 deletions packages/miniapp-runtime/src/app/connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function connectReactPage(
};

static getDerivedStateFromError(error: Error) {
triggerAppHook('onError', error.message + error.stack);
triggerAppHook(this, 'onError', error.message + error.stack);
return { hasError: true };
}
render() {
Expand Down Expand Up @@ -185,62 +185,62 @@ export class AppWrapper extends React.Component {
[ON_LAUNCH]: setDefaultDescriptor({
value(options) {
setRouterParams(options);
triggerAppHook('onLaunch', options);
triggerAppHook(this, 'onLaunch', options);
},
}),

[ON_SHOW]: setDefaultDescriptor({
value(options) {
setRouterParams(options);
triggerAppHook('onShow', options);
triggerAppHook(this, 'onShow', options);
},
}),

[ON_HIDE]: setDefaultDescriptor({
value() {
triggerAppHook('onHide');
triggerAppHook(this, 'onHide');
},
}),

[ON_ERROR]: setDefaultDescriptor({
value(error: string) {
triggerAppHook('onError', error);
triggerAppHook(this, 'onError', error);
},
}),

[ON_PAGE_NOT_FOUND]: setDefaultDescriptor({
value(res: unknown) {
triggerAppHook('onPageNotFound', res);
triggerAppHook(this, 'onPageNotFound', res);
},
}),

[ON_UNHANDLED_REJECTION]: setDefaultDescriptor({
value(res: unknown) {
triggerAppHook('onUnhandledRejection', res);
triggerAppHook(this, 'onUnhandledRejection', res);
},
}),
});

if (lifecycles.onShareAppMessage) {
// Only works in ali miniapp
appObj.onShareAppMessage = function (res) {
return triggerAppHook('onShareAppMessage', res);
return triggerAppHook(this, 'onShareAppMessage', res);
};
}

Current.app = appObj;
return App(appObj);
}

function triggerAppHook(lifecycle: keyof PageLifeCycle | keyof AppInstance, ...option): any {
function triggerAppHook(app: unknown, lifecycle: keyof PageLifeCycle | keyof AppInstance, ...option): any {
const instance = getPageInstance(HOOKS_APP_ID);
if (instance) {
const func = hooks.call('getLifecycle', instance, lifecycle);
if (Array.isArray(func)) {
if (lifecycle === 'onShareAppMessage') {
return func[0].apply(null, option);
return func[0].apply(app, option);
}
func.forEach(cb => cb.apply(null, option));
func.forEach(cb => cb.apply(app, option));
}
}
}
4 changes: 2 additions & 2 deletions packages/miniapp-runtime/src/app/runClientApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import { setHistory } from './history.js';
import injectMiniappLifecycles from './injectMiniappLifecycles.js';

export default async function runClientApp(options: RunClientAppOptions) {
const { app, runtimeModules } = options;
const { app, runtimeModules, runtimeOptions } = options;
const appConfig = getAppConfig(app);
const appContext: AppContext = {
appExport: app,
appConfig,
appData: null,
};
const runtime = new Runtime(appContext);
const runtime = new Runtime(appContext, runtimeOptions);
if (runtimeModules.statics) {
await Promise.all(runtimeModules.statics.map(m => runtime.loadModule(m)).filter(Boolean));
}
Expand Down
16 changes: 16 additions & 0 deletions packages/miniapp-runtime/src/dom/event-target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,20 @@ export class EventTarget {
const isAnyEventBinded = Object.keys(handlers).find(key => handlers[key].length);
return Boolean(isAnyEventBinded);
}

public triggerEventListenerInternal(type: string, args: unknown[]) {
type = type.toLowerCase();
const handlers = this.__handlers[type];
if (!isArray(handlers)) {
return;
}
for (const handler of handlers) {
handler(...args);
}
}

public getListenerNames(): string[] {
const handlers = this.__handlers;
return Object.keys(handlers).filter(key => handlers[key].length);
}
}
21 changes: 21 additions & 0 deletions packages/miniapp-runtime/src/dom/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import env from '../env.js';
import type { EventOptions, MpEvent } from '../interface/index.js';
import { isParentBinded } from '../utils/index.js';
import type { Element } from './element.js';
import { type Node } from './node.js';

// 事件对象。以 Web 标准的事件对象为基础,加入小程序事件对象中携带的部分信息,并模拟实现事件冒泡。
export class Event {
Expand Down Expand Up @@ -179,3 +180,23 @@ export function eventHandler(event: MpEvent) {
}
}
}

export function createEventHandlerForThirdComponent(sid: string, eventName: string) {
return (...args: unknown[]) => {
const node = env.document.getElementById(sid);
if (node) {
node.triggerEventListenerInternal(eventName, args);
}
};
}

export function bindEventHandlersForThirdComponentNode(node: Node) {
const instance = node._root?.ctx;
if (!instance) {
return;
}
const eventNames = node.getListenerNames();
for (const eventName of eventNames) {
instance[`eh_${node.sid}_${eventName}`] = createEventHandlerForThirdComponent(node.sid, eventName);
}
}
4 changes: 3 additions & 1 deletion packages/miniapp-runtime/src/dom/root.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isFunction, isUndefined, Shortcuts } from '@ice/shared';
import { hooks, isFunction, isUndefined, Shortcuts } from '@ice/shared';

import {
CUSTOM_WRAPPER,
Expand Down Expand Up @@ -166,6 +166,7 @@ export class RootElement extends Element {
// eslint-disable-next-line no-console
console.log('custom wrapper setData: ', data);
}
hooks.call('modifySetDataPayload', data, ctx);
ctx.setData(data, cb);
});
}
Expand All @@ -176,6 +177,7 @@ export class RootElement extends Element {
// eslint-disable-next-line no-console
console.log('page setData:', normalUpdate);
}
hooks.call('modifySetDataPayload', data, ctx);
ctx.setData(normalUpdate, cb);
}
}, 0);
Expand Down
14 changes: 4 additions & 10 deletions packages/miniapp-runtime/src/hydrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,8 @@ export function hydrate(node: Element | Text): MiniData {
}
}

let { childNodes } = node;

// 过滤 comment 节点
childNodes = childNodes.filter(node => !isComment(node));

if (childNodes.length > 0) {
data[Shortcuts.Childnodes] = childNodes.map(hydrate);
} else {
data[Shortcuts.Childnodes] = [];
}
// Children
data[Shortcuts.Childnodes] = node.childNodes.filter(node => !isComment(node)).map(hydrate);

if (node.className !== '') {
data[Shortcuts.Class] = node.className;
Expand All @@ -108,6 +100,8 @@ export function hydrate(node: Element | Text): MiniData {
delete data[prop];
}
}
} else {
hooks.call('hydrateNativeComponentNode', node);
}

return data;
Expand Down
Loading

0 comments on commit 4a9c48d

Please sign in to comment.