From daad2210e3c0045f91a3ecce800bd8c286562bbd Mon Sep 17 00:00:00 2001 From: yucongshuang Date: Fri, 29 May 2026 10:50:34 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E8=A1=A5=E5=85=A8=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=9A=84features=E4=BB=A5=E5=8F=8A=E7=BB=84=E4=BB=B6=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/hap-compiler/src/style/mediaquery.js | 2 +- packages/hap-compiler/src/template/index.js | 4 +- .../hap-compiler/src/template/validator.js | 20 ++++- packages/hap-packager/src/common/shared.js | 90 +++++++++++++++++-- 4 files changed, 102 insertions(+), 14 deletions(-) diff --git a/packages/hap-compiler/src/style/mediaquery.js b/packages/hap-compiler/src/style/mediaquery.js index 2c2f477c..ffc4d51e 100644 --- a/packages/hap-compiler/src/style/mediaquery.js +++ b/packages/hap-compiler/src/style/mediaquery.js @@ -137,7 +137,7 @@ const featureValidator = { if (sizeStr[0] === '"' || sizeStr[0] === "'") { sizeStr = sizeStr.slice(1, sizeStr.length - 1) } - const reg = /^(1|2|4|8|AUTO|FULL)x(1|2|4|8|AUTO|FULL)$/ + const reg = /^(1|2|4|8|AUTO|FULL)x(1|2|4|8|AUTO|FULL|N)$/ if (reg.test(sizeStr)) { return { value: sizeStr } } diff --git a/packages/hap-compiler/src/template/index.js b/packages/hap-compiler/src/template/index.js index a3c9d777..75ad00a8 100644 --- a/packages/hap-compiler/src/template/index.js +++ b/packages/hap-compiler/src/template/index.js @@ -256,7 +256,7 @@ function initParser(code, options, filePath) { const selfClosable = validator.isSupportedSelfClosing(tagName) if (selfClosing && !selfClosable) { colorconsole.error( - `${tagName}标签,禁止使用自闭合 ${filePath}@${token.location.line}:${token.location.col}` + `${tagName}标签,禁止使用自闭合 ${filePath} @${token.location.line}:${token.location.col}` ) } @@ -285,7 +285,7 @@ function initParser(code, options, filePath) { (pos !== parser.__m['pos'] && token.type === Tokenizer.START_TAG_TOKEN) ) { colorconsole.warn( - `${parser.__m['tagName']}标签要闭合,请遵循XML规范 ${filePath}@${parser.__m['pos']}` + `${parser.__m['tagName']}标签要闭合,请遵循XML规范 ${filePath} @${parser.__m['pos']}` ) parser.__m = {} } diff --git a/packages/hap-compiler/src/template/validator.js b/packages/hap-compiler/src/template/validator.js index 058d1234..0f04b77c 100644 --- a/packages/hap-compiler/src/template/validator.js +++ b/packages/hap-compiler/src/template/validator.js @@ -217,7 +217,7 @@ const tagNatives = { }, web: { atomic: true, - events: ['pagestart', 'pagefinish', 'titlereceive', 'error', 'message', 'progress'], + events: ['pagestart', 'pagefinish', 'titlereceive', 'error', 'message', 'progress', 'intercepturl'], attrs: { src: {}, trustedurl: {}, @@ -232,7 +232,8 @@ const tagNatives = { }, supportzoom: { enum: ['true', 'false'] - } + }, + intercepturl:{} } }, list: { @@ -603,6 +604,9 @@ const tagNatives = { empty: true, attrs: { src: {}, + loop: { + enum: ['true', 'false'] + }, muted: { enum: ['false', 'true'] }, @@ -623,6 +627,9 @@ const tagNatives = { playcount: {}, speed: { def: 1 + }, + 'object-fit': { + enum: ['contain', 'cover', 'fill', 'none', 'scale-down'] } }, events: [ @@ -634,7 +641,10 @@ const tagNatives = { 'seeking', 'seeked', 'timeupdate', - 'fullscreenchange' + 'fullscreenchange', + 'firstframe', + 'buffering', + 'error' ] }, camera: { @@ -866,6 +876,8 @@ const tagNatives = { }, progress: {}, speed: {}, + 'start-frame': {}, + 'end-frame': {}, loop: { enum: [true, false] }, @@ -876,7 +888,7 @@ const tagNatives = { enum: [`AUTOMATIC`, `HARDWARE`, `SOFTWARE`] } }, - events: ['complete', 'error', 'change'] + events: ['complete', 'error', 'change', 'loaded'] }, 'drawer-navigation': { parents: ['drawer'], diff --git a/packages/hap-packager/src/common/shared.js b/packages/hap-packager/src/common/shared.js index f9a55b15..6b5882bc 100644 --- a/packages/hap-packager/src/common/shared.js +++ b/packages/hap-packager/src/common/shared.js @@ -17,7 +17,11 @@ function frameworkInit() { // 基本名 base: 'system', // 扩展名 - ext: 'service' + ext: 'service', + // nearme新增扩展名 + nearme: 'nearme', + // hap扩展名 + hap: 'hap' }, // 保留的features,保持与runtime_config.xml同步 reservedFeatures: [], @@ -80,7 +84,14 @@ function frameworkInit() { 'nfc', 'uploadtask', 'downloadtask', - 'requesttask' + 'requesttask', + 'minormode', + 'nfc', + 'localconnection', + 'hostconnection', + 'permission', + 'audiolite', + 'page' ] const serviceFeatures = [ 'account', @@ -100,7 +111,10 @@ function frameworkInit() { 'wxaccount', 'wxpay', 'biometriverify', - 'texttoaudio' + 'texttoaudio', + 'oppoinneraccount', + 'simCalibration', + 'quickappservice' ] systemFeatures.forEach((feature) => { // system @@ -117,7 +131,7 @@ function frameworkInit() { }) // 卡片中支持的feature - const supportInCard = [ + const systemSupportInCard = [ 'share', 'prompt', 'vibrator', @@ -131,11 +145,73 @@ function frameworkInit() { 'calendar', 'package', 'app', - 'router' + 'router', + 'media', + 'cipher', + 'permission', + 'badge', + 'localconnection', + 'hostconnection', + 'audio', + 'audiolite', + 'barcode', + 'configuration', + 'model', + 'bluetooth' ] - supportInCard.forEach((feature) => { + systemSupportInCard.forEach((feature) => { global.framework.supportInCard.push(`${global.framework.module.base}.${feature}`) }) + const nearmeSupportInCard = [ + 'media', + 'history', + 'http', + 'shortcut', + 'stats', + 'router', + 'package', + 'device', + 'theme', + 'browser', + 'feedback', + 'navigator', + 'note', + 'miniprogram', + 'downloadtask', + 'sceneservice', + 'marketbook', + 'permission', + 'account', + 'applist', + 'contentresolver', + 'receiver', + 'settings', + 'preload', + 'logger', + 'network', + 'system', + 'nearby', + 'batchanimator' + ] + nearmeSupportInCard.forEach((feature) => { + global.framework.supportInCard.push(`${global.framework.module.nearme}.${feature}`) + }) + const serviceSupportInCard = [ + 'account', + 'push', + 'simCalibration', + 'oppoinneraccount' + ] + serviceSupportInCard.forEach((feature) => { + global.framework.supportInCard.push(`${global.framework.module.ext}.${feature}`) + }) + const hapSupportInCard = [ + 'io.MessageChannel', + 'sharedStorage' + ] + hapSupportInCard.forEach((feature) => { + global.framework.supportInCard.push(`${global.framework.module.hap}.${feature}`) + }) } /** @@ -197,7 +273,7 @@ function searchModuleImport(fileCont, options = {}) { function checkFeatureInCard(obj = {}) { Object.keys(obj).forEach((key) => { obj[key].features && - obj[key].features.every((item) => { + obj[key].features.forEach((item) => { if (global.framework.supportInCard.indexOf(item.name) === -1) { // 不支持的native模块 colorconsole.error( From 68a5b68e724b1714359daaf03a8f4cb4097a5c3b Mon Sep 17 00:00:00 2001 From: yucongshuang Date: Tue, 9 Jun 2026 16:10:38 +0800 Subject: [PATCH 2/2] =?UTF-8?q?watch=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=83=AD?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=97=B6=E6=96=B0=E8=B5=84=E6=BA=90=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E4=BF=AE=E6=94=B9=E5=90=8E=E7=9A=84=E8=B5=84=E6=BA=90?= =?UTF-8?q?=E9=9C=80=E5=A4=8D=E5=88=B6=E5=88=B0build=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/plugins/resource-plugin.js | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/packages/hap-packager/src/plugins/resource-plugin.js b/packages/hap-packager/src/plugins/resource-plugin.js index 83848530..17f9cfe0 100644 --- a/packages/hap-packager/src/plugins/resource-plugin.js +++ b/packages/hap-packager/src/plugins/resource-plugin.js @@ -238,15 +238,6 @@ ResourcePlugin.prototype.apply = function (compiler) { let runned = false compiler.hooks.emit.tapAsync('ResourcePlugin', function (compilation, callback) { - if (runned) { - setTimeout(() => { - // 此节点即可通知预览刷新,打 rpk 错误不显示在预览界面 - eventBus.emit(PACKAGER_BUILD_DONE) - // 必须在定时器中调用 callback - callback() - }, 0) - return - } runned = true const sourceDir = options.src const targetDir = options.dest @@ -330,6 +321,32 @@ ResourcePlugin.prototype.apply = function (compiler) { return true } }) + // watch 模式下增量构建:仅复制新增或变更的静态资源,保留 HMR 性能优化 + if (runned) { + pairs = pairs.filter((pair) => { + const { srcFile, destFile } = pair + if (compiler.modifiedFiles && compiler.modifiedFiles.has(srcFile)) { + return true + } + if (!fs.existsSync(destFile)) { + return true + } + try { + return fs.statSync(srcFile).mtimeMs > fs.statSync(destFile).mtimeMs + } catch (err) { + return true + } + }) + if (pairs.length === 0) { + setTimeout(() => { + // 此节点即可通知预览刷新,打 rpk 错误不显示在预览界面 + eventBus.emit(PACKAGER_BUILD_DONE) + // 必须在定时器中调用 callback + callback() + }, 0) + return + } + } const promises = pairs.map((pair) => { return new Promise((resolve, reject) => { const { srcFile, destFile } = pair