diff --git a/crates/mako/src/build/transform.rs b/crates/mako/src/build/transform.rs index d5713c791..504885af0 100644 --- a/crates/mako/src/build/transform.rs +++ b/crates/mako/src/build/transform.rs @@ -142,6 +142,8 @@ impl Transform { }))); // TODO: is it a problem to clone comments? let comments = origin_comments.get_swc_comments().clone(); + let assumptions = context.assumptions_for(file); + folders.push(Box::new(swc_preset_env::preset_env( unresolved_mark, Some(comments), @@ -152,7 +154,7 @@ impl Transform { )), ..Default::default() }, - Assumptions::default(), + assumptions, &mut FeatureFlag::default(), ))); // simplify, but keep top level dead code @@ -227,6 +229,19 @@ impl Transform { } } +impl Context { + pub fn assumptions_for(&self, file: &File) -> Assumptions { + let is_ts = file.extname == "ts" || file.extname == "tsx"; + + let mut assumptions = Assumptions::default(); + assumptions.set_public_class_fields |= !self.config.use_define_for_class_fields; + if is_ts { + assumptions.set_class_methods |= !self.config.use_define_for_class_fields; + } + assumptions + } +} + // TODO: use visitor instead // Why do this? // 为了修复 @import url() 会把 css 当 asset 处理,返回 base64 的问题 diff --git a/crates/mako/src/config/config.rs b/crates/mako/src/config/config.rs index 0c0598d56..4ba8ae015 100644 --- a/crates/mako/src/config/config.rs +++ b/crates/mako/src/config/config.rs @@ -504,6 +504,7 @@ pub struct Config { pub rsc_client: Option, pub experimental: ExperimentalConfig, pub watch: WatchConfig, + pub use_define_for_class_fields: bool, } #[allow(dead_code)] @@ -657,6 +658,7 @@ const DEFAULT_CONFIG: &str = r#" "rscServer": false, "rscClient": false, "experimental": { "webpackSyntaxValidate": [] }, + "useDefineForClassFields": true, "watch": { "ignorePaths": [] }, "devServer": { "host": "127.0.0.1", "port": 3000 } } diff --git a/e2e/fixtures/javascript.transform.use_define_for_class_fields/expect.js b/e2e/fixtures/javascript.transform.use_define_for_class_fields/expect.js new file mode 100644 index 000000000..a8944f70b --- /dev/null +++ b/e2e/fixtures/javascript.transform.use_define_for_class_fields/expect.js @@ -0,0 +1,7 @@ +const assert = require("assert"); +const { parseBuildResult, trim, moduleReg, injectSimpleJest } = require("../../../scripts/test-utils"); +const { files } = parseBuildResult(__dirname); + +injectSimpleJest(); + +require("./dist/index.js"); diff --git a/e2e/fixtures/javascript.transform.use_define_for_class_fields/mako.config.json b/e2e/fixtures/javascript.transform.use_define_for_class_fields/mako.config.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/e2e/fixtures/javascript.transform.use_define_for_class_fields/mako.config.json @@ -0,0 +1 @@ +{} diff --git a/e2e/fixtures/javascript.transform.use_define_for_class_fields/src/index.tsx b/e2e/fixtures/javascript.transform.use_define_for_class_fields/src/index.tsx new file mode 100644 index 000000000..80788efdd --- /dev/null +++ b/e2e/fixtures/javascript.transform.use_define_for_class_fields/src/index.tsx @@ -0,0 +1,20 @@ +class T{ + a; + b(){ + return this.a + } +} + +it('define the field with descriptor by default',()=>{ + let t = new T(); + expect(Object.getOwnPropertyDescriptor(t,'a')).toStrictEqual({ + value: undefined, + writable: true, + enumerable: true, + configurable: true + }); +}); + + + + diff --git a/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/expect.js b/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/expect.js new file mode 100644 index 000000000..a8944f70b --- /dev/null +++ b/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/expect.js @@ -0,0 +1,7 @@ +const assert = require("assert"); +const { parseBuildResult, trim, moduleReg, injectSimpleJest } = require("../../../scripts/test-utils"); +const { files } = parseBuildResult(__dirname); + +injectSimpleJest(); + +require("./dist/index.js"); diff --git a/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/mako.config.json b/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/mako.config.json new file mode 100644 index 000000000..f6c2a69a1 --- /dev/null +++ b/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/mako.config.json @@ -0,0 +1,3 @@ +{ + "useDefineForClassFields": false +} diff --git a/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/src/index.tsx b/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/src/index.tsx new file mode 100644 index 000000000..4ad19df87 --- /dev/null +++ b/e2e/fixtures/javascript.transform.use_define_for_class_fields_off/src/index.tsx @@ -0,0 +1,15 @@ +class T{ + a; + b(){ + return this.a + } +} + +it('has no descriptor when disable use define for class fields',()=>{ + let t = new T(); + expect(Object.getOwnPropertyDescriptor(t,'a')).toStrictEqual(undefined); +}); + + + + diff --git a/packages/bundler-mako/.gitignore b/packages/bundler-mako/.gitignore new file mode 100644 index 000000000..fc8032bef --- /dev/null +++ b/packages/bundler-mako/.gitignore @@ -0,0 +1 @@ +examples/**/dist diff --git a/packages/bundler-mako/.npmignore b/packages/bundler-mako/.npmignore index b744996d7..e4a6a9f86 100644 --- a/packages/bundler-mako/.npmignore +++ b/packages/bundler-mako/.npmignore @@ -1 +1,2 @@ scripts +examples diff --git a/packages/bundler-mako/examples/simple/base-tsconfig.json b/packages/bundler-mako/examples/simple/base-tsconfig.json new file mode 100644 index 000000000..de4dca889 --- /dev/null +++ b/packages/bundler-mako/examples/simple/base-tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "useDefineForClassFields": true + } +} diff --git a/packages/bundler-mako/examples/simple/build.js b/packages/bundler-mako/examples/simple/build.js new file mode 100644 index 000000000..91552b484 --- /dev/null +++ b/packages/bundler-mako/examples/simple/build.js @@ -0,0 +1,25 @@ +const bundler = require('../../'); +const noop = () => {}; + +bundler + .build({ + cwd: __dirname, + config: { + entry: { + index: 'index.ts', + }, + alias: {}, + jsMinifier: 'none', + hash: false, + targets: { + chrome: 40, + }, + }, + onBuildComplete: noop, + chainWebpack: noop, + watch: false, + }) + .then( + () => console.log('Build completed'), + (e) => console.log(e), + ); diff --git a/packages/bundler-mako/examples/simple/index.ts b/packages/bundler-mako/examples/simple/index.ts new file mode 100644 index 000000000..7c57670be --- /dev/null +++ b/packages/bundler-mako/examples/simple/index.ts @@ -0,0 +1,16 @@ +const assert = require('assert'); + +class T { + a; + b() { + return this.a; + } +} + +let t = new T(); +assert.deepStrictEqual(Object.getOwnPropertyDescriptor(t, 'a'), { + value: undefined, + writable: true, + enumerable: true, + configurable: true, +}); diff --git a/packages/bundler-mako/examples/simple/tsconfig.json b/packages/bundler-mako/examples/simple/tsconfig.json new file mode 100644 index 000000000..e26699a2d --- /dev/null +++ b/packages/bundler-mako/examples/simple/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./base-tsconfig.json", + "compilerOptions": { + "allowJs": true, + "outDir": "dist2" + } +} diff --git a/packages/bundler-mako/index.js b/packages/bundler-mako/index.js index 69a9ac924..0816d7a86 100644 --- a/packages/bundler-mako/index.js +++ b/packages/bundler-mako/index.js @@ -5,6 +5,7 @@ const assert = require('assert'); const { createProxy, createHttpsServer } = require('@umijs/bundler-utils'); const lodash = require('lodash'); const chalk = require('chalk'); +const { parseTsconfig } = require('get-tsconfig'); const { createProxyMiddleware, } = require('@umijs/bundler-utils/compiled/http-proxy-middleware'); @@ -510,6 +511,7 @@ async function getMakoConfig(opts) { {}, ); const outputPath = path.resolve(opts.cwd, opts.config.outputPath || 'dist'); + const tsConfig = getTsConfig(opts); const makoConfig = { entry: opts.entry, @@ -541,6 +543,8 @@ async function getMakoConfig(opts) { emotion, forkTSChecker: !!forkTSChecker, ...(opts.disableCopy ? { copy: [] } : { copy: ['public'].concat(copy) }), + useDefineForClassFields: + tsConfig.compilerOptions.useDefineForClassFields ?? true, }; return makoConfig; @@ -565,3 +569,28 @@ function normalizeDefineValue(val) { }, {}); } } + +const DEFAULT_TS_CONFIG = { + compilerOptions: { + useDefineForClassFields: true, + }, +}; + +function getTsConfig(opts) { + let root = opts.cwd; + const tsConfigPath = path.resolve(root, 'tsconfig.json'); + + if (fs.existsSync(tsConfigPath)) { + try { + return parseTsconfig(tsConfigPath); + } catch (e) { + console.error( + 'parsing tsconfig.json failed, fallback to default tsconfig\n', + e, + ); + return DEFAULT_TS_CONFIG; + } + } else { + return DEFAULT_TS_CONFIG; + } +} diff --git a/packages/bundler-mako/package.json b/packages/bundler-mako/package.json index 14367cada..f49a084f4 100644 --- a/packages/bundler-mako/package.json +++ b/packages/bundler-mako/package.json @@ -2,13 +2,14 @@ "name": "@umijs/bundler-mako", "version": "0.4.17", "dependencies": { - "@umijs/mako": "0.4.18-canary.20240521.4", "@umijs/bundler-utils": "^4.0.81", + "@umijs/mako": "0.4.18-canary.20240521.4", "chalk": "^4.1.2", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", "cors": "^2.8.5", "express": "^4.18.2", + "get-tsconfig": "4.7.5", "lodash": "^4.17.21", "rimraf": "5.0.1", "webpack-5-chain": "8.0.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8402508d8..57277c715 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -382,6 +382,9 @@ importers: express: specifier: ^4.18.2 version: 4.18.2 + get-tsconfig: + specifier: 4.7.5 + version: 4.7.5 lodash: specifier: ^4.17.21 version: 4.17.21 @@ -2823,7 +2826,7 @@ packages: resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==} dependencies: '@esbuild-kit/core-utils': 3.1.0 - get-tsconfig: 4.6.0 + get-tsconfig: 4.7.5 dev: true /@esbuild-kit/core-utils@3.1.0: @@ -2837,7 +2840,7 @@ packages: resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} dependencies: '@esbuild-kit/core-utils': 3.1.0 - get-tsconfig: 4.6.0 + get-tsconfig: 4.7.5 dev: true /@esbuild/android-arm64@0.17.19: @@ -8461,17 +8464,10 @@ packages: get-intrinsic: 1.2.1 dev: true - /get-tsconfig@4.6.0: - resolution: {integrity: sha512-lgbo68hHTQnFddybKbbs/RDRJnJT5YyGy2kQzVwbq+g67X73i+5MVTval34QxGkOe9X5Ujf1UYpCaphLyltjEg==} + /get-tsconfig@4.7.5: + resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} dependencies: resolve-pkg-maps: 1.0.0 - dev: true - - /get-tsconfig@4.7.2: - resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} - dependencies: - resolve-pkg-maps: 1.0.0 - dev: true /git-hooks-list@3.1.0: resolution: {integrity: sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==} @@ -13299,7 +13295,6 @@ packages: /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - dev: true /resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} @@ -14341,7 +14336,7 @@ packages: hasBin: true dependencies: esbuild: 0.18.20 - get-tsconfig: 4.7.2 + get-tsconfig: 4.7.5 optionalDependencies: fsevents: 2.3.3 dev: true