From acaf8594cab77b8debd7ce1aa2b616bae1cae92e Mon Sep 17 00:00:00 2001 From: ZEJIA LIU <53506531+ZEJIA-LIU@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:38:35 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20useXsForTempla?= =?UTF-8?q?te=20=E8=AF=95=E7=94=A8=E6=80=A7=E5=AD=97=E6=AE=B5=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E5=8D=8A=E7=BC=96=E8=AF=91=E9=A2=84=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20(#16598)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: init * feat: 完成模块拆分与基本工作流 * feat: 完成组件收集 * feat: 完成收集环节和转化环节的串联 * feat: 完成react组件中render组件的搜集 * feat: 拓扑算法输出依赖顺序 * chore(release): publish 4.0.6-alpha.0 --tag=alpha * feat: 暂时保存 * feat: 补齐绝大部份测试用例 * lint: 使用rustfmt 统一代码风格 * style: 优化目录结构 * feat: 完善测试用例 * ci: 添加新的swc插件编译命令 * feat: 接入半编译预处理 swc 插件 * chore(debug): 增加快捷调试脚本&解决husky不工作问题 * perf(setData): 优先使用微任务执行setData * perf(wxs): 增加模版渲染时是否使用wxs配置(不使用wxs性能可提升10%以上) * perf(event): 增加clickview模版,减少冗余事件绑定 * perf(template): 移除模版中用于循环体的block标签,降低节点嵌套和模版大小 * chore(release): publish 4.0.7-alpha.1 --tag=alpha * test: 更新snapshots * perf(setData): 修复不使用wxs时custom-wrapper组件l属性为null导致的warning问题 * feat: 半编译支持没有xs的情况 * lint: fix * feat: 更新半编译swc * chore(release): publish 4.0.7-alpha.2 --tag=alpha * chore: 解决合并冲突 * chore: 解决合并冲突 * feat: 设置半编译预处理config --------- Co-authored-by: yushijie1 --- .cargo/config.toml | 4 +- .husky/commit-msg | 0 .husky/pre-commit | 0 .vscode/settings.json | 3 +- Cargo.lock | 11 + crates/native_binding/package.json | 2 +- crates/swc_plugin_compile_mode/.editorconfig | 6 - crates/swc_plugin_compile_mode/src/lib.rs | 102 +- .../src/tests/attributes.rs | 26 +- .../src/tests/children.rs | 42 +- .../src/tests/condition.rs | 68 +- .../src/tests/entry.rs | 10 +- .../src/tests/harmony/attributes.rs | 18 +- .../src/tests/harmony/children.rs | 26 +- .../src/tests/harmony/condition.rs | 18 +- .../src/tests/harmony/entry.rs | 2 +- .../src/tests/harmony/looping.rs | 18 +- .../src/tests/harmony/mod.rs | 15 +- .../src/tests/looping.rs | 52 +- .../swc_plugin_compile_mode/src/tests/mod.rs | 43 +- .../src/tests/shake.rs | 10 +- .../swc_plugin_compile_mode/src/tests/wxs.rs | 34 +- .../swc_plugin_compile_mode/src/transform.rs | 1594 ++-- .../src/transform_harmony.rs | 1265 +-- .../src/utils/constants.rs | 1 - .../src/utils/harmony/components.rs | 127 +- .../swc_plugin_compile_mode/src/utils/mod.rs | 740 +- .../should_support_conditional_expr.js | 33 +- .../should_support_jsx_container_expr.js | 8 + .../Cargo.toml | 17 + .../src/lib.rs | 30 + .../src/tests/entry.rs | 117 + .../src/tests/mod.rs | 28 + .../src/tests/props.rs | 51 + .../src/tests/render.rs | 126 + .../src/utils/constant.rs | 2 + .../src/utils/mod.rs | 3 + .../src/utils/react_component.rs | 38 + .../src/utils/render_fn.rs | 24 + .../src/visitors/collect_render_fn.rs | 170 + .../src/visitors/entry.rs | 183 + .../src/visitors/find_react_component.rs | 81 + .../src/visitors/generate_deps.rs | 47 + .../src/visitors/is_compile_mode_component.rs | 57 + .../src/visitors/mod.rs | 6 + .../src/visitors/transform/component_entry.rs | 127 + .../src/visitors/transform/mod.rs | 2 + .../src/visitors/transform/process.rs | 116 + .../tests/entry.rs/should_support_arrow_fn.js | 10 + .../should_support_default_export_arrow_fn.js | 10 + .../should_support_default_export_fn.js | 10 + .../should_support_export_arrow_fn.js | 10 + .../entry.rs/should_support_export_fn.js | 10 + .../src/tests/entry.rs/should_support_fn.js | 10 + .../should_not_replace_dynamic_props.js | 17 + .../props.rs/should_replace_static_props.js | 19 + ...should_not_render_with_circle_recursion.js | 71 + .../render.rs/should_render_with_recursion.js | 75 + .../should_render_with_sub_component_attr.js | 31 + crates/swc_plugin_define_config/src/lib.rs | 139 +- crates/taro_init/src/async_fs.rs | 2 +- crates/taro_init/src/constants.rs | 4 +- crates/taro_init/src/creator.rs | 5 +- crates/taro_init/src/plugin.rs | 5 +- crates/taro_init/src/project.rs | 5 +- crates/taro_init/src/rn/edit.rs | 2 +- crates/taro_init/src/utils.rs | 40 +- npm/darwin-arm64/package.json | 2 +- npm/darwin-x64/package.json | 2 +- npm/linux-x64-gnu/package.json | 2 +- npm/linux-x64-musl/package.json | 2 +- npm/win32-x64-msvc/package.json | 2 +- package.json | 10 +- .../package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- packages/babel-preset-taro/package.json | 2 +- packages/create-app/package.json | 2 +- packages/css-to-react-native/package.json | 2 +- packages/eslint-config-taro/package.json | 2 +- packages/jest-helper/package.json | 2 +- packages/postcss-html-transform/package.json | 2 +- .../postcss-plugin-constparse/package.json | 2 +- packages/postcss-pxtransform/package.json | 2 +- packages/postcss-unit-transform/package.json | 2 +- packages/rollup-plugin-copy/package.json | 2 +- packages/shared/package.json | 2 +- packages/shared/src/components.ts | 1 + packages/shared/src/constants.ts | 4 + packages/shared/src/shortcuts.ts | 1 + packages/shared/src/template.ts | 108 +- packages/shared/src/utils.ts | 5 +- .../stylelint-config-taro-rn/package.json | 2 +- packages/stylelint-taro-rn/package.json | 2 +- packages/stylelint-taro/package.json | 2 +- packages/taro-api/package.json | 2 +- .../__snapshots__/config.test.ts.snap | 88 +- packages/taro-cli-convertor/package.json | 2 +- packages/taro-cli/package.json | 2 +- .../taro-components-advanced/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../taro-components-library-vue3/package.json | 2 +- packages/taro-components-react/package.json | 2 +- packages/taro-components-rn/package.json | 2 +- packages/taro-components/package.json | 3 +- packages/taro-components/types/common.d.ts | 5 +- packages/taro-extend/package.json | 2 +- packages/taro-framework-react/package.json | 2 +- packages/taro-framework-solid/package.json | 2 +- packages/taro-framework-vue3/package.json | 2 +- packages/taro-h5/package.json | 2 +- packages/taro-helper/package.json | 2 +- packages/taro-helper/scripts/constants.js | 1 + .../swc-backup/swc_plugin_compile_mode.wasm | Bin 1037382 -> 2058289 bytes .../swc_plugin_compile_mode_pre_process.wasm | Bin 0 -> 900236 bytes packages/taro-loader/package.json | 2 +- packages/taro-platform-alipay/package.json | 2 +- packages/taro-platform-h5/package.json | 2 +- .../taro-platform-harmony-hybrid/package.json | 2 +- packages/taro-platform-harmony/package.json | 2 +- packages/taro-platform-jd/package.json | 2 +- packages/taro-platform-qq/package.json | 2 +- packages/taro-platform-swan/package.json | 2 +- packages/taro-platform-swan/src/template.ts | 1 + packages/taro-platform-tt/package.json | 2 +- packages/taro-platform-weapp/package.json | 2 +- packages/taro-plugin-html/package.json | 2 +- packages/taro-plugin-http/package.json | 2 +- packages/taro-plugin-inject/package.json | 2 +- packages/taro-plugin-mini-ci/package.json | 2 +- .../taro-plugin-react-devtools/package.json | 2 +- .../taro-plugin-vue-devtools/package.json | 2 +- packages/taro-react/package.json | 2 +- packages/taro-rn-runner/package.json | 2 +- .../taro-rn-style-transformer/package.json | 2 +- packages/taro-rn-supporter/package.json | 2 +- packages/taro-rn-transformer/package.json | 2 +- packages/taro-rn/package.json | 2 +- packages/taro-router-rn/package.json | 2 +- packages/taro-router/package.json | 2 +- packages/taro-runner-utils/package.json | 2 +- packages/taro-runtime-rn/package.json | 2 +- packages/taro-runtime/package.json | 2 +- packages/taro-runtime/src/constants/index.ts | 1 + packages/taro-runtime/src/dom/event-target.ts | 6 + packages/taro-runtime/src/dom/root.ts | 18 +- packages/taro-runtime/src/hydrate.ts | 5 + packages/taro-service/package.json | 2 +- packages/taro-transformer-wx/package.json | 2 +- packages/taro-vite-runner/package.json | 2 +- packages/taro-vite-runner/src/mini/emit.ts | 13 +- .../taro-vite-runner/src/mini/pipeline.ts | 10 +- .../taro-vite-runner/src/utils/component.ts | 2 +- packages/taro-webpack5-prebundle/package.json | 2 +- packages/taro-webpack5-runner/package.json | 2 +- .../src/loaders/miniCompilerLoader.ts | 18 +- .../src/plugins/MiniCompileModePlugin.ts | 2 +- .../src/plugins/MiniPlugin.ts | 14 +- .../src/utils/component.ts | 2 +- packages/taro-with-weapp/package.json | 2 +- packages/taro/package.json | 2 +- packages/taro/types/compile/config/mini.d.ts | 2 + packages/taroize/package.json | 2 +- pnpm-lock.yaml | 8212 ++++++++--------- scripts/debug.js | 100 + .../__snapshots__/babel.spec.ts.snap | 628 +- .../compiler-macros.spec.ts.snap | 628 +- .../__snapshots__/config.spec.ts.snap | 3276 +++---- .../__snapshots__/css-modules.spec.ts.snap | 1268 ++- .../__snapshots__/framework.spec.ts.snap | 1576 ++-- .../__snapshots__/mini-platform.spec.ts.snap | 1090 +-- .../__snapshots__/parse-html.spec.ts.snap | 628 +- .../__snapshots__/prerender.spec.ts.snap | 1986 ++-- .../__tests__/__snapshots__/sass.spec.ts.snap | 3140 +++---- .../__snapshots__/skyline.spec.ts.snap | 809 +- .../__snapshots__/subpackages.spec.ts.snap | 644 +- .../__snapshots__/tabbar.spec.ts.snap | 1480 ++- tests/__tests__/__snapshots__/ts.spec.ts.snap | 628 +- .../__snapshots__/wx-hybrid.spec.ts.snap | 694 +- tests/__tests__/bundled/globby/index.js | 47 +- 181 files changed, 16262 insertions(+), 17014 deletions(-) mode change 100644 => 100755 .husky/commit-msg mode change 100644 => 100755 .husky/pre-commit delete mode 100644 crates/swc_plugin_compile_mode/.editorconfig create mode 100644 crates/swc_plugin_compile_mode/tests/__swc_snapshots__/src/tests/condition.rs/should_support_jsx_container_expr.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/Cargo.toml create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/lib.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/entry.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/mod.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/props.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/tests/render.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/utils/constant.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/utils/mod.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/utils/react_component.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/utils/render_fn.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/collect_render_fn.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/entry.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/find_react_component.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/generate_deps.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/is_compile_mode_component.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/mod.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/component_entry.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/mod.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/src/visitors/transform/process.rs create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_arrow_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_arrow_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_default_export_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_arrow_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_export_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/entry.rs/should_support_fn.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/props.rs/should_not_replace_dynamic_props.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/props.rs/should_replace_static_props.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_not_render_with_circle_recursion.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_recursion.js create mode 100644 crates/swc_plugin_compile_mode_pre_process/tests/__swc_snapshots__/src/tests/render.rs/should_render_with_sub_component_attr.js mode change 100644 => 100755 packages/taro-helper/swc-backup/swc_plugin_compile_mode.wasm create mode 100755 packages/taro-helper/swc-backup/swc_plugin_compile_mode_pre_process.wasm create mode 100644 scripts/debug.js diff --git a/.cargo/config.toml b/.cargo/config.toml index a4f1b35089e5..73aaed3491f0 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -20,5 +20,5 @@ rustflags = ["-C", "target-feature=+crt-static"] # Alias to build actual SWC plugin binary for the specified target. build-wasi = "build --target wasm32-wasi" build-wasm32 = "build --target wasm32-unknown-unknown" -build-swc-plugins = "build-wasi --release -p swc_plugin_compile_mode -p swc_plugin_define_config" -test-swc-plugins = "test -p swc_plugin_compile_mode -p swc_plugin_define_config" +build-swc-plugins = "build-wasi --release -p swc_plugin_compile_mode -p swc_plugin_define_config -p swc_plugin_compile_mode_pre_process" +test-swc-plugins = "test -p swc_plugin_compile_mode -p swc_plugin_define_config -p swc_plugin_compile_mode_pre_process" diff --git a/.husky/commit-msg b/.husky/commit-msg old mode 100644 new mode 100755 diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 diff --git a/.vscode/settings.json b/.vscode/settings.json index ebd73d16e806..5c4932a411f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,7 +18,8 @@ "./crates/taro_init/Cargo.toml", "./crates/native_binding/Cargo.toml", "./crates/swc_plugin_compile_mode/Cargo.toml", - "./crates/swc_plugin_define_config/Cargo.toml" + "./crates/swc_plugin_define_config/Cargo.toml", + "./crates/swc_plugin_compile_mode_pre_process/Cargo.toml" ], "rust-analyzer.showUnlinkedFileNotification": false } diff --git a/Cargo.lock b/Cargo.lock index 80018fcb0743..87ef4ab62aa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1975,6 +1975,17 @@ dependencies = [ "swc_core", ] +[[package]] +name = "swc_plugin_compile_mode_pre_process" +version = "0.1.0" +dependencies = [ + "regex", + "rustc-hash", + "serde", + "serde_json", + "swc_core", +] + [[package]] name = "swc_plugin_define_config" version = "0.2.0" diff --git a/crates/native_binding/package.json b/crates/native_binding/package.json index 011168658f25..00a4036a00d2 100644 --- a/crates/native_binding/package.json +++ b/crates/native_binding/package.json @@ -1,6 +1,6 @@ { "name": "@tarojs/binding", - "version": "4.0.6", + "version": "4.0.7-alpha.2", "description": "Node binding for taro", "main": "binding.js", "typings": "binding.d.ts", diff --git a/crates/swc_plugin_compile_mode/.editorconfig b/crates/swc_plugin_compile_mode/.editorconfig deleted file mode 100644 index 7b227545b443..000000000000 --- a/crates/swc_plugin_compile_mode/.editorconfig +++ /dev/null @@ -1,6 +0,0 @@ -[*.rs] -indent_style = space -indent_size = 4 - -[*.js] -trim_trailing_whitespace = false diff --git a/crates/swc_plugin_compile_mode/src/lib.rs b/crates/swc_plugin_compile_mode/src/lib.rs index 593e7e5fdd59..a137e09bcbf0 100644 --- a/crates/swc_plugin_compile_mode/src/lib.rs +++ b/crates/swc_plugin_compile_mode/src/lib.rs @@ -1,54 +1,60 @@ +use serde::Deserialize; +use std::collections::HashMap; use swc_core::{ - ecma::{ - ast::Program, - visit::{as_folder, FoldWith, VisitMut}, - }, - plugin::{ - plugin_transform, - proxies::TransformPluginProgramMetadata - } + ecma::{ + ast::Program, + visit::{as_folder, FoldWith, VisitMut}, + }, + plugin::{plugin_transform, proxies::TransformPluginProgramMetadata}, }; -use serde::{Deserialize}; -use std::collections::HashMap; -mod utils; -mod transform; -mod transform_harmony; #[cfg(test)] mod tests; +mod transform; +mod transform_harmony; +mod utils; struct SerdeDefault; impl SerdeDefault { - fn platform_default () -> String { - String::from("WEAPP") - } + fn platform_default() -> String { + String::from("WEAPP") + } + fn is_use_xs_default() -> bool { + true + } + fn template_tag_default() -> String { + String::from("") + } } -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug)] pub struct ComponentReplace { - pub current_init: String, - pub dependency_define: String, + pub current_init: String, + pub dependency_define: String, } #[derive(Deserialize, Debug)] pub struct PluginConfig { - pub tmpl_prefix: String, - #[serde(default = "SerdeDefault::platform_default")] - pub platform: String, - #[serde(default)] - pub is_harmony: bool, - #[serde(default)] - pub components: HashMap>, - #[serde(default)] - pub adapter: HashMap, - #[serde(default)] - pub support_events: Vec, - #[serde(default)] - pub support_components: Vec, - #[serde(default)] - pub event_adapter: HashMap, - #[serde(default)] - pub component_replace: HashMap, - + pub tmpl_prefix: String, + #[serde(default = "SerdeDefault::platform_default")] + pub platform: String, + #[serde(default)] + pub is_harmony: bool, + #[serde(default)] + pub components: HashMap>, + #[serde(default)] + pub adapter: HashMap, + #[serde(default)] + pub support_events: Vec, + #[serde(default)] + pub support_components: Vec, + #[serde(default)] + pub event_adapter: HashMap, + #[serde(default)] + pub component_replace: HashMap, + #[serde(default = "SerdeDefault::is_use_xs_default")] + pub is_use_xs: bool, + #[serde(default = "SerdeDefault::template_tag_default")] + pub template_tag: String, } /// An example plugin function with macro support. @@ -68,19 +74,15 @@ pub struct PluginConfig { /// Refer swc_plugin_macro to see how does it work internally. #[plugin_transform] pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program { - let config = serde_json::from_str::( - &metadata - .get_transform_plugin_config() - .unwrap() - ) - .unwrap(); + let config = + serde_json::from_str::(&metadata.get_transform_plugin_config().unwrap()).unwrap(); - // 如果 config 中的 is_harmony 字段为 true 则走 harmony_transform, 否则则走 transform - let visitor: Box = if config.is_harmony { - Box::new(transform_harmony::TransformVisitor::new(config)) - } else { - Box::new(transform::TransformVisitor::new(config)) - }; + // 如果 config 中的 is_harmony 字段为 true 则走 harmony_transform, 否则则走 transform + let visitor: Box = if config.is_harmony { + Box::new(transform_harmony::TransformVisitor::new(config)) + } else { + Box::new(transform::TransformVisitor::new(config)) + }; - program.fold_with(&mut as_folder(visitor)) + program.fold_with(&mut as_folder(visitor)) } diff --git a/crates/swc_plugin_compile_mode/src/tests/attributes.rs b/crates/swc_plugin_compile_mode/src/tests/attributes.rs index ddc9de82f4f8..891279df343b 100644 --- a/crates/swc_plugin_compile_mode/src/tests/attributes.rs +++ b/crates/swc_plugin_compile_mode/src/tests/attributes.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_keep_static_attrs_only_in_templates, - r#" + get_syntax_config(), + |_| tr(), + should_keep_static_attrs_only_in_templates, + r#" function Index () { return ( @@ -17,10 +17,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_turn_dynamic_attrs, - r#" + get_syntax_config(), + |_| tr(), + should_turn_dynamic_attrs, + r#" function Index () { return ( @@ -37,10 +37,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_handle_events, - r#" + get_syntax_config(), + |_| tr(), + should_handle_events, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/children.rs b/crates/swc_plugin_compile_mode/src/tests/children.rs index dbc9cfa5e939..85207bbfa183 100644 --- a/crates/swc_plugin_compile_mode/src/tests/children.rs +++ b/crates/swc_plugin_compile_mode/src/tests/children.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_render_fn, - r#" + get_syntax_config(), + |_| tr(), + should_support_render_fn, + r#" function Index () { return ( @@ -19,10 +19,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_fragment, - r#" + get_syntax_config(), + |_| tr(), + should_support_fragment, + r#" function Index () { return ( @@ -54,10 +54,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_context_api, - r#" + get_syntax_config(), + |_| tr(), + should_support_context_api, + r#" function Index () { return ( @@ -77,10 +77,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_render_react_component, - r#" + get_syntax_config(), + |_| tr(), + should_render_react_component, + r#" function Index () { return ( @@ -94,10 +94,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_render_native_component, - r#" + get_syntax_config(), + |_| tr(), + should_render_native_component, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/condition.rs b/crates/swc_plugin_compile_mode/src/tests/condition.rs index e9001259505d..625799d8282b 100644 --- a/crates/swc_plugin_compile_mode/src/tests/condition.rs +++ b/crates/swc_plugin_compile_mode/src/tests/condition.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_and_expr, - r#" + get_syntax_config(), + |_| tr(), + should_support_and_expr, + r#" function Index () { return ( @@ -34,26 +34,42 @@ test!( } "# ); + test!( - get_syntax_config(), - |_| tr(), - should_support_conditional_expr, - r#" - function Index () { - return ( - - {condition ? {content} : hello} - {condition1 ? condition2 ? {a} : {b} : {c}} - {condition1 ? {a} : condition2 ? {b} : {c}} - {condition1 ? {a} : (condition2 ? {b} : {c})} - {condition1 ? condition2 && {a} : {b}} - {condition1 ? {a} : condition2 && {b}} - {condition1 ? "someText" : 789} - {condition1 ? : } - {condition1 ? {condition2 ? : } : } - - - ) - } - "# + get_syntax_config(), + |_| tr(), + should_support_conditional_expr, + r#" + function Index () { + return ( + + {condition ? {content} : hello} + {condition1 ? condition2 ? {a} : {b} : {c}} + {condition1 ? {a} : condition2 ? {b} : {c}} + {condition1 ? {a} : (condition2 ? {b} : {c})} + {condition1 ? condition2 && {a} : {b}} + {condition1 ? {a} : condition2 && {b}} + {condition1 ? "someText" : 789} + {condition1 ? : } + {condition1 ? {condition2 ? : } : } + + + ) + } + "# +); + +test!( + get_syntax_config(), + |_| tr(), + should_support_jsx_container_expr, + r#" + function Index () { + return ( + + {} + + ) + } + "# ); diff --git a/crates/swc_plugin_compile_mode/src/tests/entry.rs b/crates/swc_plugin_compile_mode/src/tests/entry.rs index de9f47355941..a588ccfd227a 100644 --- a/crates/swc_plugin_compile_mode/src/tests/entry.rs +++ b/crates/swc_plugin_compile_mode/src/tests/entry.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_multi_compile_mode, - r#" + get_syntax_config(), + |_| tr(), + should_support_multi_compile_mode, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/attributes.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/attributes.rs index 23952b0b8302..f6d974c59283 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/attributes.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/attributes.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_turn_dynamic_attrs, - r#" + get_syntax_config(), + |_| tr(), + should_turn_dynamic_attrs, + r#" function Index () { return ( @@ -25,10 +25,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_handle_events, - r#" + get_syntax_config(), + |_| tr(), + should_handle_events, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/children.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/children.rs index 341731a2aace..802f0e75f749 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/children.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/children.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_render_fn, - r#" + get_syntax_config(), + |_| tr(), + should_support_render_fn, + r#" function Index () { return ( @@ -23,10 +23,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_fragment, - r#" + get_syntax_config(), + |_| tr(), + should_support_fragment, + r#" function Index () { return ( @@ -58,10 +58,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_render_react_component, - r#" + get_syntax_config(), + |_| tr(), + should_render_react_component, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/condition.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/condition.rs index 97c264e49478..a06cd6e1993c 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/condition.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/condition.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_and_expr, - r#" + get_syntax_config(), + |_| tr(), + should_support_and_expr, + r#" function Index () { return ( @@ -22,10 +22,10 @@ test!( "# ); test!( - get_syntax_config(), - |_| tr(), - should_support_conditional_expr, - r#" + get_syntax_config(), + |_| tr(), + should_support_conditional_expr, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/entry.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/entry.rs index 340e6e6d59bd..ebe8fa4904d6 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/entry.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/entry.rs @@ -1,5 +1,5 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( get_syntax_config(), diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/looping.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/looping.rs index c4362f0c7741..0d3c09a441ee 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/looping.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/looping.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_loop_with_function_expr, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_function_expr, + r#" function Index () { return ( @@ -26,10 +26,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_loop_with_arrow_function_with_blockstmt, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_arrow_function_with_blockstmt, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/harmony/mod.rs b/crates/swc_plugin_compile_mode/src/tests/harmony/mod.rs index 858212721f97..f86994eb25d8 100644 --- a/crates/swc_plugin_compile_mode/src/tests/harmony/mod.rs +++ b/crates/swc_plugin_compile_mode/src/tests/harmony/mod.rs @@ -1,19 +1,16 @@ pub use super::get_syntax_config; +use crate::{transform_harmony::*, PluginConfig}; use swc_core::ecma::visit::{as_folder, Fold, VisitMut}; -use crate::{ - PluginConfig, - transform_harmony::*, -}; -mod entry; mod attributes; +mod children; mod condition; +mod entry; mod looping; -mod children; -pub fn tr () -> impl Fold + VisitMut { +pub fn tr() -> impl Fold + VisitMut { let config = serde_json::from_str::( - r#" + r#" { "is_harmony": true, "tmpl_prefix": "f0", @@ -37,7 +34,7 @@ pub fn tr () -> impl Fold + VisitMut { "onTouchCancel": "onTouch", "onLoad": "onComplete" } - }"# + }"#, ) .unwrap(); let visitor = TransformVisitor::new(config); diff --git a/crates/swc_plugin_compile_mode/src/tests/looping.rs b/crates/swc_plugin_compile_mode/src/tests/looping.rs index fbf9257ce957..1adc3acf43d5 100644 --- a/crates/swc_plugin_compile_mode/src/tests/looping.rs +++ b/crates/swc_plugin_compile_mode/src/tests/looping.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_loop_with_function_expr, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_function_expr, + r#" function Index () { return ( @@ -26,10 +26,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_loop_with_arrow_function_with_blockstmt, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_arrow_function_with_blockstmt, + r#" function Index () { return ( @@ -43,10 +43,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_loop_with_arrow_function_with_expr, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_arrow_function_with_expr, + r#" function Index () { return ( @@ -58,10 +58,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_nested_loop, - r#" + get_syntax_config(), + |_| tr(), + should_support_nested_loop, + r#" function Index () { return ( @@ -83,12 +83,11 @@ test!( "# ); - test!( - get_syntax_config(), - |_| tr(), - should_loop_with_fragment, - r#" + get_syntax_config(), + |_| tr(), + should_loop_with_fragment, + r#" function Index () { return ( @@ -104,12 +103,11 @@ test!( "# ); - test!( - get_syntax_config(), - |_| tr(), - should_loop_be_wrapped_when_its_not_the_only_child, - r#" + get_syntax_config(), + |_| tr(), + should_loop_be_wrapped_when_its_not_the_only_child, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/mod.rs b/crates/swc_plugin_compile_mode/src/tests/mod.rs index 1675d69f25b7..b78d8af3416c 100644 --- a/crates/swc_plugin_compile_mode/src/tests/mod.rs +++ b/crates/swc_plugin_compile_mode/src/tests/mod.rs @@ -1,24 +1,21 @@ +use crate::{transform::*, PluginConfig}; use swc_core::ecma::{ - parser, - visit::{as_folder, Fold}, -}; -use crate::{ - PluginConfig, - transform::*, + parser, + visit::{as_folder, Fold}, }; -mod entry; mod attributes; -mod shake; -mod condition; -mod looping; mod children; +mod condition; +mod entry; mod harmony; +mod looping; +mod shake; mod wxs; -pub fn tr () -> impl Fold { - let config = serde_json::from_str::( - r#" +pub fn tr() -> impl Fold { + let config = serde_json::from_str::( + r#" { "tmpl_prefix": "f0", "components": { @@ -87,16 +84,16 @@ pub fn tr () -> impl Fold { "xs": "wxs", "type": "weapp" } - }"# - ) - .unwrap(); - let visitor = TransformVisitor::new(config); - as_folder(visitor) + }"#, + ) + .unwrap(); + let visitor = TransformVisitor::new(config); + as_folder(visitor) } -pub fn get_syntax_config () -> parser::Syntax { - parser::Syntax::Es(parser::EsConfig { - jsx: true, - ..Default::default() - }) +pub fn get_syntax_config() -> parser::Syntax { + parser::Syntax::Es(parser::EsConfig { + jsx: true, + ..Default::default() + }) } diff --git a/crates/swc_plugin_compile_mode/src/tests/shake.rs b/crates/swc_plugin_compile_mode/src/tests/shake.rs index 7910b49b9351..237635dcfce9 100644 --- a/crates/swc_plugin_compile_mode/src/tests/shake.rs +++ b/crates/swc_plugin_compile_mode/src/tests/shake.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_static_jsx_being_shaked, - r#" + get_syntax_config(), + |_| tr(), + should_static_jsx_being_shaked, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/tests/wxs.rs b/crates/swc_plugin_compile_mode/src/tests/wxs.rs index 489fc8fb9091..fe1accf0117c 100644 --- a/crates/swc_plugin_compile_mode/src/tests/wxs.rs +++ b/crates/swc_plugin_compile_mode/src/tests/wxs.rs @@ -1,11 +1,11 @@ +use super::{get_syntax_config, tr}; use swc_core::ecma::transforms::testing::test; -use super::{tr, get_syntax_config}; test!( - get_syntax_config(), - |_| tr(), - should_support_wxs_children, - r#" + get_syntax_config(), + |_| tr(), + should_support_wxs_children, + r#" function Index () { return ( @@ -20,10 +20,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_wxs_attributes, - r#" + get_syntax_config(), + |_| tr(), + should_support_wxs_attributes, + r#" function Index () { return ( @@ -38,10 +38,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_wxs_work_in_multi_compile_mode, - r#" + get_syntax_config(), + |_| tr(), + should_wxs_work_in_multi_compile_mode, + r#" function Index () { return ( @@ -62,10 +62,10 @@ test!( ); test!( - get_syntax_config(), - |_| tr(), - should_support_wxs_events, - r#" + get_syntax_config(), + |_| tr(), + should_support_wxs_events, + r#" function Index () { return ( diff --git a/crates/swc_plugin_compile_mode/src/transform.rs b/crates/swc_plugin_compile_mode/src/transform.rs index 723996323344..4cbca1f71b64 100644 --- a/crates/swc_plugin_compile_mode/src/transform.rs +++ b/crates/swc_plugin_compile_mode/src/transform.rs @@ -1,781 +1,927 @@ - +use crate::utils::{self, constants::*}; +use crate::{utils::as_xscript_expr_string, PluginConfig}; +use std::collections::HashMap; use swc_core::{ - common::{ - iter::IdentifyLast, - util::take::Take, - DUMMY_SP as span, - Spanned, - }, - ecma::{ - self, - ast::*, - visit::{VisitMut, VisitMutWith}, - utils::{quote_ident, quote_str}, - }, - plugin::errors::HANDLER, - atoms::Atom, + atoms::Atom, + common::{iter::IdentifyLast, util::take::Take, Spanned, DUMMY_SP as span}, + ecma::{ + self, + ast::*, + utils::{quote_ident, quote_str}, + visit::{VisitMut, VisitMutWith}, + }, + plugin::errors::HANDLER, }; -use std::collections::HashMap; -use crate::{PluginConfig, utils::as_xscript_expr_string}; -use crate::utils::{self, constants::*}; struct PreVisitor; impl PreVisitor { - fn new () -> Self { - Self {} - } + fn new() -> Self { + Self {} + } } impl VisitMut for PreVisitor { - fn visit_mut_jsx_element_children(&mut self, children: &mut Vec) { - let len = children.len(); - - // 当 JSX 循环表达式存在兄弟节点,且这些兄弟节点中有动态节点(存在 JSX 表达式)时, - // 自动为该循环体外层包裹一个 。 - // 对应测试用例:should_loop_be_wrapped_when_its_not_the_only_child - if len > 1 { - let mut list: Vec = vec![]; - - // 收集 JSX 循环表达式到 list - children - .iter_mut() - .enumerate() - .for_each(|(i, child)| { - if let JSXElementChild::JSXExprContainer(JSXExprContainer { expr: JSXExpr::Expr(expr), .. }) = child { - if let Expr::Call(CallExpr { callee: Callee::Expr(callee_expr), args, .. }) = &mut **expr { - if utils::is_call_expr_of_loop(callee_expr, args) { - list.push(i); - } - } - } - }); - - // 遍历 list,为每个 child 的外层包裹 - fn wrap (list: Vec, children: &mut Vec) { - list.into_iter().for_each(|i| { - let child = &mut children[i]; - if let JSXElementChild::JSXExprContainer(JSXExprContainer { expr: JSXExpr::Expr(expr), .. }) = child { - let expr = expr.take(); - *child = JSXElementChild::JSXElement(Box::new(JSXElement { - span, - opening: JSXOpeningElement { - name: JSXElementName::Ident(quote_ident!("block")), - span, - attrs: vec![], - self_closing: false, - type_args: None - }, - children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(expr) })], - closing: Some(JSXClosingElement { span, name: JSXElementName::Ident(quote_ident!("block")) }) - })); - } - }); + fn visit_mut_jsx_element_children(&mut self, children: &mut Vec) { + let len = children.len(); + + // 当 JSX 循环表达式存在兄弟节点,且这些兄弟节点中有动态节点(存在 JSX 表达式)时, + // 自动为该循环体外层包裹一个 。 + // 对应测试用例:should_loop_be_wrapped_when_its_not_the_only_child + if len > 1 { + let mut list: Vec = vec![]; + + // 收集 JSX 循环表达式到 list + children.iter_mut().enumerate().for_each(|(i, child)| { + if let JSXElementChild::JSXExprContainer(JSXExprContainer { + expr: JSXExpr::Expr(expr), + .. + }) = child + { + if let Expr::Call(CallExpr { + callee: Callee::Expr(callee_expr), + args, + .. + }) = &mut **expr + { + if utils::is_call_expr_of_loop(callee_expr, args) { + list.push(i); } + } + } + }); + + // 遍历 list,为每个 child 的外层包裹 + fn wrap(list: Vec, children: &mut Vec) { + list.into_iter().for_each(|i| { + let child = &mut children[i]; + if let JSXElementChild::JSXExprContainer(JSXExprContainer { + expr: JSXExpr::Expr(expr), + .. + }) = child + { + let expr = expr.take(); + *child = JSXElementChild::JSXElement(Box::new(JSXElement { + span, + opening: JSXOpeningElement { + name: JSXElementName::Ident(quote_ident!("block")), + span, + attrs: vec![], + self_closing: false, + type_args: None, + }, + children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { + span, + expr: JSXExpr::Expr(expr), + })], + closing: Some(JSXClosingElement { + span, + name: JSXElementName::Ident(quote_ident!("block")), + }), + })); + } + }); + } + + if list.len() == 1 { + // 只有一个 JSX 循环表达式时,检查兄弟节点是否全是静态节点,如果不是则要包裹 + let mut pure = true; + let index = list[0]; + for i in 0..len { + if i != index && !utils::is_static_jsx_element_child(&children[i]) { + pure = false; + break; + } + } + if !pure { + wrap(list, children); + } + } else if list.len() > 1 { + // 有多个 JSX 循环表达式时一定要包裹 + wrap(list, children); + } + } - if list.len() == 1 { - // 只有一个 JSX 循环表达式时,检查兄弟节点是否全是静态节点,如果不是则要包裹 - let mut pure = true; - let index = list[0]; - for i in 0..len { - if i != index && !utils::is_static_jsx_element_child(&children[i]) { - pure = false; - break; - } - } - if !pure { - wrap(list, children); + children.visit_mut_children_with(self); + } + fn visit_mut_jsx_element_child(&mut self, child: &mut JSXElementChild) { + if let JSXElementChild::JSXExprContainer(JSXExprContainer { + expr: JSXExpr::Expr(expr), + .. + }) = child + { + if let Expr::Paren(ParenExpr { expr: e, .. }) = &mut **expr { + *expr = e.take(); + } + + match &mut **expr { + Expr::Bin(BinExpr { + op, left, right, .. + }) => { + // C&&A 替换为 C?A:A',原因是为了无论显示还是隐藏都保留一个元素,从而不影响兄弟节点的变量路径 + if *op == op!("&&") { + fn inject_compile_if(el: &mut Box, condition: &mut Box) -> () { + el.opening + .attrs + .push(utils::create_jsx_expr_attr(COMPILE_IF, condition.clone())); + } + fn get_element_double( + element_name: JSXElementName, + condition: &mut Box, + right: &mut Box, + ) -> Expr { + Expr::Cond(CondExpr { + span, + test: condition.take(), + cons: right.take(), + alt: Box::new(utils::create_self_closing_jsx_element_expr( + element_name, // element 替换为同类型的元素。在显示/隐藏切换时,让运行时 diff 只更新必要属性而不是整个节点刷新 + Some(vec![utils::create_jsx_bool_attr(COMPILE_IGNORE)]), + )), + }) + } + match &mut **right { + Expr::JSXElement(el) => { + let element_name = el.opening.name.clone(); + inject_compile_if(el, left); + **expr = get_element_double(element_name, left, right); + } + Expr::Paren(ParenExpr { + expr: paren_expr, .. + }) => { + if paren_expr.is_jsx_element() { + let el: &mut Box = paren_expr.as_mut_jsx_element().unwrap(); + let element_name = el.opening.name.clone(); + inject_compile_if(el, left); + **expr = get_element_double(element_name, left, paren_expr); } - } else if list.len() > 1 { - // 有多个 JSX 循环表达式时一定要包裹 - wrap(list, children); + } + Expr::Lit(_) => { + **expr = Expr::Cond(CondExpr { + span, + test: left.take(), + cons: right.take(), + alt: Box::new(Expr::Lit(Lit::Str(quote_str!(COMPILE_IGNORE)))), + }) + } + _ => { + let jsx_el_name = JSXElementName::Ident(quote_ident!("block")); + let mut block = Box::new(JSXElement { + span, + opening: JSXOpeningElement { + name: jsx_el_name.clone(), + span, + attrs: vec![], + self_closing: false, + type_args: None, + }, + children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { + span, + expr: JSXExpr::Expr(right.take()), + })], + closing: Some(JSXClosingElement { + span, + name: jsx_el_name.clone(), + }), + }); + inject_compile_if(&mut block, left); + **expr = + get_element_double(jsx_el_name, left, &mut Box::new(Expr::JSXElement(block))); + } } + } } - - children.visit_mut_children_with(self); - } - fn visit_mut_jsx_element_child (&mut self, child: &mut JSXElementChild) { - if let JSXElementChild::JSXExprContainer(JSXExprContainer { expr: JSXExpr::Expr(expr), .. }) = child { - if let Expr::Paren(ParenExpr { expr: e, .. }) = &mut **expr { - *expr = e.take(); + Expr::Cond(CondExpr { + test, cons, alt, .. + }) => { + let compile_if = utils::create_jsx_expr_attr(COMPILE_IF, test.clone()); + let compile_else = utils::create_jsx_bool_attr(COMPILE_ELSE); + let process_cond_arm = |arm: &mut Box, attr: JSXAttrOrSpread| match &mut **arm { + Expr::JSXElement(el) => { + el.opening.attrs.push(attr); } - - match &mut **expr { - Expr::Bin(BinExpr { op, left, right, ..}) => { - // C&&A 替换为 C?A:A',原因是为了无论显示还是隐藏都保留一个元素,从而不影响兄弟节点的变量路径 - if *op == op!("&&") { - fn inject_compile_if (el: &mut Box, condition: &mut Box) -> () { - el.opening.attrs.push(utils::create_jsx_expr_attr(COMPILE_IF, condition.clone())); - } - fn get_element_double (element_name: JSXElementName, condition: &mut Box, right: &mut Box) -> Expr { - Expr::Cond(CondExpr { - span, - test: condition.take(), - cons: right.take(), - alt: Box::new(utils::create_self_closing_jsx_element_expr( - element_name, // element 替换为同类型的元素。在显示/隐藏切换时,让运行时 diff 只更新必要属性而不是整个节点刷新 - Some(vec![utils::create_jsx_bool_attr(COMPILE_IGNORE)] - ))) - }) - } - match &mut **right { - Expr::JSXElement(el) => { - let element_name = el.opening.name.clone(); - inject_compile_if(el, left); - **expr = get_element_double(element_name, left, right); - }, - Expr::Paren(ParenExpr { expr: paren_expr, .. }) => { - if paren_expr.is_jsx_element() { - let el: &mut Box = paren_expr.as_mut_jsx_element().unwrap(); - let element_name = el.opening.name.clone(); - inject_compile_if(el, left); - **expr = get_element_double(element_name, left, paren_expr); - } - }, - Expr::Lit(_) => { - **expr = Expr::Cond(CondExpr { - span, - test: left.take(), - cons: right.take(), - alt: Box::new(Expr::Lit(Lit::Str(quote_str!(COMPILE_IGNORE)))) - }) - }, - _ => { - let jsx_el_name = JSXElementName::Ident(quote_ident!("block")); - let mut block = Box::new(JSXElement { - span, - opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![], self_closing: false, type_args: None }, - children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(right.take()) })], - closing: Some(JSXClosingElement { span, name: jsx_el_name.clone() }) - }); - inject_compile_if(&mut block, left); - **expr = get_element_double(jsx_el_name, left, &mut Box::new(Expr::JSXElement(block))); - } - } - } - }, - Expr::Cond(CondExpr { test, cons, alt, ..}) => { - let compile_if = utils::create_jsx_expr_attr(COMPILE_IF, test.clone()); - let compile_else = utils::create_jsx_bool_attr(COMPILE_ELSE); - let process_cond_arm = |arm: &mut Box, attr: JSXAttrOrSpread| { - match &mut **arm { - Expr::JSXElement(el) => { - el.opening.attrs.push(attr); - }, - _ => { - let temp = arm.take(); - let jsx_el_name = JSXElementName::Ident(quote_ident!("block")); - **arm = Expr::JSXElement(Box::new(JSXElement { - span, - opening: JSXOpeningElement { name: jsx_el_name.clone(), span, attrs: vec![attr], self_closing: false, type_args: None }, - children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { span, expr: JSXExpr::Expr(temp)})], - closing: Some(JSXClosingElement { span, name: jsx_el_name }) - })) - } - } - }; - process_cond_arm(cons, compile_if); - process_cond_arm(alt, compile_else); + _ => { + let temp = arm.take(); + let jsx_el_name = JSXElementName::Ident(quote_ident!("block")); + **arm = Expr::JSXElement(Box::new(JSXElement { + span, + opening: JSXOpeningElement { + name: jsx_el_name.clone(), + span, + attrs: vec![attr], + self_closing: false, + type_args: None, }, - _ => (), + children: vec![JSXElementChild::JSXExprContainer(JSXExprContainer { + span, + expr: JSXExpr::Expr(temp), + })], + closing: Some(JSXClosingElement { + span, + name: jsx_el_name, + }), + })) } - - expr.visit_mut_children_with(self); - } else { - child.visit_mut_children_with(self); + }; + process_cond_arm(cons, compile_if); + process_cond_arm(alt, compile_else); } + _ => (), + } + + expr.visit_mut_children_with(self); + } else { + child.visit_mut_children_with(self); } + } } pub struct TransformVisitor { - pub config: PluginConfig, - pub is_compile_mode: bool, - pub node_stack: Vec, - pub templates: HashMap, - pub get_tmpl_name: Box String>, - pub xs_module_names: Vec, - pub xs_sources: Vec, + pub config: PluginConfig, + pub is_compile_mode: bool, + pub node_stack: Vec, + pub templates: HashMap, + pub get_tmpl_name: Box String>, + pub xs_module_names: Vec, + pub xs_sources: Vec, } impl TransformVisitor { - pub fn new (config: PluginConfig) -> Self { - let get_tmpl_name = Box::new(utils::named_iter( - format!("{}t", config.tmpl_prefix) - )); - Self { - config, - is_compile_mode: false, - node_stack: vec![], - templates: HashMap::new(), - get_tmpl_name, - xs_module_names: vec![], - xs_sources: vec![], - } + pub fn new(config: PluginConfig) -> Self { + let get_tmpl_name = Box::new(utils::named_iter(format!("{}t", config.tmpl_prefix))); + Self { + config, + is_compile_mode: false, + node_stack: vec![], + templates: HashMap::new(), + get_tmpl_name, + xs_module_names: vec![], + xs_sources: vec![], } - - fn build_xml_element (&mut self, el: &mut JSXElement) -> String { - let is_inner_component = utils::is_inner_component(&el, &self.config); - let opening_element = &mut el.opening; - - match &opening_element.name { - JSXElementName::Ident(ident) => { - if is_inner_component { - // 内置组件 - let mut name = utils::to_kebab_case(ident.as_ref()); - let attrs = self.build_xml_attrs(opening_element, &name); - if attrs.is_none() { return String::new() }; - let (children, ..) = self.build_xml_children(&mut el.children, None); - - if utils::is_xscript(&name) { - name = match self.config.adapter.get("xs") { - Some(xs) => { - xs.to_string() - }, - None => { - HANDLER.with(|handler| { - handler - .struct_span_err(el.span, "Taro CompileMode 语法错误") - .span_label(el.span, "当前小程序平台不支持 xs 语法") - .emit(); - panic!() - }) - } - }; - } - - format!("<{}{}>{}", name, attrs.unwrap_or_default(), children, name) - } else { - // 回退到旧的渲染模式(React 组件、原生自定义组件) - let node_path = self.get_current_node_path(); - format!(r#"