You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行npm run build报错:Unexpected token: punc (.) 可选链兼容问题

问题:TSDX构建React npm库时可选链操作符(?.)报错Unexpected token: punc (.)

执行npm run build(基于tsdx build)时,代码中的可选链操作符?.触发语法错误,错误提示来自terser插件,推测是编译配置未正确处理该语法。

完整错误日志

npm run build

> portshare-frontend-libary-components@0.1.0 build
> tsdx build

@rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
@rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
✓ Creating entry file 1.3 secs
⠦ Building modules
  902 |     header: /*#__PURE__*/React__default.createElement("div", {
  903 |       className: `contact-header ${type === exports.CardType.ADD ? 'addCard' : ''}`
> 904 |     }, /*#__PURE__*/React__default.createElement("h2", null, type === exports.CardType.ADD ? 'Add Contact' : contactCard?.element?.name), type !== exports.CardType.ADD && /*#__PURE__*/React__default.createElement(OptionButtonWithDropdown, {
      |                                                                                                                         ^ Unexpected token: punc (.)
  905 |       options: [{
  906 |         label: 'remove',
(terser plugin) SyntaxError: Unexpected token: punc (.)
SyntaxError: Unexpected token: punc (.)
    at ne (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:19592)
    at c (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:28298)
    at l (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:28389)
    at f (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:28442)
    at U (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:42256)
    at me (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:48326)
    at D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:49206
    at ve (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:49221)
    at ke (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:50475)
    at We (D:\2. repo\portshare-frontend-libary-components\node_modules\tsdx\node_modules\terser\dist\bundle.min.js:1:50707)

PS D:\2. repo\portshare-frontend-libary-components> 

相关配置文件

tsconfig.json

{
  // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
  "include": ["src", "types"],
  "compilerOptions": {
    "module": "esnext",
    "lib": ["dom", "esnext"],
    "importHelpers": true,
    // output .d.ts declaration files for consumers
    "declaration": true,
    // output .js.map sourcemap files for consumers
    "sourceMap": true,
    // match output dir to input dir. e.g. dist/index instead of dist/src/index
    "rootDir": "./src",
    // stricter type-checking for stronger correctness. Recommended by TS
    "strict": true,
    // linter checks for common issues
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    // use Node's module resolution algorithm, instead of the legacy TS one
    "moduleResolution": "node",
    // transpile JSX to React.createElement
    "jsx": "react",
    // interop between ESM and CJS modules. Recommended by TS
    "esModuleInterop": true,
    // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
    "skipLibCheck": true,
    // error out if import and file system have a casing mismatch. Recommended by TS
    "forceConsistentCasingInFileNames": true,
    // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
    "noEmit": true,
    "resolveJsonModule": true, // Enable importing JSON files
    "allowSyntheticDefaultImports": true, // Enable synthetic default imports
    "allowUmdGlobalAccess": true, // Allow accessing UMD globals
    "types": ["node"], // Include the 'node' type definitions
    "target": "es5",
    "baseUrl": ".",
    "paths": {
      "*": ["types/*"]
    },
    "downlevelIteration": true
  }
}

.babelrc.json

{
  "sourceType": "unambiguous",
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "chrome": 100
        }
      }
    ],
    "@babel/preset-typescript",
    "@babel/preset-react"
  ],
  "plugins": []
}

package.json

{
  "version": "0.1.0",
  "main": "dist/index.js",
  "typings": "dist/index.d.ts",
  "files": [
    "dist",
    "src"
  ],
  "scripts": {
    "start": "tsdx watch",
    "build": "tsdx build",
    "test": "tsdx test --passWithNoTests",
    "lint": "tsdx lint",
    "prepare": "tsdx build",
    "size": "size-limit",
    "analyze": "size-limit --why",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  },
  "peerDependencies": {
    "react": ">=16"
  },
  "husky": {
    "hooks": {
      "pre-commit": "tsdx lint"
    }
  },
  "prettier": {
    "printWidth": 80,
    "semi": true,
    "singleQuote": true,
    "trailingComma": "es5"
  },
  "name": "portshare-frontend-libary-components",
  "author": "Leon Salenbacher",
  "module": "dist/portshare-frontend-libary-components.esm.js",
  "size-limit": [
    {
      "path": "dist/portshare-frontend-libary-components.cjs.production.min.js",
      "limit": "10 KB"
    },
    {
      "path": "dist/portshare-frontend-libary-components.esm.js",
      "limit": "10 KB"
    }
  ],
  "devDependencies": {
    "@babel/preset-env": "^7.22.5",
    "@babel/preset-react": "^7.22.5",
    "@babel/preset-typescript": "^7.22.5",
    "@size-limit/preset-small-lib": "^8.2.4",
    "@storybook/addon-essentials": "^7.0.21",
    "@storybook/addon-interactions": "^7.0.21",
    "@storybook/addon-links": "^7.0.21",
    "@storybook/blocks": "^7.0.21",
    "@storybook/react": "^7.0.21",
    "@storybook/react-webpack5": "^7.0.21",
    "@storybook/testing-library": "^0.0.14-next.2",
    "@types/react": "^18.2.14",
    "@types/react-dom": "^18.2.5",
    "husky": "^8.0.3",
    "node-sass": "^9.0.0",
    "portshare-frontend-libary-objects": "^1.0.8",
    "prop-types": "^15.8.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-icons": "^4.9.0",
    "react-loading": "^2.0.3",
    "react-router-dom": "^6.13.0",
    "rollup-plugin-scss": "^4.0.0",
    "rollup-plugin-terser": "^7.0.2",
    "sass": "^1.63.6",
    "sass-loader": "^13.3.2",
    "size-limit": "^8.2.4",
    "storybook": "^7.0.21",
    "tsdx": "^0.14.1",
    "tslib": "^2.5.3"
  },
  "dependencies": {
    "typescript": "^5.1.3",
    "react-simple-star-rating": "^5.1.7"
  }
}
解决方案

原因分析

错误来自terser压缩阶段,说明TS编译后代码仍保留了?.语法,而当前terser版本不支持该语法;或者TSDX的默认构建流程未正确调用Babel转译可选链。

方案1:升级terser版本并配置支持ES2020+

  1. 卸载旧版rollup-plugin-terser,安装新版@rollup/plugin-terser:
npm uninstall rollup-plugin-terser && npm install @rollup/plugin-terser --save-dev
  1. 新建或修改tsdx.config.js替换插件:
const terser = require('@rollup/plugin-terser');

module.exports = {
  rollup(config, options) {
    config.plugins = config.plugins.map(plugin => 
      plugin.name === 'terser' ? terser() : plugin
    );
    return config;
  },
};

方案2:调整TS配置让编译器转译可选链

  1. 修改tsconfig.json的compilerOptions,升级lib并添加转译配置:
"lib": ["dom", "es2020"],
"useDefineForClassFields": true,
"target": "es2018"

方案3:让TSDX使用Babel处理转译

  1. 安装@rollup/plugin-babel和运行时插件:
npm install @rollup/plugin-babel @babel/plugin-transform-runtime @babel/runtime --save-dev
  1. 新建tsdx.config.js配置Babel:
const babel = require('@rollup/plugin-babel');

module.exports = {
  rollup(config, options) {
    config.plugins.push(
      babel({
        extensions: ['.js', '.jsx', '.ts', '.tsx'],
        exclude: 'node_modules/**',
        babelHelpers: 'runtime',
      })
    );
    return config;
  },
};
  1. 修改.babelrc.json添加插件:
"plugins": ["@babel/plugin-transform-runtime"]

方案4:升级TSDX版本

当前使用的TSDX0.14.1版本较旧,尝试升级到最新版:

npm uninstall tsdx && npm install tsdx --save-dev

内容的提问来源于Stack Exchange,提问作者Leon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:47:01