@weapp-vite/web 1.6.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +22 -0
  2. package/dist/compiler/wxml/compile.mjs +9 -33
  3. package/dist/compiler/wxml/compile.mjs.map +1 -1
  4. package/dist/compiler/wxml/dependency.mjs +9 -1
  5. package/dist/compiler/wxml/dependency.mjs.map +1 -1
  6. package/dist/compiler/wxml/prepare.mjs +43 -0
  7. package/dist/compiler/wxml/prepare.mjs.map +1 -0
  8. package/dist/css/wxss.mjs +2 -1
  9. package/dist/css/wxss.mjs.map +1 -1
  10. package/dist/plugin/assets.d.mts +1 -0
  11. package/dist/plugin/constants.mjs +4 -2
  12. package/dist/plugin/constants.mjs.map +1 -1
  13. package/dist/plugin/hostTypes.d.mts +75 -0
  14. package/dist/plugin/index.d.mts +2 -74
  15. package/dist/plugin/index.mjs +28 -16
  16. package/dist/plugin/index.mjs.map +1 -1
  17. package/dist/plugin/sfcHmr.mjs +38 -0
  18. package/dist/plugin/sfcHmr.mjs.map +1 -0
  19. package/dist/plugin/vueSfc.mjs +12 -9
  20. package/dist/plugin/vueSfc.mjs.map +1 -1
  21. package/dist/runtime/appStyle.mjs +25 -0
  22. package/dist/runtime/appStyle.mjs.map +1 -0
  23. package/dist/runtime/component/element.mjs +39 -19
  24. package/dist/runtime/component/element.mjs.map +1 -1
  25. package/dist/runtime/component/events.mjs +34 -3
  26. package/dist/runtime/component/events.mjs.map +1 -1
  27. package/dist/runtime/component/publicInstance.mjs +7 -3
  28. package/dist/runtime/component/publicInstance.mjs.map +1 -1
  29. package/dist/runtime/component/state.mjs +7 -0
  30. package/dist/runtime/component/state.mjs.map +1 -1
  31. package/dist/runtime/component/types.d.mts +2 -0
  32. package/dist/runtime/component/utils.mjs +23 -3
  33. package/dist/runtime/component/utils.mjs.map +1 -1
  34. package/dist/runtime/componentEvents.mjs +37 -0
  35. package/dist/runtime/componentEvents.mjs.map +1 -0
  36. package/dist/runtime/eventBinding.d.mts +1 -0
  37. package/dist/runtime/eventBinding.mjs +5 -2
  38. package/dist/runtime/eventBinding.mjs.map +1 -1
  39. package/dist/runtime/hostGlobals.d.mts +1 -0
  40. package/dist/runtime/legacyTemplate/dom.mjs +2 -7
  41. package/dist/runtime/legacyTemplate/dom.mjs.map +1 -1
  42. package/dist/runtime/nativeComponents/canvas/index.mjs +12 -3
  43. package/dist/runtime/nativeComponents/canvas/index.mjs.map +1 -1
  44. package/dist/runtime/nativeComponents/index.mjs +0 -1
  45. package/dist/runtime/nativeComponents/index.mjs.map +1 -1
  46. package/dist/runtime/nativeComponents/richText/index.mjs +2 -2
  47. package/dist/runtime/nativeComponents/richText/index.mjs.map +1 -1
  48. package/dist/runtime/pageLayout.d.mts +1 -0
  49. package/dist/runtime/polyfill/index.mjs +1 -1
  50. package/dist/runtime/polyfill/routeRuntime/options.d.mts +1 -0
  51. package/dist/runtime/polyfill/routeRuntime.d.mts +1 -1
  52. package/dist/runtime/polyfill/routeRuntime.mjs +5 -1
  53. package/dist/runtime/polyfill/routeRuntime.mjs.map +1 -1
  54. package/dist/runtime/renderContext.mjs +3 -2
  55. package/dist/runtime/renderContext.mjs.map +1 -1
  56. package/dist/runtime/wevu.d.mts +1 -0
  57. package/dist/runtime/wevu.mjs +2 -0
  58. package/dist/runtime/wevu.mjs.map +1 -1
  59. package/dist/shared/wxml.mjs +5 -1
  60. package/dist/shared/wxml.mjs.map +1 -1
  61. package/package.json +15 -13
  62. package/dist/runtime/nativeComponents/richText/helpers.mjs +0 -230
  63. package/dist/runtime/nativeComponents/richText/helpers.mjs.map +0 -1
package/README.md CHANGED
@@ -54,6 +54,28 @@ defineComponent('wv-hello-world', {
54
54
  document.body.innerHTML = '<wv-hello-world title="文档地址"></wv-hello-world>'
55
55
  ```
56
56
 
57
+ ## 应用样式与隔离
58
+
59
+ `app.vue` 的内联 `<style>`、`<style src="...">`,以及原生 `App` 入口对应的样式文件,共用应用样式注册链路。样式进入页面的 Shadow Root,不依赖向 `document.head` 注入 CSS 来穿透 Shadow DOM。
60
+
61
+ - 页面先应用 app 样式,再应用自身样式;两者保留独立的 stylesheet,局部样式开头的合法 `@import` 不会因 app 规则而失效,相同优先级时页面声明仍可覆盖 app 声明。
62
+ - 自定义组件默认隔离 app 的选择器。`options.styleIsolation` 为 `apply-shared` 或 `shared` 时接收 app 样式;未设置 `styleIsolation` 时,`options.addGlobalClass: true` 也可开启。显式 `isolated` 优先于 `addGlobalClass`。
63
+ - `page` 选择器只命中页面宿主,不会在共享样式的子组件上重新设置页面主题;页面限定不增加原有 `:host` 转换的选择器权重。CSS 自定义属性仍按浏览器规则继承,局部主题可以覆盖继承值。
64
+ - 应用样式更新与一次性的 `App()` 生命周期分开:HMR 可以修改、移除、重新添加样式,已挂载和后续挂载的消费方读取同一份最新状态;卸载时解除订阅。
65
+ - legacy 字符串模板保留节点时,事件监听器按绑定所有权复用;样式更新不会叠加监听器或丢失输入值与选区,方法、别名或捕获配置变化时替换旧绑定,移除后不再拦截事件。
66
+
67
+ 这些规则描述 app 样式的可见范围,不会取消 Shadow DOM,也不扩展页面样式向组件、组件样式向外传播的现有支持范围。
68
+
69
+ ## 组件事件与属性
70
+
71
+ - 自定义组件上的 `click`、`input` 等事件绑定只接收组件通过 `triggerEvent` 或 Vue `emit` 发出的事件,不会再被内部同名原生 DOM 事件额外触发。原生控件事件和 `tap` 等已有手势别名保持原有交互。
72
+ - 组件事件保留原始名称、大小写和 `detail`,并遵循显式的 `bubbles`、`composed` 选项。捕获、`catch` 与 `capture-catch` 先区分事件来源,再决定是否处理或停止传播,不会吞掉另一通道的原生事件。Vue SFC 处理函数接收 emit payload,原生 WXML 处理函数接收含 `detail` 的事件对象。
73
+ - DOM 宿主属性承载 props 输入,公开实例的方法表承载组件方法。两者同名时,Boolean、String、Number、Object、Array 和 Function props 不会被方法安装改写,模板和公开实例仍可调用对应方法。方法表优先级仅用于声明的 prop 冲突;没有此类冲突的普通实例方法仍支持显式赋值或自有访问器覆写。
74
+ - setup 方法安装采用完整快照,替换或移除方法不会写入 props。保留 setup 方法优先于同名静态方法的顺序;清空 setup 快照后恢复最新静态定义。普通自有字段、访问器和不可配置属性不由框架热更新覆盖。
75
+ - 父级 `setData` 的嵌套 Object / Array 路径更新只复制本批变更路径上的容器;显式提交整个对象或数组时,为该子树创建输入快照。原地修改后的同引用提交,以及新外层对象复用旧嵌套值的提交,都能更新子组件的深层投影和继续转发的输入。函数引用保持可调用,未提交的分支不复制,普通未变值不重复触发观察器;大对象增量更新优先使用具体路径,避免整棵已提交子树的复制成本。
76
+
77
+ 现有限制:`<script setup>` 的同节点同名事件捕获/冒泡处理器,以及 legacy 字符串模板中的同类组合,仍存在独立的处理器键冲突;该组合暂需使用不同层级的节点。这不属于上述原生事件与组件事件的来源隔离。
78
+
57
79
  ## 设备视口
58
80
 
59
81
  默认配置模拟小程序页面视口:移动宽度下铺满,浏览器宽度达到 600px 后使用 375px 居中容器。页面、导航栏、`fixed` 元素和 `rpx` 共用这一区域。
@@ -1,9 +1,9 @@
1
1
  import { RUNTIME_ID } from "../../plugin/constants.mjs";
2
- import { addDependency, createDependencyContext, warnCircularTemplate, warnReadTemplate } from "./dependency.mjs";
3
- import { buildNavigationBarAttrs, extractNavigationBarFromPageMeta } from "./navigation.mjs";
4
- import { parseWxml } from "./parser.mjs";
2
+ import { addDependency, collectDependencies, createDependencyContext, warnCircularTemplate, warnReadTemplate } from "./dependency.mjs";
3
+ import { buildNavigationBarAttrs } from "./navigation.mjs";
4
+ import { normalizeTemplatePath, shouldMarkWxsImport, toRelativeImport } from "./specialNodes.mjs";
5
+ import { prepareWxml } from "./prepare.mjs";
5
6
  import { renderer } from "./renderer.mjs";
6
- import { collectSpecialNodes, normalizeTemplatePath, shouldMarkWxsImport, toRelativeImport } from "./specialNodes.mjs";
7
7
  import { readFileSync } from "node:fs";
8
8
 
9
9
  //#region src/compiler/wxml/compile.ts
@@ -33,44 +33,20 @@ function compileWxml(options) {
33
33
  continue;
34
34
  }
35
35
  try {
36
- const result = compileWxml({
36
+ const result = prepareWxml({
37
37
  id: target,
38
38
  source,
39
39
  resolveTemplatePath: options.resolveTemplatePath,
40
- resolveWxsPath: options.resolveWxsPath,
41
- dependencyContext,
42
- expandDependencies: false
43
- });
44
- expandDependencyTree(result.dependencies, target);
40
+ resolveWxsPath: options.resolveWxsPath
41
+ }, dependencyContext);
42
+ expandDependencyTree(collectDependencies(result, dependencyContext), target);
45
43
  } catch (error) {
46
44
  if (error instanceof Error && error.message) warnings.push(`[web] 无法解析模板依赖: ${target} ${error.message}`);
47
45
  }
48
46
  dependencyContext.active.delete(target);
49
47
  }
50
48
  };
51
- let nodes = parseWxml(options.source);
52
- let navigationBarAttrs;
53
- if (options.navigationBar) {
54
- const extracted = extractNavigationBarFromPageMeta(nodes);
55
- nodes = extracted.nodes;
56
- if (extracted.warnings.length > 0) warnings.push(...extracted.warnings);
57
- navigationBarAttrs = extracted.attrs;
58
- }
59
- const templates = [];
60
- const includes = [];
61
- const imports = [];
62
- const wxs = [];
63
- const renderNodesList = collectSpecialNodes(nodes, {
64
- templates,
65
- includes,
66
- imports,
67
- wxs,
68
- wxsModules: /* @__PURE__ */ new Map(),
69
- warnings,
70
- sourceId: options.id,
71
- resolveTemplate: (raw) => options.resolveTemplatePath(raw, options.id),
72
- resolveWxs: (raw) => options.resolveWxsPath(raw, options.id)
73
- });
49
+ const { renderNodes: renderNodesList, navigationBarAttrs, templates, includes, imports, wxs } = prepareWxml(options, dependencyContext);
74
50
  if (options.navigationBar && options.navigationBar.config.navigationStyle !== "custom") {
75
51
  const attrs = buildNavigationBarAttrs(options.navigationBar.config, navigationBarAttrs);
76
52
  renderNodesList.unshift({
@@ -1 +1 @@
1
- {"version":3,"file":"compile.mjs","names":[],"sources":["../../../src/compiler/wxml/compile.ts"],"sourcesContent":["import type {\n ImportEntry,\n IncludeEntry,\n TemplateDefinition,\n WxmlCompileOptions,\n WxmlCompileResult,\n WxsEntry,\n} from './types'\n\nimport { readFileSync } from 'node:fs'\nimport { RUNTIME_ID } from '../../plugin/constants'\nimport { addDependency, createDependencyContext, warnCircularTemplate, warnReadTemplate } from './dependency'\nimport { buildNavigationBarAttrs, extractNavigationBarFromPageMeta } from './navigation'\nimport { parseWxml } from './parser'\nimport { renderer } from './renderer'\nimport { collectSpecialNodes, normalizeTemplatePath, shouldMarkWxsImport, toRelativeImport } from './specialNodes'\n\nconst WEB_TEMPLATE_QUERY = 'weapp-web-template'\n\nfunction appendTemplateQuery(pathname: string) {\n return `${pathname}${pathname.includes('?') ? '&' : '?'}${WEB_TEMPLATE_QUERY}`\n}\n\nexport function compileWxml(options: WxmlCompileOptions): WxmlCompileResult {\n const dependencyContext = options.dependencyContext ?? createDependencyContext()\n const expandDependencies = options.expandDependencies ?? !options.dependencyContext\n const warnings = dependencyContext.warnings\n\n const expandDependencyTree = (dependencies: string[], importer: string) => {\n for (const target of dependencies) {\n if (dependencyContext.active.has(target)) {\n warnCircularTemplate(dependencyContext, importer, target)\n continue\n }\n if (dependencyContext.visited.has(target)) {\n continue\n }\n dependencyContext.visited.add(target)\n dependencyContext.active.add(target)\n let source: string\n try {\n source = readFileSync(target, 'utf8')\n }\n catch {\n warnReadTemplate(dependencyContext, target)\n dependencyContext.active.delete(target)\n continue\n }\n try {\n const result = compileWxml({\n id: target,\n source,\n resolveTemplatePath: options.resolveTemplatePath,\n resolveWxsPath: options.resolveWxsPath,\n dependencyContext,\n expandDependencies: false,\n })\n expandDependencyTree(result.dependencies, target)\n }\n catch (error) {\n if (error instanceof Error && error.message) {\n warnings.push(`[web] 无法解析模板依赖: ${target} ${error.message}`)\n }\n }\n dependencyContext.active.delete(target)\n }\n }\n\n let nodes = parseWxml(options.source)\n let navigationBarAttrs: Record<string, string> | undefined\n if (options.navigationBar) {\n const extracted = extractNavigationBarFromPageMeta(nodes)\n nodes = extracted.nodes\n if (extracted.warnings.length > 0) {\n warnings.push(...extracted.warnings)\n }\n navigationBarAttrs = extracted.attrs\n }\n\n const templates: TemplateDefinition[] = []\n const includes: IncludeEntry[] = []\n const imports: ImportEntry[] = []\n const wxs: WxsEntry[] = []\n const wxsModules = new Map<string, string>()\n\n const renderNodesList = collectSpecialNodes(nodes, {\n templates,\n includes,\n imports,\n wxs,\n wxsModules,\n warnings,\n sourceId: options.id,\n resolveTemplate: (raw: string) => options.resolveTemplatePath(raw, options.id),\n resolveWxs: (raw: string) => options.resolveWxsPath(raw, options.id),\n })\n\n if (options.navigationBar && options.navigationBar.config.navigationStyle !== 'custom') {\n const attrs = buildNavigationBarAttrs(options.navigationBar.config, navigationBarAttrs)\n renderNodesList.unshift({\n type: 'element',\n name: 'weapp-navigation-bar',\n attribs: attrs,\n })\n }\n\n const importLines: string[] = [\n `import { html } from 'lit'`,\n `import { repeat } from 'lit/directives/repeat.js'`,\n `import { bindRuntimeEvent } from '${RUNTIME_ID}'`,\n ]\n const bodyLines: string[] = []\n const directDependencies: string[] = []\n\n for (const entry of imports) {\n const importPath = normalizeTemplatePath(toRelativeImport(options.id, entry.id))\n importLines.push(`import { templates as ${entry.importName} } from '${appendTemplateQuery(importPath)}'`)\n addDependency(entry.id, dependencyContext, directDependencies)\n }\n\n for (const entry of includes) {\n const importPath = normalizeTemplatePath(toRelativeImport(options.id, entry.id))\n importLines.push(`import { render as ${entry.importName} } from '${appendTemplateQuery(importPath)}'`)\n addDependency(entry.id, dependencyContext, directDependencies)\n }\n\n for (const entry of wxs) {\n if (entry.kind === 'src') {\n const baseImport = normalizeTemplatePath(toRelativeImport(options.id, entry.value))\n const importPath = shouldMarkWxsImport(entry.value)\n ? `${baseImport}?wxs`\n : baseImport\n importLines.push(`import ${entry.importName} from '${importPath}'`)\n addDependency(entry.value, dependencyContext, directDependencies)\n }\n }\n\n if (templates.length > 0 || imports.length > 0) {\n const templatePairs: string[] = []\n for (const entry of imports) {\n templatePairs.push(`...${entry.importName}`)\n }\n for (const template of templates) {\n const rendered = renderer.renderNodes(template.nodes, 'scope', '__wxs_modules', options.componentTags)\n templatePairs.push(`${JSON.stringify(template.name)}: (scope, ctx) => ${rendered}`)\n }\n bodyLines.push(`const __templates = { ${templatePairs.join(', ')} }`)\n }\n else {\n bodyLines.push(`const __templates = {}`)\n }\n\n if (wxs.length > 0) {\n bodyLines.push(`const __wxs_inline_cache = Object.create(null)`)\n bodyLines.push(`let __wxs_modules = {}`)\n const wxsMapEntries: string[] = []\n for (const entry of wxs) {\n if (entry.kind === 'inline') {\n const inlineCode = entry.value.trim()\n const cacheKey = JSON.stringify(entry.module)\n if (inlineCode) {\n bodyLines.push(`function ${entry.importName}(ctx) {`)\n bodyLines.push(` if (!__wxs_inline_cache[${cacheKey}]) {`)\n bodyLines.push(` __wxs_inline_cache[${cacheKey}] = ctx.createWxsModule(${JSON.stringify(inlineCode)}, ${JSON.stringify(options.id)})`)\n bodyLines.push(` }`)\n bodyLines.push(` return __wxs_inline_cache[${cacheKey}]`)\n bodyLines.push(`}`)\n }\n else {\n bodyLines.push(`function ${entry.importName}() { return {} }`)\n }\n wxsMapEntries.push(`${JSON.stringify(entry.module)}: ${entry.importName}(ctx)`)\n continue\n }\n wxsMapEntries.push(`${JSON.stringify(entry.module)}: ${entry.importName}`)\n }\n bodyLines.push(`function __resolveWxsModules(ctx) {`)\n bodyLines.push(` return { ${wxsMapEntries.join(', ')} }`)\n bodyLines.push(`}`)\n }\n else {\n bodyLines.push(`const __wxs_modules = {}`)\n }\n\n const includesRender = includes.map(entry => `${entry.importName}(scope, ctx)`)\n const renderContent = renderer.renderNodes(renderNodesList, 'scope', '__wxs_modules', options.componentTags)\n const contentExpr = includesRender.length > 0\n ? `[${[...includesRender, renderContent].join(', ')}]`\n : renderContent\n\n bodyLines.push(`export function render(scope, ctx) {`)\n if (wxs.length > 0) {\n bodyLines.push(` __wxs_modules = __resolveWxsModules(ctx)`)\n }\n bodyLines.push(` return ${contentExpr}`)\n bodyLines.push(`}`)\n bodyLines.push(`export const templates = __templates`)\n bodyLines.push(`export default render`)\n\n if (expandDependencies) {\n dependencyContext.visited.add(options.id)\n dependencyContext.active.add(options.id)\n expandDependencyTree(directDependencies, options.id)\n dependencyContext.active.delete(options.id)\n }\n\n const code = [...importLines, '', ...bodyLines].join('\\n')\n const dependencies = expandDependencies ? dependencyContext.dependencies : directDependencies\n return {\n code,\n dependencies,\n warnings: warnings.length > 0 ? warnings : undefined,\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"compile.mjs","names":[],"sources":["../../../src/compiler/wxml/compile.ts"],"sourcesContent":["import type { WxmlCompileOptions, WxmlCompileResult } from './types'\n\nimport { readFileSync } from 'node:fs'\nimport { RUNTIME_ID } from '../../plugin/constants'\nimport { addDependency, collectDependencies, createDependencyContext, warnCircularTemplate, warnReadTemplate } from './dependency'\nimport { buildNavigationBarAttrs } from './navigation'\nimport { prepareWxml } from './prepare'\nimport { renderer } from './renderer'\nimport { normalizeTemplatePath, shouldMarkWxsImport, toRelativeImport } from './specialNodes'\n\nconst WEB_TEMPLATE_QUERY = 'weapp-web-template'\n\nfunction appendTemplateQuery(pathname: string) {\n return `${pathname}${pathname.includes('?') ? '&' : '?'}${WEB_TEMPLATE_QUERY}`\n}\n\nexport function compileWxml(options: WxmlCompileOptions): WxmlCompileResult {\n const dependencyContext = options.dependencyContext ?? createDependencyContext()\n const expandDependencies = options.expandDependencies ?? !options.dependencyContext\n const warnings = dependencyContext.warnings\n\n const expandDependencyTree = (dependencies: string[], importer: string) => {\n for (const target of dependencies) {\n if (dependencyContext.active.has(target)) {\n warnCircularTemplate(dependencyContext, importer, target)\n continue\n }\n if (dependencyContext.visited.has(target)) {\n continue\n }\n dependencyContext.visited.add(target)\n dependencyContext.active.add(target)\n let source: string\n try {\n source = readFileSync(target, 'utf8')\n }\n catch {\n warnReadTemplate(dependencyContext, target)\n dependencyContext.active.delete(target)\n continue\n }\n try {\n const result = prepareWxml({\n id: target,\n source,\n resolveTemplatePath: options.resolveTemplatePath,\n resolveWxsPath: options.resolveWxsPath,\n }, dependencyContext)\n expandDependencyTree(collectDependencies(result, dependencyContext), target)\n }\n catch (error) {\n if (error instanceof Error && error.message) {\n warnings.push(`[web] 无法解析模板依赖: ${target} ${error.message}`)\n }\n }\n dependencyContext.active.delete(target)\n }\n }\n\n const {\n renderNodes: renderNodesList,\n navigationBarAttrs,\n templates,\n includes,\n imports,\n wxs,\n } = prepareWxml(options, dependencyContext)\n\n if (options.navigationBar && options.navigationBar.config.navigationStyle !== 'custom') {\n const attrs = buildNavigationBarAttrs(options.navigationBar.config, navigationBarAttrs)\n renderNodesList.unshift({\n type: 'element',\n name: 'weapp-navigation-bar',\n attribs: attrs,\n })\n }\n\n const importLines: string[] = [\n `import { html } from 'lit'`,\n `import { repeat } from 'lit/directives/repeat.js'`,\n `import { bindRuntimeEvent } from '${RUNTIME_ID}'`,\n ]\n const bodyLines: string[] = []\n const directDependencies: string[] = []\n\n for (const entry of imports) {\n const importPath = normalizeTemplatePath(toRelativeImport(options.id, entry.id))\n importLines.push(`import { templates as ${entry.importName} } from '${appendTemplateQuery(importPath)}'`)\n addDependency(entry.id, dependencyContext, directDependencies)\n }\n\n for (const entry of includes) {\n const importPath = normalizeTemplatePath(toRelativeImport(options.id, entry.id))\n importLines.push(`import { render as ${entry.importName} } from '${appendTemplateQuery(importPath)}'`)\n addDependency(entry.id, dependencyContext, directDependencies)\n }\n\n for (const entry of wxs) {\n if (entry.kind === 'src') {\n const baseImport = normalizeTemplatePath(toRelativeImport(options.id, entry.value))\n const importPath = shouldMarkWxsImport(entry.value)\n ? `${baseImport}?wxs`\n : baseImport\n importLines.push(`import ${entry.importName} from '${importPath}'`)\n addDependency(entry.value, dependencyContext, directDependencies)\n }\n }\n\n if (templates.length > 0 || imports.length > 0) {\n const templatePairs: string[] = []\n for (const entry of imports) {\n templatePairs.push(`...${entry.importName}`)\n }\n for (const template of templates) {\n const rendered = renderer.renderNodes(template.nodes, 'scope', '__wxs_modules', options.componentTags)\n templatePairs.push(`${JSON.stringify(template.name)}: (scope, ctx) => ${rendered}`)\n }\n bodyLines.push(`const __templates = { ${templatePairs.join(', ')} }`)\n }\n else {\n bodyLines.push(`const __templates = {}`)\n }\n\n if (wxs.length > 0) {\n bodyLines.push(`const __wxs_inline_cache = Object.create(null)`)\n bodyLines.push(`let __wxs_modules = {}`)\n const wxsMapEntries: string[] = []\n for (const entry of wxs) {\n if (entry.kind === 'inline') {\n const inlineCode = entry.value.trim()\n const cacheKey = JSON.stringify(entry.module)\n if (inlineCode) {\n bodyLines.push(`function ${entry.importName}(ctx) {`)\n bodyLines.push(` if (!__wxs_inline_cache[${cacheKey}]) {`)\n bodyLines.push(` __wxs_inline_cache[${cacheKey}] = ctx.createWxsModule(${JSON.stringify(inlineCode)}, ${JSON.stringify(options.id)})`)\n bodyLines.push(` }`)\n bodyLines.push(` return __wxs_inline_cache[${cacheKey}]`)\n bodyLines.push(`}`)\n }\n else {\n bodyLines.push(`function ${entry.importName}() { return {} }`)\n }\n wxsMapEntries.push(`${JSON.stringify(entry.module)}: ${entry.importName}(ctx)`)\n continue\n }\n wxsMapEntries.push(`${JSON.stringify(entry.module)}: ${entry.importName}`)\n }\n bodyLines.push(`function __resolveWxsModules(ctx) {`)\n bodyLines.push(` return { ${wxsMapEntries.join(', ')} }`)\n bodyLines.push(`}`)\n }\n else {\n bodyLines.push(`const __wxs_modules = {}`)\n }\n\n const includesRender = includes.map(entry => `${entry.importName}(scope, ctx)`)\n const renderContent = renderer.renderNodes(renderNodesList, 'scope', '__wxs_modules', options.componentTags)\n const contentExpr = includesRender.length > 0\n ? `[${[...includesRender, renderContent].join(', ')}]`\n : renderContent\n\n bodyLines.push(`export function render(scope, ctx) {`)\n if (wxs.length > 0) {\n bodyLines.push(` __wxs_modules = __resolveWxsModules(ctx)`)\n }\n bodyLines.push(` return ${contentExpr}`)\n bodyLines.push(`}`)\n bodyLines.push(`export const templates = __templates`)\n bodyLines.push(`export default render`)\n\n if (expandDependencies) {\n dependencyContext.visited.add(options.id)\n dependencyContext.active.add(options.id)\n expandDependencyTree(directDependencies, options.id)\n dependencyContext.active.delete(options.id)\n }\n\n const code = [...importLines, '', ...bodyLines].join('\\n')\n const dependencies = expandDependencies ? dependencyContext.dependencies : directDependencies\n return {\n code,\n dependencies,\n warnings: warnings.length > 0 ? warnings : undefined,\n }\n}\n"],"mappings":"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"}
@@ -16,6 +16,14 @@ function addDependency(value, context, direct) {
16
16
  direct?.push(value);
17
17
  }
18
18
  }
19
+ /** 依赖扫描完成分析后,按编译器的分组顺序登记直接依赖。 */
20
+ function collectDependencies(entries, context) {
21
+ const dependencies = [];
22
+ for (const entry of entries.imports) addDependency(entry.id, context, dependencies);
23
+ for (const entry of entries.includes) addDependency(entry.id, context, dependencies);
24
+ for (const entry of entries.wxs) if (entry.kind === "src") addDependency(entry.value, context, dependencies);
25
+ return dependencies;
26
+ }
19
27
  function warnReadTemplate(context, target) {
20
28
  context.warnings.push(`[web] 无法读取模板依赖: ${target}`);
21
29
  }
@@ -27,5 +35,5 @@ function warnCircularTemplate(context, from, target) {
27
35
  }
28
36
 
29
37
  //#endregion
30
- export { addDependency, createDependencyContext, warnCircularTemplate, warnReadTemplate };
38
+ export { addDependency, collectDependencies, createDependencyContext, warnCircularTemplate, warnReadTemplate };
31
39
  //# sourceMappingURL=dependency.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dependency.mjs","names":[],"sources":["../../../src/compiler/wxml/dependency.ts"],"sourcesContent":["import type { WxmlDependencyContext } from './types'\n\nexport function createDependencyContext(): WxmlDependencyContext {\n return {\n warnings: [],\n dependencies: [],\n dependencySet: new Set(),\n visited: new Set(),\n active: new Set(),\n circularWarnings: new Set(),\n }\n}\n\nexport function addDependency(\n value: string,\n context: WxmlDependencyContext,\n direct?: string[],\n) {\n if (!context.dependencySet.has(value)) {\n context.dependencySet.add(value)\n context.dependencies.push(value)\n direct?.push(value)\n }\n}\n\nexport function warnReadTemplate(context: WxmlDependencyContext, target: string) {\n context.warnings.push(`[web] 无法读取模板依赖: ${target}`)\n}\n\nexport function warnCircularTemplate(\n context: WxmlDependencyContext,\n from: string,\n target: string,\n) {\n const key = `${from}=>${target}`\n if (context.circularWarnings.has(key)) {\n return\n }\n context.circularWarnings.add(key)\n context.warnings.push(`[web] WXML 循环引用: ${from} -> ${target}`)\n}\n"],"mappings":";AAEA,SAAgB,0BAAiD;CAC/D,OAAO;EACL,UAAU,CAAC;EACX,cAAc,CAAC;EACf,+BAAe,IAAI,IAAI;EACvB,yBAAS,IAAI,IAAI;EACjB,wBAAQ,IAAI,IAAI;EAChB,kCAAkB,IAAI,IAAI;CAC5B;AACF;AAEA,SAAgB,cACd,OACA,SACA,QACA;CACA,IAAI,CAAC,QAAQ,cAAc,IAAI,KAAK,GAAG;EACrC,QAAQ,cAAc,IAAI,KAAK;EAC/B,QAAQ,aAAa,KAAK,KAAK;EAC/B,QAAQ,KAAK,KAAK;CACpB;AACF;AAEA,SAAgB,iBAAiB,SAAgC,QAAgB;CAC/E,QAAQ,SAAS,KAAK,mBAAmB,QAAQ;AACnD;AAEA,SAAgB,qBACd,SACA,MACA,QACA;CACA,MAAM,MAAM,GAAG,KAAK,IAAI;CACxB,IAAI,QAAQ,iBAAiB,IAAI,GAAG,GAClC;CAEF,QAAQ,iBAAiB,IAAI,GAAG;CAChC,QAAQ,SAAS,KAAK,oBAAoB,KAAK,MAAM,QAAQ;AAC/D"}
1
+ {"version":3,"file":"dependency.mjs","names":[],"sources":["../../../src/compiler/wxml/dependency.ts"],"sourcesContent":["import type { ImportEntry, IncludeEntry, WxmlDependencyContext, WxsEntry } from './types'\n\nexport function createDependencyContext(): WxmlDependencyContext {\n return {\n warnings: [],\n dependencies: [],\n dependencySet: new Set(),\n visited: new Set(),\n active: new Set(),\n circularWarnings: new Set(),\n }\n}\n\nexport function addDependency(\n value: string,\n context: WxmlDependencyContext,\n direct?: string[],\n) {\n if (!context.dependencySet.has(value)) {\n context.dependencySet.add(value)\n context.dependencies.push(value)\n direct?.push(value)\n }\n}\n\n/** 依赖扫描完成分析后,按编译器的分组顺序登记直接依赖。 */\nexport function collectDependencies(\n entries: { imports: ImportEntry[], includes: IncludeEntry[], wxs: WxsEntry[] },\n context: WxmlDependencyContext,\n) {\n const dependencies: string[] = []\n for (const entry of entries.imports) {\n addDependency(entry.id, context, dependencies)\n }\n for (const entry of entries.includes) {\n addDependency(entry.id, context, dependencies)\n }\n for (const entry of entries.wxs) {\n if (entry.kind === 'src') {\n addDependency(entry.value, context, dependencies)\n }\n }\n return dependencies\n}\n\nexport function warnReadTemplate(context: WxmlDependencyContext, target: string) {\n context.warnings.push(`[web] 无法读取模板依赖: ${target}`)\n}\n\nexport function warnCircularTemplate(\n context: WxmlDependencyContext,\n from: string,\n target: string,\n) {\n const key = `${from}=>${target}`\n if (context.circularWarnings.has(key)) {\n return\n }\n context.circularWarnings.add(key)\n context.warnings.push(`[web] WXML 循环引用: ${from} -> ${target}`)\n}\n"],"mappings":";AAEA,SAAgB,0BAAiD;CAC/D,OAAO;EACL,UAAU,CAAC;EACX,cAAc,CAAC;EACf,+BAAe,IAAI,IAAI;EACvB,yBAAS,IAAI,IAAI;EACjB,wBAAQ,IAAI,IAAI;EAChB,kCAAkB,IAAI,IAAI;CAC5B;AACF;AAEA,SAAgB,cACd,OACA,SACA,QACA;CACA,IAAI,CAAC,QAAQ,cAAc,IAAI,KAAK,GAAG;EACrC,QAAQ,cAAc,IAAI,KAAK;EAC/B,QAAQ,aAAa,KAAK,KAAK;EAC/B,QAAQ,KAAK,KAAK;CACpB;AACF;;AAGA,SAAgB,oBACd,SACA,SACA;CACA,MAAM,eAAyB,CAAC;CAChC,KAAK,MAAM,SAAS,QAAQ,SAC1B,cAAc,MAAM,IAAI,SAAS,YAAY;CAE/C,KAAK,MAAM,SAAS,QAAQ,UAC1B,cAAc,MAAM,IAAI,SAAS,YAAY;CAE/C,KAAK,MAAM,SAAS,QAAQ,KAC1B,IAAI,MAAM,SAAS,OACjB,cAAc,MAAM,OAAO,SAAS,YAAY;CAGpD,OAAO;AACT;AAEA,SAAgB,iBAAiB,SAAgC,QAAgB;CAC/E,QAAQ,SAAS,KAAK,mBAAmB,QAAQ;AACnD;AAEA,SAAgB,qBACd,SACA,MACA,QACA;CACA,MAAM,MAAM,GAAG,KAAK,IAAI;CACxB,IAAI,QAAQ,iBAAiB,IAAI,GAAG,GAClC;CAEF,QAAQ,iBAAiB,IAAI,GAAG;CAChC,QAAQ,SAAS,KAAK,oBAAoB,KAAK,MAAM,QAAQ;AAC/D"}
@@ -0,0 +1,43 @@
1
+ import { extractNavigationBarFromPageMeta } from "./navigation.mjs";
2
+ import { parseWxml } from "./parser.mjs";
3
+ import { collectSpecialNodes } from "./specialNodes.mjs";
4
+
5
+ //#region src/compiler/wxml/prepare.ts
6
+ /** 共享模板分析阶段,依赖扫描复用其结果而不生成渲染代码。 */
7
+ function prepareWxml(options, dependencyContext) {
8
+ const warnings = dependencyContext.warnings;
9
+ let nodes = parseWxml(options.source);
10
+ let navigationBarAttrs;
11
+ if (options.navigationBar) {
12
+ const extracted = extractNavigationBarFromPageMeta(nodes);
13
+ nodes = extracted.nodes;
14
+ if (extracted.warnings.length > 0) warnings.push(...extracted.warnings);
15
+ navigationBarAttrs = extracted.attrs;
16
+ }
17
+ const templates = [];
18
+ const includes = [];
19
+ const imports = [];
20
+ const wxs = [];
21
+ return {
22
+ renderNodes: collectSpecialNodes(nodes, {
23
+ templates,
24
+ includes,
25
+ imports,
26
+ wxs,
27
+ wxsModules: /* @__PURE__ */ new Map(),
28
+ warnings,
29
+ sourceId: options.id,
30
+ resolveTemplate: (raw) => options.resolveTemplatePath(raw, options.id),
31
+ resolveWxs: (raw) => options.resolveWxsPath(raw, options.id)
32
+ }),
33
+ navigationBarAttrs,
34
+ templates,
35
+ includes,
36
+ imports,
37
+ wxs
38
+ };
39
+ }
40
+
41
+ //#endregion
42
+ export { prepareWxml };
43
+ //# sourceMappingURL=prepare.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepare.mjs","names":[],"sources":["../../../src/compiler/wxml/prepare.ts"],"sourcesContent":["import type {\n ImportEntry,\n IncludeEntry,\n TemplateDefinition,\n WxmlCompileOptions,\n WxmlDependencyContext,\n WxsEntry,\n} from './types'\nimport { extractNavigationBarFromPageMeta } from './navigation'\nimport { parseWxml } from './parser'\nimport { collectSpecialNodes } from './specialNodes'\n\n/** 共享模板分析阶段,依赖扫描复用其结果而不生成渲染代码。 */\nexport function prepareWxml(options: WxmlCompileOptions, dependencyContext: WxmlDependencyContext) {\n const warnings = dependencyContext.warnings\n let nodes = parseWxml(options.source)\n let navigationBarAttrs: Record<string, string> | undefined\n if (options.navigationBar) {\n const extracted = extractNavigationBarFromPageMeta(nodes)\n nodes = extracted.nodes\n if (extracted.warnings.length > 0) {\n warnings.push(...extracted.warnings)\n }\n navigationBarAttrs = extracted.attrs\n }\n\n const templates: TemplateDefinition[] = []\n const includes: IncludeEntry[] = []\n const imports: ImportEntry[] = []\n const wxs: WxsEntry[] = []\n const renderNodes = collectSpecialNodes(nodes, {\n templates,\n includes,\n imports,\n wxs,\n wxsModules: new Map<string, string>(),\n warnings,\n sourceId: options.id,\n resolveTemplate: (raw: string) => options.resolveTemplatePath(raw, options.id),\n resolveWxs: (raw: string) => options.resolveWxsPath(raw, options.id),\n })\n\n return { renderNodes, navigationBarAttrs, templates, includes, imports, wxs }\n}\n"],"mappings":";;;;;;AAaA,SAAgB,YAAY,SAA6B,mBAA0C;CACjG,MAAM,WAAW,kBAAkB;CACnC,IAAI,QAAQ,UAAU,QAAQ,MAAM;CACpC,IAAI;CACJ,IAAI,QAAQ,eAAe;EACzB,MAAM,YAAY,iCAAiC,KAAK;EACxD,QAAQ,UAAU;EAClB,IAAI,UAAU,SAAS,SAAS,GAC9B,SAAS,KAAK,GAAG,UAAU,QAAQ;EAErC,qBAAqB,UAAU;CACjC;CAEA,MAAM,YAAkC,CAAC;CACzC,MAAM,WAA2B,CAAC;CAClC,MAAM,UAAyB,CAAC;CAChC,MAAM,MAAkB,CAAC;CAazB,OAAO;EAAE,aAZW,oBAAoB,OAAO;GAC7C;GACA;GACA;GACA;GACA,4BAAY,IAAI,IAAoB;GACpC;GACA,UAAU,QAAQ;GAClB,kBAAkB,QAAgB,QAAQ,oBAAoB,KAAK,QAAQ,EAAE;GAC7E,aAAa,QAAgB,QAAQ,eAAe,KAAK,QAAQ,EAAE;EACrE,CAEmB;EAAG;EAAoB;EAAW;EAAU;EAAS;CAAI;AAC9E"}
package/dist/css/wxss.mjs CHANGED
@@ -5,6 +5,7 @@ import selectorParser from "postcss-selector-parser";
5
5
  //#region src/css/wxss.ts
6
6
  const RPX_RE = /(-?(?:\d+(?:\.\d+)?|\.\d+))rpx/gi;
7
7
  const SAFE_AREA_ENV_RE = /env\(\s*safe-area-inset-(top|right|bottom|left)(?:\s*,[^)]*)?\)/gi;
8
+ const PAGE_HOST_SELECTOR = selectorParser().astSync(":host(:where([data-weapp-page-active]))").nodes[0].nodes[0];
8
9
  function isDeepPseudo(pseudo) {
9
10
  return pseudo.value === ":deep" || pseudo.value === "::v-deep";
10
11
  }
@@ -23,7 +24,7 @@ function transformNativeTags(selector) {
23
24
  selector.walkTags((tag) => {
24
25
  if (tag.parent?.type === "selector" && tag.parent.parent?.type === "pseudo" && tag.parent.parent.value === "::part") return;
25
26
  if (tag.value === "page") {
26
- tag.replaceWith(selectorParser.pseudo({ value: ":host" }));
27
+ tag.replaceWith(PAGE_HOST_SELECTOR.clone());
27
28
  return;
28
29
  }
29
30
  const webTag = resolveNativeComponentWebTag(tag.value);
@@ -1 +1 @@
1
- {"version":3,"file":"wxss.mjs","names":[],"sources":["../../src/css/wxss.ts"],"sourcesContent":["import postcss from 'postcss'\nimport selectorParser from 'postcss-selector-parser'\nimport { resolveNativeComponentWebTag } from '../shared/nativeComponents'\n\nexport interface WxssTransformOptions {\n /**\n * 1rpx 对应的 CSS 像素数。\n * 默认值近似于 750rpx 设计稿在 375px 屏幕上的换算。\n */\n pxPerRpx?: number\n /**\n * rpx 换算的设计宽度。传入后会把 rpx 转为\n * `calc(var(--rpx) * N)` 以实现响应式缩放。\n */\n designWidth?: number\n /**\n * 用于存储运行时 rpx 大小的 CSS 变量名。\n * @default \"--rpx\"\n */\n rpxVar?: string\n}\n\nexport interface WxssTransformResult {\n css: string\n}\n\nconst RPX_RE = /(-?(?:\\d+(?:\\.\\d+)?|\\.\\d+))rpx/gi\nconst SAFE_AREA_ENV_RE = /env\\(\\s*safe-area-inset-(top|right|bottom|left)(?:\\s*,[^)]*)?\\)/gi\n\nfunction isDeepPseudo(pseudo: selectorParser.Pseudo) {\n return pseudo.value === ':deep' || pseudo.value === '::v-deep'\n}\n\nfunction flattenDeepPseudos(selector: selectorParser.Selector) {\n selector.walkPseudos((pseudo) => {\n if (!isDeepPseudo(pseudo)) {\n return\n }\n const nestedSelector = pseudo.nodes?.[0]\n if (nestedSelector && nestedSelector.nodes.length > 0) {\n pseudo.replaceWith(...nestedSelector.nodes.map(node => node.clone()))\n return\n }\n pseudo.remove()\n })\n}\n\nfunction transformNativeTags(selector: selectorParser.Selector) {\n selector.walkTags((tag) => {\n if (tag.parent?.type === 'selector' && tag.parent.parent?.type === 'pseudo' && tag.parent.parent.value === '::part') {\n return\n }\n if (tag.value === 'page') {\n tag.replaceWith(selectorParser.pseudo({ value: ':host' }))\n return\n }\n const webTag = resolveNativeComponentWebTag(tag.value)\n if (webTag) {\n tag.value = webTag\n }\n })\n}\n\nfunction createPartPseudo(className: string) {\n return selectorParser.pseudo({\n value: '::part',\n nodes: [selectorParser.selector({\n value: '',\n nodes: [selectorParser.tag({ value: className })],\n })],\n })\n}\n\nfunction createVirtualHostPartSelector(source: selectorParser.Selector) {\n const selector = source.clone()\n let deepPseudo: selectorParser.Pseudo | undefined\n selector.walkPseudos((pseudo) => {\n if (!deepPseudo && isDeepPseudo(pseudo)) {\n deepPseudo = pseudo\n }\n })\n if (!deepPseudo || deepPseudo.parent?.type !== 'selector') {\n return undefined\n }\n\n const parent = deepPseudo.parent\n const pseudoIndex = parent.nodes.indexOf(deepPseudo)\n const nestedNodes = deepPseudo.nodes?.[0]?.nodes ?? []\n const nestedTargetClass = nestedNodes.find(node => node.type === 'class')?.value\n let targetStart = pseudoIndex\n if (nestedNodes.length > 0) {\n deepPseudo.replaceWith(...nestedNodes.map(node => node.clone()))\n }\n else {\n deepPseudo.remove()\n while (parent.nodes[targetStart]?.type === 'combinator') {\n targetStart += 1\n }\n }\n\n let targetEnd = targetStart\n while (targetEnd + 1 < parent.nodes.length && parent.nodes[targetEnd + 1]?.type !== 'combinator') {\n targetEnd += 1\n }\n if (targetStart >= parent.nodes.length || targetEnd < parent.nodes.length - 1) {\n return undefined\n }\n\n const targetNodes = parent.nodes.slice(targetStart, targetEnd + 1)\n const targetClass = nestedTargetClass\n ?? targetNodes.find(node => node.type === 'class')?.value\n const targetNode = parent.nodes[targetEnd]!\n if (!targetClass) {\n return undefined\n }\n\n const firstTargetPseudo = targetNodes.find(node => node.type === 'pseudo')\n if (firstTargetPseudo?.value.startsWith(':') && !firstTargetPseudo.value.startsWith('::')) {\n return undefined\n }\n if (firstTargetPseudo) {\n parent.insertBefore(firstTargetPseudo, createPartPseudo(targetClass))\n }\n else {\n parent.insertAfter(targetNode, createPartPseudo(targetClass))\n }\n flattenDeepPseudos(selector)\n transformNativeTags(selector)\n return selector\n}\n\nfunction transformWxssSelector(selector: string) {\n const root = selectorParser().astSync(selector)\n const output: string[] = []\n for (const sourceSelector of root.nodes) {\n const partSelector = createVirtualHostPartSelector(sourceSelector)\n const flatSelector = sourceSelector.clone()\n flattenDeepPseudos(flatSelector)\n transformNativeTags(flatSelector)\n output.push(flatSelector.toString())\n if (partSelector) {\n output.push(partSelector.toString())\n }\n }\n return output.join(',\\n')\n}\n\nfunction transformWxssRoot(root: postcss.Root, options?: WxssTransformOptions) {\n const rpxVar = options?.rpxVar ?? '--rpx'\n const useVariable = options?.pxPerRpx === undefined\n || (typeof options.designWidth === 'number' && Number.isFinite(options.designWidth))\n const ratio = options?.pxPerRpx ?? 0.5\n root.walkRules((rule) => {\n if (rule.selector) {\n rule.selector = transformWxssSelector(rule.selector)\n }\n })\n root.walkDecls((declaration) => {\n declaration.value = declaration.value\n .replace(\n SAFE_AREA_ENV_RE,\n (_, side: string) => `var(--weapp-safe-area-inset-${side})`,\n )\n .replace(RPX_RE, (_, value: string) => {\n const numeric = Number.parseFloat(value)\n if (useVariable) {\n return `calc(var(${rpxVar}) * ${numeric})`\n }\n const converted = Math.round(numeric * ratio * 1000) / 1000\n return `${converted}px`\n })\n })\n}\n\nexport function createWxssPostcssPlugin(options?: WxssTransformOptions) {\n return {\n postcssPlugin: 'weapp-vite-web-wxss',\n Once(root: postcss.Root) {\n transformWxssRoot(root, options)\n },\n }\n}\n\nexport function transformWxssToCss(source: string, options?: WxssTransformOptions): WxssTransformResult {\n const root = postcss.parse(source)\n transformWxssRoot(root, options)\n return {\n css: root.toString(),\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"wxss.mjs","names":[],"sources":["../../src/css/wxss.ts"],"sourcesContent":["import postcss from 'postcss'\nimport selectorParser from 'postcss-selector-parser'\nimport { resolveNativeComponentWebTag } from '../shared/nativeComponents'\n\nexport interface WxssTransformOptions {\n /**\n * 1rpx 对应的 CSS 像素数。\n * 默认值近似于 750rpx 设计稿在 375px 屏幕上的换算。\n */\n pxPerRpx?: number\n /**\n * rpx 换算的设计宽度。传入后会把 rpx 转为\n * `calc(var(--rpx) * N)` 以实现响应式缩放。\n */\n designWidth?: number\n /**\n * 用于存储运行时 rpx 大小的 CSS 变量名。\n * @default \"--rpx\"\n */\n rpxVar?: string\n}\n\nexport interface WxssTransformResult {\n css: string\n}\n\nconst RPX_RE = /(-?(?:\\d+(?:\\.\\d+)?|\\.\\d+))rpx/gi\nconst SAFE_AREA_ENV_RE = /env\\(\\s*safe-area-inset-(top|right|bottom|left)(?:\\s*,[^)]*)?\\)/gi\nconst PAGE_HOST_SELECTOR = selectorParser().astSync(':host(:where([data-weapp-page-active]))').nodes[0]!.nodes[0]!\n\nfunction isDeepPseudo(pseudo: selectorParser.Pseudo) {\n return pseudo.value === ':deep' || pseudo.value === '::v-deep'\n}\n\nfunction flattenDeepPseudos(selector: selectorParser.Selector) {\n selector.walkPseudos((pseudo) => {\n if (!isDeepPseudo(pseudo)) {\n return\n }\n const nestedSelector = pseudo.nodes?.[0]\n if (nestedSelector && nestedSelector.nodes.length > 0) {\n pseudo.replaceWith(...nestedSelector.nodes.map(node => node.clone()))\n return\n }\n pseudo.remove()\n })\n}\n\nfunction transformNativeTags(selector: selectorParser.Selector) {\n selector.walkTags((tag) => {\n if (tag.parent?.type === 'selector' && tag.parent.parent?.type === 'pseudo' && tag.parent.parent.value === '::part') {\n return\n }\n if (tag.value === 'page') {\n tag.replaceWith(PAGE_HOST_SELECTOR.clone())\n return\n }\n const webTag = resolveNativeComponentWebTag(tag.value)\n if (webTag) {\n tag.value = webTag\n }\n })\n}\n\nfunction createPartPseudo(className: string) {\n return selectorParser.pseudo({\n value: '::part',\n nodes: [selectorParser.selector({\n value: '',\n nodes: [selectorParser.tag({ value: className })],\n })],\n })\n}\n\nfunction createVirtualHostPartSelector(source: selectorParser.Selector) {\n const selector = source.clone()\n let deepPseudo: selectorParser.Pseudo | undefined\n selector.walkPseudos((pseudo) => {\n if (!deepPseudo && isDeepPseudo(pseudo)) {\n deepPseudo = pseudo\n }\n })\n if (!deepPseudo || deepPseudo.parent?.type !== 'selector') {\n return undefined\n }\n\n const parent = deepPseudo.parent\n const pseudoIndex = parent.nodes.indexOf(deepPseudo)\n const nestedNodes = deepPseudo.nodes?.[0]?.nodes ?? []\n const nestedTargetClass = nestedNodes.find(node => node.type === 'class')?.value\n let targetStart = pseudoIndex\n if (nestedNodes.length > 0) {\n deepPseudo.replaceWith(...nestedNodes.map(node => node.clone()))\n }\n else {\n deepPseudo.remove()\n while (parent.nodes[targetStart]?.type === 'combinator') {\n targetStart += 1\n }\n }\n\n let targetEnd = targetStart\n while (targetEnd + 1 < parent.nodes.length && parent.nodes[targetEnd + 1]?.type !== 'combinator') {\n targetEnd += 1\n }\n if (targetStart >= parent.nodes.length || targetEnd < parent.nodes.length - 1) {\n return undefined\n }\n\n const targetNodes = parent.nodes.slice(targetStart, targetEnd + 1)\n const targetClass = nestedTargetClass\n ?? targetNodes.find(node => node.type === 'class')?.value\n const targetNode = parent.nodes[targetEnd]!\n if (!targetClass) {\n return undefined\n }\n\n const firstTargetPseudo = targetNodes.find(node => node.type === 'pseudo')\n if (firstTargetPseudo?.value.startsWith(':') && !firstTargetPseudo.value.startsWith('::')) {\n return undefined\n }\n if (firstTargetPseudo) {\n parent.insertBefore(firstTargetPseudo, createPartPseudo(targetClass))\n }\n else {\n parent.insertAfter(targetNode, createPartPseudo(targetClass))\n }\n flattenDeepPseudos(selector)\n transformNativeTags(selector)\n return selector\n}\n\nfunction transformWxssSelector(selector: string) {\n const root = selectorParser().astSync(selector)\n const output: string[] = []\n for (const sourceSelector of root.nodes) {\n const partSelector = createVirtualHostPartSelector(sourceSelector)\n const flatSelector = sourceSelector.clone()\n flattenDeepPseudos(flatSelector)\n transformNativeTags(flatSelector)\n output.push(flatSelector.toString())\n if (partSelector) {\n output.push(partSelector.toString())\n }\n }\n return output.join(',\\n')\n}\n\nfunction transformWxssRoot(root: postcss.Root, options?: WxssTransformOptions) {\n const rpxVar = options?.rpxVar ?? '--rpx'\n const useVariable = options?.pxPerRpx === undefined\n || (typeof options.designWidth === 'number' && Number.isFinite(options.designWidth))\n const ratio = options?.pxPerRpx ?? 0.5\n root.walkRules((rule) => {\n if (rule.selector) {\n rule.selector = transformWxssSelector(rule.selector)\n }\n })\n root.walkDecls((declaration) => {\n declaration.value = declaration.value\n .replace(\n SAFE_AREA_ENV_RE,\n (_, side: string) => `var(--weapp-safe-area-inset-${side})`,\n )\n .replace(RPX_RE, (_, value: string) => {\n const numeric = Number.parseFloat(value)\n if (useVariable) {\n return `calc(var(${rpxVar}) * ${numeric})`\n }\n const converted = Math.round(numeric * ratio * 1000) / 1000\n return `${converted}px`\n })\n })\n}\n\nexport function createWxssPostcssPlugin(options?: WxssTransformOptions) {\n return {\n postcssPlugin: 'weapp-vite-web-wxss',\n Once(root: postcss.Root) {\n transformWxssRoot(root, options)\n },\n }\n}\n\nexport function transformWxssToCss(source: string, options?: WxssTransformOptions): WxssTransformResult {\n const root = postcss.parse(source)\n transformWxssRoot(root, options)\n return {\n css: root.toString(),\n }\n}\n"],"mappings":"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"}
@@ -3,4 +3,5 @@ import { IncomingMessage, ServerResponse } from "node:http";
3
3
  type WebAssetNext = (error?: unknown) => void;
4
4
  export declare function createWebAssetMiddleware(srcRoot: string): (request: IncomingMessage, response: ServerResponse, next: WebAssetNext) => void;
5
5
  //#endregion
6
+ export {};
6
7
  //# sourceMappingURL=assets.d.mts.map
@@ -1,3 +1,5 @@
1
+ import { WEAPP_VITE_WEB_AUTO_ROUTES_RESOLVED_MODULE_ID, WEAPP_VITE_WEB_ENTRY_RESOLVED_MODULE_ID } from "@weapp-core/constants";
2
+
1
3
  //#region src/plugin/constants.ts
2
4
  const SCRIPT_EXTS = [
3
5
  ".vue",
@@ -37,10 +39,10 @@ const WXS_RESOLVE_EXTS = [
37
39
  ".ts",
38
40
  ".js"
39
41
  ];
40
- const ENTRY_ID = "\0@weapp-vite/web/entry";
42
+ const ENTRY_ID = WEAPP_VITE_WEB_ENTRY_RESOLVED_MODULE_ID;
41
43
  const RUNTIME_ID = "/@weapp-vite/web/runtime";
42
44
  const AUTO_ROUTES_ID = "weapp-vite/auto-routes";
43
- const RESOLVED_AUTO_ROUTES_ID = "\0@weapp-vite/web/auto-routes";
45
+ const RESOLVED_AUTO_ROUTES_ID = WEAPP_VITE_WEB_AUTO_ROUTES_RESOLVED_MODULE_ID;
44
46
  const TEMPLATE_QUERY = "weapp-web-template";
45
47
  const STYLE_QUERY = "weapp-web-style";
46
48
  const SFC_TEMPLATE_QUERY = "weapp-web-sfc-template";
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","names":[],"sources":["../../src/plugin/constants.ts"],"sourcesContent":["export const SCRIPT_EXTS = ['.vue', '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\nexport const STYLE_EXTS = ['.wxss', '.scss', '.less', '.css']\nexport const TRANSFORM_STYLE_EXTS = ['.wxss']\nexport const TEMPLATE_EXTS = ['.wxml', '.axml', '.swan', '.ttml', '.qml', '.ksml', '.xhsml', '.html']\nexport const WXS_EXTS = ['.wxs', '.wxs.ts', '.wxs.js']\nexport const WXS_RESOLVE_EXTS = ['.wxs', '.wxs.ts', '.wxs.js', '.ts', '.js']\n\nexport const ENTRY_ID = '\\0@weapp-vite/web/entry'\nexport const RUNTIME_ID = '/@weapp-vite/web/runtime'\nexport const AUTO_ROUTES_ID = 'weapp-vite/auto-routes'\nexport const RESOLVED_AUTO_ROUTES_ID = '\\0@weapp-vite/web/auto-routes'\nexport const TEMPLATE_QUERY = 'weapp-web-template'\nexport const STYLE_QUERY = 'weapp-web-style'\nexport const SFC_TEMPLATE_QUERY = 'weapp-web-sfc-template'\nexport const SFC_STYLE_QUERY = 'weapp-web-sfc-style'\nexport const WEB_COMPONENT_PREFIX = '/@weapp-vite/web/component/'\nexport const WEB_COMPONENT_QUERY = 'weapp-web-component'\n"],"mappings":";AAAA,MAAa,cAAc;CAAC;CAAQ;CAAO;CAAQ;CAAO;CAAQ;CAAQ;AAAM;AAChF,MAAa,aAAa;CAAC;CAAS;CAAS;CAAS;AAAM;AAC5D,MAAa,uBAAuB,CAAC,OAAO;AAC5C,MAAa,gBAAgB;CAAC;CAAS;CAAS;CAAS;CAAS;CAAQ;CAAS;CAAU;AAAO;AACpG,MAAa,WAAW;CAAC;CAAQ;CAAW;AAAS;AACrD,MAAa,mBAAmB;CAAC;CAAQ;CAAW;CAAW;CAAO;AAAK;AAE3E,MAAa,WAAW;AACxB,MAAa,aAAa;AAC1B,MAAa,iBAAiB;AAC9B,MAAa,0BAA0B;AACvC,MAAa,iBAAiB;AAC9B,MAAa,cAAc;AAC3B,MAAa,qBAAqB;AAClC,MAAa,kBAAkB;AAC/B,MAAa,uBAAuB;AACpC,MAAa,sBAAsB"}
1
+ {"version":3,"file":"constants.mjs","names":[],"sources":["../../src/plugin/constants.ts"],"sourcesContent":["import {\n WEAPP_VITE_WEB_AUTO_ROUTES_RESOLVED_MODULE_ID,\n WEAPP_VITE_WEB_ENTRY_RESOLVED_MODULE_ID,\n} from '@weapp-core/constants'\n\nexport const SCRIPT_EXTS = ['.vue', '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\nexport const STYLE_EXTS = ['.wxss', '.scss', '.less', '.css']\nexport const TRANSFORM_STYLE_EXTS = ['.wxss']\nexport const TEMPLATE_EXTS = ['.wxml', '.axml', '.swan', '.ttml', '.qml', '.ksml', '.xhsml', '.html']\nexport const WXS_EXTS = ['.wxs', '.wxs.ts', '.wxs.js']\nexport const WXS_RESOLVE_EXTS = ['.wxs', '.wxs.ts', '.wxs.js', '.ts', '.js']\n\nexport const ENTRY_ID = WEAPP_VITE_WEB_ENTRY_RESOLVED_MODULE_ID\nexport const RUNTIME_ID = '/@weapp-vite/web/runtime'\nexport const AUTO_ROUTES_ID = 'weapp-vite/auto-routes'\nexport const RESOLVED_AUTO_ROUTES_ID = WEAPP_VITE_WEB_AUTO_ROUTES_RESOLVED_MODULE_ID\nexport const TEMPLATE_QUERY = 'weapp-web-template'\nexport const STYLE_QUERY = 'weapp-web-style'\nexport const SFC_TEMPLATE_QUERY = 'weapp-web-sfc-template'\nexport const SFC_STYLE_QUERY = 'weapp-web-sfc-style'\nexport const WEB_COMPONENT_PREFIX = '/@weapp-vite/web/component/'\nexport const WEB_COMPONENT_QUERY = 'weapp-web-component'\n"],"mappings":";;;AAKA,MAAa,cAAc;CAAC;CAAQ;CAAO;CAAQ;CAAO;CAAQ;CAAQ;AAAM;AAChF,MAAa,aAAa;CAAC;CAAS;CAAS;CAAS;AAAM;AAC5D,MAAa,uBAAuB,CAAC,OAAO;AAC5C,MAAa,gBAAgB;CAAC;CAAS;CAAS;CAAS;CAAS;CAAQ;CAAS;CAAU;AAAO;AACpG,MAAa,WAAW;CAAC;CAAQ;CAAW;AAAS;AACrD,MAAa,mBAAmB;CAAC;CAAQ;CAAW;CAAW;CAAO;AAAK;AAE3E,MAAa,WAAW;AACxB,MAAa,aAAa;AAC1B,MAAa,iBAAiB;AAC9B,MAAa,0BAA0B;AACvC,MAAa,iBAAiB;AAC9B,MAAa,cAAc;AAC3B,MAAa,qBAAqB;AAClC,MAAa,kBAAkB;AAC/B,MAAa,uBAAuB;AACpC,MAAa,sBAAsB"}
@@ -0,0 +1,75 @@
1
+ import { createWebAssetMiddleware } from "./assets.mjs";
2
+ import { ResolveWebModuleId, WebStylePreprocessOptions } from "./types.mjs";
3
+ import { AcceptedPlugin, ProcessOptions } from "postcss";
4
+ import { SourceMap } from "magic-string";
5
+ import { ViteDevServer } from "vite";
6
+ //#region src/plugin/hostTypes.d.ts
7
+ export interface WebPluginContext {
8
+ warn?: (message: string) => void;
9
+ addWatchFile?: (id: string) => void;
10
+ emitFile?: (asset: {
11
+ type: 'asset';
12
+ fileName: string;
13
+ source: Uint8Array;
14
+ }) => void;
15
+ resolve?: (source: string, importer?: string, options?: {
16
+ skipSelf?: boolean;
17
+ }) => Promise<{
18
+ id: string;
19
+ } | null>;
20
+ }
21
+ type WebTransformResult = {
22
+ code: string;
23
+ map: SourceMap | null;
24
+ } | null;
25
+ type WebPostcssConfig = ProcessOptions & {
26
+ plugins?: AcceptedPlugin[];
27
+ };
28
+ export interface WebCssConfig {
29
+ postcss?: string | WebPostcssConfig;
30
+ preprocessorOptions?: WebStylePreprocessOptions;
31
+ }
32
+ export interface WebUserConfig {
33
+ css?: WebCssConfig;
34
+ }
35
+ export interface WebResolvedConfig extends WebUserConfig {
36
+ root: string;
37
+ command: string;
38
+ createResolver?: () => ResolveWebModuleId;
39
+ optimizeDeps?: {
40
+ exclude?: string[];
41
+ include?: string[];
42
+ };
43
+ }
44
+ export interface WebHmrContext<Module extends object = object> {
45
+ file: string;
46
+ modules?: Module[];
47
+ }
48
+ export interface WebDevServer {
49
+ middlewares: {
50
+ use: (middleware: ReturnType<typeof createWebAssetMiddleware>) => void;
51
+ };
52
+ moduleGraph?: Pick<ViteDevServer['moduleGraph'], 'getModuleById' | 'getModulesByFile' | 'invalidateModule'>;
53
+ }
54
+ export interface WeappWebVitePlugin {
55
+ name: string;
56
+ enforce?: 'pre' | 'post';
57
+ config?: (this: WebPluginContext, config: WebUserConfig) => WebUserConfig | void;
58
+ configResolved?: (this: WebPluginContext, config: WebResolvedConfig) => void | Promise<void>;
59
+ configureServer?: (server: WebDevServer) => void;
60
+ buildStart?: (this: WebPluginContext) => void | Promise<void>;
61
+ resolveId?: (id: string, importer?: string) => string | null | Promise<string | null>;
62
+ load?: (id: string) => string | null | Promise<string | null>;
63
+ watchChange?: {
64
+ order: 'post';
65
+ sequential: true;
66
+ handler: (this: WebPluginContext, id: string, change: {
67
+ event: 'create' | 'update' | 'delete';
68
+ }) => Promise<void>;
69
+ };
70
+ handleHotUpdate?: <Module extends object>(this: WebPluginContext, ctx: WebHmrContext<Module>) => Module[] | void | Promise<Module[] | void>;
71
+ transform?: (this: WebPluginContext, code: string, id: string) => WebTransformResult | Promise<WebTransformResult>;
72
+ }
73
+ //#endregion
74
+ export {};
75
+ //# sourceMappingURL=hostTypes.d.mts.map
@@ -1,78 +1,6 @@
1
- import { ResolveWebModuleId, WeappWebPluginOptions, WebStylePreprocessOptions } from "./types.mjs";
2
- import { createWebAssetMiddleware } from "./assets.mjs";
3
- import { SourceMap } from "magic-string";
1
+ import { WeappWebPluginOptions } from "./types.mjs";
2
+ import { WeappWebVitePlugin } from "./hostTypes.mjs";
4
3
  //#region src/plugin/index.d.ts
5
- interface WebPluginContext {
6
- warn?: (message: string) => void;
7
- addWatchFile?: (id: string) => void;
8
- emitFile?: (asset: {
9
- type: 'asset';
10
- fileName: string;
11
- source: Uint8Array;
12
- }) => void;
13
- resolve?: (source: string, importer?: string, options?: {
14
- skipSelf?: boolean;
15
- }) => Promise<{
16
- id: string;
17
- } | null>;
18
- }
19
- type WebTransformResult = {
20
- code: string;
21
- map: SourceMap | null;
22
- } | null;
23
- interface WebPostcssConfig {
24
- plugins?: Array<{
25
- postcssPlugin?: string;
26
- }>;
27
- [key: string]: unknown;
28
- }
29
- interface WebUserConfig {
30
- css?: {
31
- postcss?: string | WebPostcssConfig;
32
- preprocessorOptions?: WebStylePreprocessOptions;
33
- };
34
- }
35
- interface WebResolvedConfig extends WebUserConfig {
36
- root: string;
37
- command: string;
38
- createResolver?: () => ResolveWebModuleId;
39
- optimizeDeps?: {
40
- exclude?: string[];
41
- include?: string[];
42
- };
43
- }
44
- interface WebHmrContext {
45
- file: string;
46
- }
47
- interface WebDevServer {
48
- middlewares: {
49
- use: (middleware: ReturnType<typeof createWebAssetMiddleware>) => void;
50
- };
51
- moduleGraph?: {
52
- getModuleById: (id: string) => object | undefined;
53
- getModulesByFile: (file: string) => Set<object> | undefined;
54
- invalidateModule: (module: object) => void;
55
- };
56
- }
57
- interface WeappWebVitePlugin {
58
- name: string;
59
- enforce?: 'pre' | 'post';
60
- config?: (this: WebPluginContext, config: WebUserConfig) => WebUserConfig | void;
61
- configResolved?: (this: WebPluginContext, config: WebResolvedConfig) => void | Promise<void>;
62
- configureServer?: (server: WebDevServer) => void;
63
- buildStart?: (this: WebPluginContext) => void | Promise<void>;
64
- resolveId?: (id: string, importer?: string) => string | null | Promise<string | null>;
65
- load?: (id: string) => string | null | Promise<string | null>;
66
- watchChange?: {
67
- order: 'post';
68
- sequential: true;
69
- handler: (this: WebPluginContext, id: string, change: {
70
- event: 'create' | 'update' | 'delete';
71
- }) => Promise<void>;
72
- };
73
- handleHotUpdate?: (this: WebPluginContext, ctx: WebHmrContext) => void | Promise<void>;
74
- transform?: (this: WebPluginContext, code: string, id: string) => WebTransformResult | Promise<WebTransformResult>;
75
- }
76
4
  export declare function weappWebPlugin(options?: WeappWebPluginOptions): WeappWebVitePlugin;
77
5
  //#endregion
78
6
  export type { WeappWebPluginOptions };
@@ -11,6 +11,7 @@ import { createMiniProgramPackageResolver, getAncestorNodeModulesPaths } from ".
11
11
  import { transformScriptModule } from "./register.mjs";
12
12
  import { ensureWebVueSfcResult, generateWebVueSfcStyle, generateWebVueSfcTemplate, resolveWebVueSfcStyleLanguage, transformWebVueSfcScript } from "./vueSfc.mjs";
13
13
  import { getStableWebComponentId, scanProject } from "./scan.mjs";
14
+ import { collectSfcHmrModules } from "./sfcHmr.mjs";
14
15
  import { createEmptyScanState } from "./state.mjs";
15
16
  import { createInlineStyleModule } from "./styleModule.mjs";
16
17
  import { readFile } from "node:fs/promises";
@@ -54,7 +55,7 @@ function createWebCssConfig(config, wxssOptions, warn) {
54
55
  return;
55
56
  }
56
57
  const plugins = postcssConfig?.plugins ?? [];
57
- if (plugins.some((plugin) => plugin.postcssPlugin === "weapp-vite-web-wxss")) return;
58
+ if (plugins.some((plugin) => "postcssPlugin" in plugin && plugin.postcssPlugin === "weapp-vite-web-wxss")) return;
58
59
  return {
59
60
  postcss: {
60
61
  ...postcssConfig,
@@ -124,7 +125,13 @@ function weappWebPlugin(options = {}) {
124
125
  };
125
126
  };
126
127
  const scan = (context) => {
128
+ const graph = devServer?.moduleGraph;
129
+ for (const id of SCAN_VIRTUAL_MODULE_IDS) {
130
+ const module = graph?.getModuleById(id);
131
+ if (module) graph?.invalidateModule(module);
132
+ }
127
133
  const result = scanQueue.then(async () => {
134
+ const previousState = state;
128
135
  const nextState = createEmptyScanState();
129
136
  await scanProject({
130
137
  srcRoot,
@@ -138,7 +145,6 @@ function weappWebPlugin(options = {}) {
138
145
  });
139
146
  const nextComponentImportIdMap = /* @__PURE__ */ new Map();
140
147
  for (const component of nextState.scanResult.components) if (component.importId) nextComponentImportIdMap.set(component.importId, component.script);
141
- const graph = devServer?.moduleGraph;
142
148
  const files = graph ? /* @__PURE__ */ new Set() : void 0;
143
149
  if (files) for (const snapshot of [state, nextState]) {
144
150
  for (const file of snapshot.moduleMeta.keys()) files.add(file);
@@ -147,25 +153,20 @@ function weappWebPlugin(options = {}) {
147
153
  }
148
154
  state = nextState;
149
155
  componentImportIdMap = nextComponentImportIdMap;
150
- if (graph && files) {
151
- for (const id of SCAN_VIRTUAL_MODULE_IDS) {
152
- const module = graph.getModuleById(id);
153
- if (module) graph.invalidateModule(module);
154
- }
155
- for (const file of files) {
156
- const modules = graph.getModulesByFile(file);
157
- if (modules) for (const module of modules) graph.invalidateModule(module);
158
- }
156
+ if (graph && files) for (const file of files) {
157
+ const modules = graph.getModulesByFile(file);
158
+ if (modules) for (const module of modules) graph.invalidateModule(module);
159
159
  }
160
+ return [previousState, nextState];
160
161
  });
161
- scanQueue = result.catch(() => {});
162
+ scanQueue = result.then(() => {}, () => {});
162
163
  return result;
163
164
  };
164
165
  const scanChangedFile = async (context, file) => {
165
166
  const clean = cleanUrl(file);
166
167
  const normalized = normalizePath(clean);
167
168
  if (!isInsideDir(clean, srcRoot) && !state.moduleMeta.has(normalized) && !state.templatePathSet.has(normalized)) return;
168
- if (clean.endsWith(".json") || isTemplateFile(clean) || isWxsFile(clean) || clean.endsWith(".wxss") || SCRIPT_EXTS.includes(extname(clean))) await scan(context);
169
+ if (state.templatePathSet.has(normalized) || clean.endsWith(".json") || isTemplateFile(clean) || isWxsFile(clean) || clean.endsWith(".wxss") || SCRIPT_EXTS.includes(extname(clean))) return scan(context);
169
170
  };
170
171
  return {
171
172
  name: "@weapp-vite/web",
@@ -235,8 +236,14 @@ function weappWebPlugin(options = {}) {
235
236
  return resolveMiniProgramModuleId?.(id, importer).then((resolved) => resolved ?? null) ?? null;
236
237
  },
237
238
  async load(id) {
238
- if (id === "\0@weapp-vite/web/entry") return generateEntryModule(state.scanResult, root, wxssOptions, options);
239
- if (id === "\0@weapp-vite/web/auto-routes") return generateAutoRoutesModule(state.scanResult);
239
+ if (id === ENTRY_ID) {
240
+ await scanQueue;
241
+ return generateEntryModule(state.scanResult, root, wxssOptions, options);
242
+ }
243
+ if (id === RESOLVED_AUTO_ROUTES_ID) {
244
+ await scanQueue;
245
+ return generateAutoRoutesModule(state.scanResult);
246
+ }
240
247
  if (hasQuery(id, "weapp-web-template")) {
241
248
  const filename = cleanUrl(id);
242
249
  let source = await readFile(filename, "utf8");
@@ -304,6 +311,8 @@ function weappWebPlugin(options = {}) {
304
311
  uniApp: options.__uniApp,
305
312
  stylePreprocessOptions
306
313
  });
314
+ this.addWatchFile?.(filename);
315
+ for (const dependency of result.meta?.sfcSrcDeps ?? []) this.addWatchFile?.(dependency);
307
316
  return generateWebVueSfcStyle(result);
308
317
  }
309
318
  return null;
@@ -316,7 +325,10 @@ function weappWebPlugin(options = {}) {
316
325
  }
317
326
  },
318
327
  async handleHotUpdate(ctx) {
319
- await scanChangedFile(this, ctx.file);
328
+ const graph = devServer?.moduleGraph;
329
+ const snapshots = await scanChangedFile(this, ctx.file);
330
+ const affected = graph ? collectSfcHmrModules(snapshots ?? [state], cleanUrl(ctx.file), graph, ctx.modules) : ctx.modules;
331
+ return ctx.modules || affected?.length ? affected : void 0;
320
332
  },
321
333
  async transform(code, id) {
322
334
  const clean = cleanUrl(id);