From 8c4b08155f5e545b8c557ea37aa03e32cf8b1213 Mon Sep 17 00:00:00 2001 From: bailicangdu <1264889788@qq.com> Date: Fri, 5 Nov 2021 17:29:51 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=85=83?= =?UTF-8?q?=E7=B4=A0=E6=9F=A5=E8=AF=A2=E6=97=B6=E5=B8=A6=E6=9C=89=E7=89=B9?= =?UTF-8?q?=E6=AE=8A=E5=AD=97=E7=AC=A6=E5=AF=BC=E8=87=B4=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/index.html | 2 +- docs/zh-cn/advanced.md | 73 +++++++++++---- docs/zh-cn/changelog.md | 7 +- docs/zh-cn/data.md | 79 ++++++++-------- examples/children/vite/src/main.js | 17 +++- examples/main-react16/src/pages/vite/vite.js | 13 ++- jest.config.js | 1 + package.json | 7 +- rollup.config.js | 1 + src/__tests__/libs/utils.test.ts | 8 ++ src/__tests__/source/patch.test.ts | 45 ++++----- src/index.ts | 3 +- src/libs/utils.ts | 20 ++++ src/source/patch.ts | 97 +++++++++++--------- typings/global.d.ts | 4 + 15 files changed, 239 insertions(+), 138 deletions(-) diff --git a/docs/index.html b/docs/index.html index befc90076..d4bfa4306 100644 --- a/docs/index.html +++ b/docs/index.html @@ -30,7 +30,7 @@
MicroApp
-

一种用于构建微前端应用的极简方案

+

一款轻量、高效、功能强大的微前端框架

开始使用 在线案例 diff --git a/docs/zh-cn/advanced.md b/docs/zh-cn/advanced.md index 87926a5d0..99b64fa6d 100644 --- a/docs/zh-cn/advanced.md +++ b/docs/zh-cn/advanced.md @@ -36,7 +36,7 @@ microApp.start({ > 1、如果跨域请求带cookie,那么`Access-Control-Allow-Origin`不能设置为`*`,这一点需要注意 ## 2、适配vite -当子应用是vite应用时需要做特别的适配,适配vite的代价是巨大的,我们必须关闭沙箱功能,因为沙箱在`module script`下不支持,这导致大部分功能失效,包括:环境变量、样式隔离、元素隔离、数据通信、资源地址补全、baseroute 等。 +当子应用是vite应用时需要做特别的适配,适配vite的代价是巨大的,我们必须关闭沙箱功能,因为沙箱在`module script`下不支持,这导致大部分功能失效,包括:环境变量、样式隔离、元素隔离、资源地址补全、baseroute 等。 在嵌入vite子应用时,`micro-app`的功能只负责渲染,其它的行为由应用自行决定,这包括如何防止样式、JS变量、元素的冲突。 @@ -47,6 +47,9 @@ microApp.start({ ##### 1、修改vite.config.js ```js +import { join } from 'path' +import { writeFileSync } from 'fs' + // vite.config.js export default defineConfig({ base: `${process.env.NODE_ENV === 'production' ? 'http://my-site.com' : ''}/basename/`, @@ -57,20 +60,24 @@ export default defineConfig({ let basePath = '' return { name: "vite:micro-app", - apply: 'build', // 只在生产环境生效 + apply: 'build', configResolved(config) { - // 获取资源地址前缀 basePath = `${config.base}${config.build.assetsDir}/` }, - renderChunk(code, chunk) { - // build后,import会通过相对地址引入模块,需要将其补全 - if (chunk.fileName.endsWith('.js') && /(from|import)(\s*['"])(\.\.?\/)/g.test(code)) { - code = code.replace(/(from|import)(\s*['"])(\.\.?\/)/g, (all, $1, $2, $3) => { - return all.replace($3, new URL($3, basePath)) - }) + writeBundle (options, bundle) { + for (const chunkName in bundle) { + if (Object.prototype.hasOwnProperty.call(bundle, chunkName)) { + const chunk = bundle[chunkName] + if (chunk.fileName && chunk.fileName.endsWith('.js')) { + chunk.code = chunk.code.replace(/(from|import\()(\s*['"])(\.\.?\/)/g, (all, $1, $2, $3) => { + return all.replace($3, new URL($3, basePath)) + }) + const fullPath = join(options.dir, chunk.fileName) + writeFileSync(fullPath, chunk.code) + } + } } - return code - } + }, } })(), ], @@ -78,11 +85,7 @@ export default defineConfig({ ``` ##### 2、路由 -vite环境下,当路由的baseName和vite.base值不相等,两者会进行拼接,这导致无法自定义baseName来适配基座应用的路由。 - -有两种方式解决这个问题: -- 方式一:子应用使用hash路由 -- 方式二:子应用根据基座路由单独打包一个版本,这个版本的子应用无法单独访问,必须嵌入基座中运行。 +推荐子应用使用hash路由,避免一些可能出现的问题。 ##### 3、静态资源 图片等静态资源需要使用绝对地址,可以使用 `new URL('../assets/logo.png', import.meta.url).href` 等方式获取资源的全链接地址。 @@ -127,7 +130,43 @@ microApp.start({ }) ``` -> [!TIP] +### vite数据通信 +沙箱关闭后,子应用默认的通信功能失效,此时可以通过手动注册通信对象实现一致的功能。 + +**注册方式:在基座应用中为子应用初始化通信对象** + +```js +import { EventCenterForMicroApp } from '@micro-zoe/micro-app' + +// 注意:每个vite子应用根据appName单独分配一个通信对象 +window.eventCenterForViteApp1 = new EventCenterForMicroApp(appName) +``` + +vite子应用就可以通过注册的`eventCenterForViteApp1`对象进行通信,其api和`window.microApp`一致,*而基座通信方式没有任何变化。* + +**子应用通信方式:** +```js +/** + * 绑定监听函数 + * dataListener: 绑定函数 + * autoTrigger: 在初次绑定监听函数时有缓存数据,是否需要主动触发一次,默认为false + */ +window.eventCenterForViteApp1.addDataListener(dataListener: (data: Object) => void, autoTrigger?: boolean) + +// 解绑指定函数 +window.eventCenterForViteApp1.removeDataListener(dataListener) + +// 清空当前子应用的所有绑定函数(全局数据函数除外) +window.eventCenterForViteApp1.clearDataListener() + +// 主动获取数据 +window.eventCenterForViteApp1.getData() + +// 子应用向基座应用发送数据 +window.eventCenterForViteApp1.dispatch({type: '子应用发送的数据'}) +``` + +> [!WARNING] > 1、关闭沙箱后的子应用可以直接访问全局window,可以通过挂载全局变量来进行数据通信和其它操作。 > > 2、适配vite本质上是适配module脚本,其它非vite构建的module脚本也可以采用相同的思路处理。 diff --git a/docs/zh-cn/changelog.md b/docs/zh-cn/changelog.md index 5a58bc55d..0a22fdd7e 100644 --- a/docs/zh-cn/changelog.md +++ b/docs/zh-cn/changelog.md @@ -12,9 +12,14 @@ `2021-11-05` +- **New** + + - 🆕 新增了`EventCenterForMicroApp`方法,用于沙箱关闭时实现通信功能(如vite) + - **Bug Fix** - - 🐞 修复了在不支持`ShadowRoot`的浏览器中的报错问题 + - 🐞 修复了在不支持`ShadowRoot`的浏览器中的报错问题,fix [#134](https://github.com/micro-zoe/micro-app/issues/134) + - 🐞 修复了元素查询时带有特殊字符导致报错的问题,fix [#140](https://github.com/micro-zoe/micro-app/issues/140) ### 0.4.2 diff --git a/docs/zh-cn/data.md b/docs/zh-cn/data.md index 6638fb48a..6a69433ec 100644 --- a/docs/zh-cn/data.md +++ b/docs/zh-cn/data.md @@ -9,7 +9,46 @@ 如果想要同时向多个子应用发送数据,可以看一下节[全局数据通信](/zh-cn/data?id=全局数据通信) -### 1、基座应用向子应用发送数据 + +### 1、子应用获取来自基座应用的数据 + `micro-app`会向子应用注入名称为`microApp`的全局对象,子应用通过这个对象和基座应用进行数据交互。 + + 有两种方式获取来自基座应用的数据: + + **方式1:绑定/解绑监听函数** + + 监听函数只有在数据变化时才会触发。 + ```js + function dataListener (data) { + console.log('来自基座应用的数据', data) + } + + /** + * 绑定监听函数 + * dataListener: 绑定函数 + * autoTrigger: 在初次绑定监听函数时有缓存数据,是否需要主动触发一次,默认为false + * 补充: autoTrigger主要是为子应用提供的,因为子应用是异步渲染的,如果在子应用还没渲染时基座应用发送数据,子应用在初始化后不会触发绑定函数,但这个数据会放入缓存中,此时可以设置autoTrigger为true主动触发一次监听函数来获取数据。 + */ + window.microApp?.addDataListener(dataListener: Function, autoTrigger?: boolean) + + // 解绑指定函数 + window.microApp?.removeDataListener(dataListener) + + // 清空当前子应用的所有绑定函数(全局数据函数除外) + window.microApp?.clearDataListener() + ``` + + **方式2:主动获取数据** + ```js + window.microApp?.getData() // 返回data数据 + ``` + +### 2、子应用向基座应用发送数据 +```js +window.microApp?.dispatch({type: '子应用发送的数据'}) +``` + +### 3、基座应用向子应用发送数据 基座应用向子应用发送数据有两种方式: **方式1: 通过data属性发送数据** @@ -56,44 +95,6 @@ microApp.setData('my-app', {type: '新的数据'}) ``` -### 2、子应用获取来自基座应用的数据 - `micro-app`会向子应用注入名称为`microApp`的全局对象,子应用通过这个对象和基座应用进行数据交互。 - - 有两种方式获取来自基座应用的数据: - - **方式1:绑定/解绑监听函数** - - 监听函数只有在数据变化时才会触发。 - ```js - function dataListener (data) { - console.log('来自基座应用的数据', data) - } - - /** - * 绑定监听函数 - * dataListener: 绑定函数 - * autoTrigger: 在初次绑定监听函数时有缓存数据,是否需要主动触发一次,默认为false - * 补充: autoTrigger主要是为子应用提供的,因为子应用是异步渲染的,如果在子应用还没渲染时基座应用发送数据,子应用在初始化后不会触发绑定函数,但这个数据会放入缓存中,此时可以设置autoTrigger为true主动触发一次监听函数来获取数据。 - */ - window.microApp?.addDataListener(dataListener: Function, autoTrigger?: boolean) - - // 解绑指定函数 - window.microApp?.removeDataListener(dataListener) - - // 清空当前子应用的所有绑定函数(全局数据函数除外) - window.microApp?.clearDataListener() - ``` - - **方式2:主动获取数据** - ```js - window.microApp?.getData() // 返回data数据 - ``` - -### 3、子应用向基座应用发送数据 -```js -window.microApp?.dispatch({type: '子应用发送的数据'}) -``` - ### 4、基座应用获取来自子应用的数据 基座应用获取来自子应用的数据有三种方式: diff --git a/examples/children/vite/src/main.js b/examples/children/vite/src/main.js index 0e414beba..8c0d9049e 100644 --- a/examples/children/vite/src/main.js +++ b/examples/children/vite/src/main.js @@ -18,7 +18,6 @@ const routes = [ // app.use(router) // app.mount('#vite-app') - let app = null let router = null let history = null @@ -35,12 +34,28 @@ function mount () { app.mount('#vite-app') console.log('微应用child-vite渲染了') + + // eventCenterForVite 是基座添加到window的数据通信对象 + // 主动获取基座下发的数据 + console.log('child-vite getData:', window.eventCenterForVite?.getData()) + + // 监听基座下发的数据变化 + window.eventCenterForVite?.addDataListener((data) => { + console.log('child-vite addDataListener:', data) + }) + + // 向基座发送数据 + setTimeout(() => { + window.eventCenterForVite?.dispatch({ myname: 'child-vite' }) + }, 3000) } // 将卸载操作放入 unmount 函数 function unmount () { app?.unmount() history?.destroy() + // 卸载所有数据监听函数 + window.eventCenterForVite?.clearDataListener() app = null router = null history = null diff --git a/examples/main-react16/src/pages/vite/vite.js b/examples/main-react16/src/pages/vite/vite.js index 0adc65853..b3c57e214 100644 --- a/examples/main-react16/src/pages/vite/vite.js +++ b/examples/main-react16/src/pages/vite/vite.js @@ -4,9 +4,13 @@ import jsxCustomEvent from '@micro-zoe/micro-app/polyfill/jsx-custom-event' import { useState } from 'react' import { Button, Spin } from 'antd' import { LoadingOutlined } from '@ant-design/icons' +import { EventCenterForMicroApp } from '@micro-zoe/micro-app' import config from '../../config' import './vite.less' +// 注册子应用vite的数据通信对象 +window.eventCenterForVite = new EventCenterForMicroApp('vite') + const antIcon = function vite () { @@ -18,9 +22,13 @@ function vite () { console.log('生命周期: vite 渲染完成了') } + function handleDataChange (e) { + console.log('来自 vite 子应用的数据', e.detail.data) + } + return (
- {/*
+
-
*/} +
{ showLoading && } @@ -39,6 +47,7 @@ function vite () { data={data} // onBeforemount={() => hideLoading(false)} onMounted={handleMounted} + onDataChange={handleDataChange} // destroy // inline disableSandbox diff --git a/jest.config.js b/jest.config.js index 996802b9e..655872bd2 100755 --- a/jest.config.js +++ b/jest.config.js @@ -39,6 +39,7 @@ module.exports = { ], globals: { __DEV__: true, + __TEST__: true, 'ts-jest': { tsconfig: { target: 'es5', diff --git a/package.json b/package.json index bb96c46a1..247cb5583 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@micro-zoe/micro-app", - "version": "0.4.2", - "description": "A minimalist solution for building micro front-end applications", + "version": "0.4.3", + "description": "A lightweight, efficient and powerful micro front-end framework", "private": false, "main": "lib/index.min.js", "module": "lib/index.esm.js", @@ -82,9 +82,6 @@ ] }, "dependencies": {}, - "peerDependencies": { - "@babel/runtime": ">=7.0.0" - }, "devDependencies": { "@babel/core": "~7.12.10", "@babel/plugin-transform-runtime": "~7.12.10", diff --git a/rollup.config.js b/rollup.config.js index 08a8cae4d..3cbea7f3c 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -33,6 +33,7 @@ const commonPlugins = [ replace({ preventAssignment: true, __VERSION__: version, + __TEST__: 'false', }) ] diff --git a/src/__tests__/libs/utils.test.ts b/src/__tests__/libs/utils.test.ts index bbae745ff..8fab30a7a 100644 --- a/src/__tests__/libs/utils.test.ts +++ b/src/__tests__/libs/utils.test.ts @@ -179,3 +179,11 @@ test('get element that not marked by micro-app', () => { test('coverage of isNull function', () => { expect(Utils.isNull(null)).toBeTruthy() }) + +test('coverage of isInvalidQuerySelectorKey', () => { + // @ts-ignore + window.__TEST__ = false + expect(Utils.isInvalidQuerySelectorKey('a&bc')).toBeTruthy() + // @ts-ignore + window.__TEST__ = true +}) diff --git a/src/__tests__/source/patch.test.ts b/src/__tests__/source/patch.test.ts index 6414ab25f..5a584c797 100644 --- a/src/__tests__/source/patch.test.ts +++ b/src/__tests__/source/patch.test.ts @@ -298,43 +298,32 @@ describe('source patch', () => { setAppName('test-app2') const fakerDoc = new Document() - // 以下覆盖Document原型方法this为空或this不是document的情况 - const createElement = Document.prototype.createElement - createElement.call(fakerDoc, 'div') - createElement.call('', 'div') - - const createElementNS = Document.prototype.createElementNS - createElementNS.call(fakerDoc, 'http://www.w3.org/1999/xhtml', 'svg') - createElementNS.call('', 'http://www.w3.org/1999/xhtml', 'svg') - - const createDocumentFragment = Document.prototype.createDocumentFragment - createDocumentFragment.call(fakerDoc) - createDocumentFragment.call('') - const querySelector = Document.prototype.querySelector querySelector.call(fakerDoc, 'div') - querySelector.call('', 'div') const querySelectorAll = Document.prototype.querySelectorAll querySelectorAll.call(fakerDoc, 'div') - querySelectorAll.call('', 'div') - clearAppName() // clear scoped - const getElementById = Document.prototype.getElementById - getElementById.call(fakerDoc, 'id') - getElementById.call('', 'id') + reslove(true) + }) + }) + }) - const getElementsByClassName = Document.prototype.getElementsByClassName - getElementsByClassName.call(fakerDoc, 'classname') - getElementsByClassName.call('', 'classname') + // 分支覆盖 - 错误的 querySelector key + test('coverage of error querySelector key', async () => { + const microappElement3 = document.createElement('micro-app') + microappElement3.setAttribute('name', 'test-app3') + microappElement3.setAttribute('url', `http://127.0.0.1:${ports.source_patch}/ssr-render/`) - const getElementsByTagName = Document.prototype.getElementsByTagName - getElementsByTagName.call(fakerDoc, 'div') - getElementsByTagName.call('', 'div') + appCon.appendChild(microappElement3) - const getElementsByName = Document.prototype.getElementsByName - getElementsByName.call(fakerDoc, 'name') - getElementsByName.call('', 'name') + await new Promise((reslove) => { + microappElement3.addEventListener('mounted', () => { + setAppName('test-app3') + document.getElementById('sd$fs') + document.getElementsByClassName('sd$fs') + document.getElementsByTagName('sd$fs') + document.getElementsByName('sd$fs') reslove(true) }) diff --git a/src/index.ts b/src/index.ts index b08ac50da..42cc1be68 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ -export { default as preFetch } from './prefetch' export { default } from './micro_app' +export { default as preFetch } from './prefetch' export { removeDomScope, pureCreateElement, version, setCurrentAppName } from './libs/utils' +export { EventCenterForMicroApp } from './interact' diff --git a/src/libs/utils.ts b/src/libs/utils.ts index e73d12ede..10fc254af 100644 --- a/src/libs/utils.ts +++ b/src/libs/utils.ts @@ -139,6 +139,11 @@ export function formatURL (url: string | null, appName: string | null = null): s } } +// export function formatName (name: string): string { +// if (!isString(name) || !name) return '' +// return name.replace(/(^\d+)|([^\w\d-_])/gi, '') +// } + /** * Get valid address, such as https://xxx/xx/xx.html to https://xxx/xx/ * @param url app.url @@ -314,3 +319,18 @@ export function cloneNode ( }) } } + +// is invalid key of querySelector +export function isInvalidQuerySelectorKey (key: string): boolean { + if (__TEST__) return !key || /(^\d)|([^\w\d-_$])/gi.test(key) + return !key || /(^\d)|([^\w\d-_\u4e00-\u9fa5])/gi.test(key) +} + +// unique element +export function isUniqueElement (key: string): boolean { + return ( + /^body$/i.test(key) || + /^head$/i.test(key) || + /^html$/i.test(key) + ) +} diff --git a/src/source/patch.ts b/src/source/patch.ts index e73448676..aaad5b809 100644 --- a/src/source/patch.ts +++ b/src/source/patch.ts @@ -8,6 +8,8 @@ import { logWarn, isPlainObject, isString, + isInvalidQuerySelectorKey, + isUniqueElement, } from '../libs/utils' import scopedCSS from './scoped_css' import { extractLinkFromHtml, foramtDynamicLink } from './links' @@ -289,9 +291,7 @@ export function patchElementPrototypeMethods (): void { */ function markElement (element: T): T { const appName = getCurrentAppName() - if (appName) { - element.__MICRO_APP_NAME__ = appName - } + appName && (element.__MICRO_APP_NAME__ = appName) return element } @@ -304,8 +304,7 @@ function patchDocument () { tagName: string, options?: ElementCreationOptions, ): HTMLElement { - const _this = this && rawDocument !== this ? this : rawDocument - const element = globalEnv.rawCreateElement.call(_this, tagName, options) + const element = globalEnv.rawCreateElement.call(this, tagName, options) return markElement(element) } @@ -314,38 +313,39 @@ function patchDocument () { name: string, options?: string | ElementCreationOptions, ): any { - const _this = this && rawDocument !== this ? this : rawDocument - const element = globalEnv.rawCreateElementNS.call(_this, namespaceURI, name, options) + const element = globalEnv.rawCreateElementNS.call(this, namespaceURI, name, options) return markElement(element) } Document.prototype.createDocumentFragment = function createDocumentFragment (): DocumentFragment { - const _this = this && rawDocument !== this ? this : rawDocument - const element = globalEnv.rawCreateDocumentFragment.call(_this) + const element = globalEnv.rawCreateDocumentFragment.call(this) return markElement(element) } // query element👇 function querySelector (this: Document, selectors: string): any { - /** - * The hijacking of queryselector should only occur on rawDocument, we should ignore document created by new DOMParser().parseFromString() - * see https://github.com/micro-zoe/micro-app/issues/56 - */ - if (this && rawDocument !== this) return globalEnv.rawQuerySelector.call(this, selectors) - const appName = getCurrentAppName() - if (!appName || selectors === 'head' || selectors === 'body' || selectors === 'html') { - return globalEnv.rawQuerySelector.call(rawDocument, selectors) + if ( + !appName || + !selectors || + isUniqueElement(selectors) || + // see https://github.com/micro-zoe/micro-app/issues/56 + rawDocument !== this + ) { + return globalEnv.rawQuerySelector.call(this, selectors) } return appInstanceMap.get(appName)?.container?.querySelector(selectors) ?? null } function querySelectorAll (this: Document, selectors: string): any { - if (this && rawDocument !== this) return globalEnv.rawQuerySelectorAll.call(this, selectors) - const appName = getCurrentAppName() - if (!appName || selectors === 'head' || selectors === 'body' || selectors === 'html') { - return globalEnv.rawQuerySelectorAll.call(rawDocument, selectors) + if ( + !appName || + !selectors || + isUniqueElement(selectors) || + rawDocument !== this + ) { + return globalEnv.rawQuerySelectorAll.call(this, selectors) } return appInstanceMap.get(appName)?.container?.querySelectorAll(selectors) ?? [] } @@ -353,47 +353,58 @@ function patchDocument () { Document.prototype.querySelector = querySelector Document.prototype.querySelectorAll = querySelectorAll - // querySelector does not support the beginning of a number Document.prototype.getElementById = function getElementById (key: string): HTMLElement | null { - const appName = getCurrentAppName() - if (!appName || /^\d/.test(key)) { - const _this = this && rawDocument !== this ? this : rawDocument - return globalEnv.rawGetElementById.call(_this, key) + if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) { + return globalEnv.rawGetElementById.call(this, key) + } + + try { + return querySelector.call(this, `#${key}`) + } catch { + return globalEnv.rawGetElementById.call(this, key) } - return querySelector.call(this, `#${key}`) } Document.prototype.getElementsByClassName = function getElementsByClassName (key: string): HTMLCollectionOf { - const appName = getCurrentAppName() - if (!appName || /^\d/.test(key)) { - const _this = this && rawDocument !== this ? this : rawDocument - return globalEnv.rawGetElementsByClassName.call(_this, key) + if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) { + return globalEnv.rawGetElementsByClassName.call(this, key) + } + + try { + return querySelectorAll.call(this, `.${key}`) + } catch { + return globalEnv.rawGetElementsByClassName.call(this, key) } - return querySelectorAll.call(this, `.${key}`) } Document.prototype.getElementsByTagName = function getElementsByTagName (key: string): HTMLCollectionOf { const appName = getCurrentAppName() if ( !appName || - /^body$/i.test(key) || - /^head$/i.test(key) || - /^html$/i.test(key) || + isUniqueElement(key) || + isInvalidQuerySelectorKey(key) || (!appInstanceMap.get(appName)?.inline && /^script$/i.test(key)) ) { - const _this = this && rawDocument !== this ? this : rawDocument - return globalEnv.rawGetElementsByTagName.call(_this, key) + return globalEnv.rawGetElementsByTagName.call(this, key) + } + + try { + return querySelectorAll.call(this, key) + } catch { + return globalEnv.rawGetElementsByTagName.call(this, key) } - return querySelectorAll.call(this, key) } Document.prototype.getElementsByName = function getElementsByName (key: string): NodeListOf { - const appName = getCurrentAppName() - if (!appName || /^\d/.test(key)) { - const _this = this && rawDocument !== this ? this : rawDocument - return globalEnv.rawGetElementsByName.call(_this, key) + if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) { + return globalEnv.rawGetElementsByName.call(this, key) + } + + try { + return querySelectorAll.call(this, `[name=${key}]`) + } catch { + return globalEnv.rawGetElementsByName.call(this, key) } - return querySelectorAll.call(this, `[name=${key}]`) } } diff --git a/typings/global.d.ts b/typings/global.d.ts index dfbea916d..e9abdda68 100644 --- a/typings/global.d.ts +++ b/typings/global.d.ts @@ -191,3 +191,7 @@ declare namespace JSX { } declare module '@micro-zoe/micro-app/polyfill/jsx-custom-event' + +declare const __DEV__: boolean + +declare const __TEST__: boolean