Skip to content
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

feat: improve miniapp #6985

Merged
merged 1 commit into from
Nov 11, 2024
Merged
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
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:*",
ClarkXia marked this conversation as resolved.
Show resolved Hide resolved
"@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
XGHeaven marked this conversation as resolved.
Show resolved Hide resolved

// 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
4 changes: 2 additions & 2 deletions packages/miniapp-runtime/src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { AppErrorBoundary, useAppContext } from '@ice/runtime';
import { AppErrorBoundary, usePublicAppContext } from '@ice/runtime';
import { AppWrapper } from './connect.js';

export default function App() {
const { appConfig } = useAppContext();
const { appConfig } = usePublicAppContext();
const { strict, errorBoundary } = appConfig.app;
const StrictMode = strict ? React.StrictMode : React.Fragment;
const ErrorBoundary = errorBoundary ? AppErrorBoundary : React.Fragment;
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));
}
}
}
11 changes: 7 additions & 4 deletions packages/miniapp-runtime/src/app/runClientApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,19 @@ 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);
if (runtimeModules.statics) {
await Promise.all(runtimeModules.statics.map(m => runtime.loadModule(m)).filter(Boolean));
const runtime = new Runtime(appContext, runtimeOptions);
if (runtimeModules.statics && runtimeModules.statics.length > 0) {
const promises = runtimeModules.statics.map(m => runtime.loadModule(m));
if (promises.some(promise => promise && promise.then)) {
console.warn('Miniapp is not support async static runtime modules');
}
}

const { miniappManifest, miniappLifecycles = {} } = app;
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
Loading
Loading