React项目引入appsettings.ts触发Webpack Babel语法错误
问题:Babel无法解析TypeScript类的public static语法
我搭建了React应用,为方便修改全局变量,在appsettings.ts文件中创建了APPSETTINGS配置类,但引入该类后Webpack构建报错,提示appsettings.ts第2行的public static语法无法被babel-loader解析,移除类的引入后项目可正常编译。
错误日志
ERROR in ../../../appsettings.ts Module build failed (from ./node_modules/babel-loader/lib/index.js): SyntaxError: [APP_DIR]\appsettings.ts: Unexpected token (2:11) 1 | export class APPSETTINGS { > 2 | public static EMAIL_SENDER: string = "name@example.com"; | ^ 3 | public static EMAIL_RECIPIENT: string = "name@example.com"; 4 | public static YEAR: number = (new Date()).getFullYear(); 5 | } at instantiate ([APP_DIR]\node_modules\@babel\parser\lib\index.js:67:32) at constructor ([APP_DIR]\node_modules\@babel\parser\lib\index.js:364:12) at Parser.raise ([APP_DIR]\node_modules\@babel\parser\lib\index.js:3364:19) at Parser.unexpected ([APP_DIR]\node_modules\@babel\parser\lib\index.js:3397:16) at Parser.parseClassMemberWithIsStatic ([APP_DIR]\node_modules\@babel\parser\lib\index.js:13888:12) at Parser.parseClassMember ([APP_DIR]\node_modules\@babel\parser\lib\index.js:13773:10) at [APP_DIR]\node_modules\@babel\parser\lib\index.js:13715:14 at Parser.withSmartMixTopicForbiddingContext ([APP_DIR]\node_modules\@babel\parser\lib\index.js:12617:14) at Parser.parseClassBody ([APP_DIR]\node_modules\@babel\parser\lib\index.js:13694:10) at Parser.parseClass ([APP_DIR]\node_modules\@babel\parser\lib\index.js:13669:22) at Parser.parseExportDeclaration ([APP_DIR]\node_modules\@babel\parser\lib\index.js:14178:25) at Parser.maybeParseExportDeclaration ([APP_DIR]\node_modules\@babel\parser\lib\index.js:14135:31) at Parser.parseExport ([APP_DIR]\node_modules\@babel\parser\lib\index.js:14058:29) at Parser.parseStatementContent ([APP_DIR]\node_modules\@babel\parser\lib\index.js:13020:27) at Parser.parseStatement ([APP_DIR]\node_modules\@babel\parser\lib\index.js:12917:17) at Parser.parseBlockOrModuleBlockBody ([APP_DIR]\node_modules\@babel\parser\lib\index.js:13497:25) at Parser.parseBlockBody ([APP_DIR]\node_modules\@babel\parser\lib\index.js:13489:10) at Parser.parseProgram ([APP_DIR]\node_modules\@babel\parser\lib\index.js:12832:10) at Parser.parseTopLevel ([APP_DIR]\node_modules\@babel\parser\lib\index.js:12822:25) at Parser.parse ([APP_DIR]\node_modules\@babel\parser\lib\index.js:14674:10) at parse ([APP_DIR]\node_modules\@babel\parser\lib\index.js:14716:38) at parser ([APP_DIR]\node_modules\@babel\core\lib\parser\index.js:41:34) at parser.next (<anonymous>) at normalizeFile ([APP_DIR]\node_modules\@babel\core\lib\transformation\normalize-file.js:66:38) at normalizeFile.next (<anonymous>) at run ([APP_DIR]\node_modules\@babel\core\lib\transformation\index.js:21:50) at run.next (<anonymous>) at transform ([APP_DIR]\node_modules\@babel\core\lib\transform.js:22:41) at transform.next (<anonymous>) at step ([APP_DIR]\node_modules\gensync\index.js:261:32) at [APP_DIR]\node_modules\gensync\index.js:273:13 at async.call.result.err.err ([APP_DIR]\node_modules\gensync\index.js:223:11) @ ./src/Page/Main/index.tsx 24:0-60 204:60-76 298:42-58 @ ./src/App.tsx 5:0-31 14:38-42 @ ./src/index.tsx 3:0-24 4:50-53 webpack 5.75.0 compiled with 1 error in 4752 ms
webpack.config.js
const path = require('path'); const webpack = require('webpack'); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const HtmlWebpackPlugin = require('html-webpack-plugin'); const dotenv = require('dotenv'); const CopyPlugin = require('copy-webpack-plugin'); const Dotenv = require('dotenv-webpack'); module.exports = function(webpackEnv) { const isEnvDevelopment = webpackEnv.development === true; const isEnvProduction = webpackEnv.production === true; return { target: 'web', watch: isEnvDevelopment, mode: isEnvProduction ? 'production' : 'development', entry: "./src/index.tsx", output: { path: path.join(__dirname, 'dist'), publicPath: "/", filename: isEnvProduction ? '[id].[hash].js' : '[name].bundle.js', chunkFilename: isEnvProduction ? '[id].[hash].[chunkhash].chunk.js' : '[name].chunk.js', }, devtool: isEnvDevelopment ? "source-map" : false, devServer: { compress: true, port: 9000, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS", "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization", https: true }, historyApiFallback: true }, resolve: { mainFields: ['browser', 'main', 'module'], extensions: ['.ts', '.tsx', '.js'] }, module: { rules: [ // 我们使用babel-loader加载jsx和tsx文件 { test: /\.(ts|js)x?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: [ "@babel/preset-env" ] } }, }, { test: /\.(css|scss)$/i, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { modules: { localIdentName: isEnvProduction ? '[sha512:contenthash:base64]' : '[sha1:contenthash:hex:5]_____[local]' }, importLoaders: 2, sourceMap: isEnvDevelopment, } }, { loader: "resolve-url-loader", }, { loader: "sass-loader", options: { sourceMap: true } } ] }, { test: /\.(eot|otf|webp|ttf|woff|woff2|jpe?g|png|gif|svg)$/, type: 'asset/resource' }, { test: /\.(pdf)(\?.*)?$/, use: [ { loader: "file-loader", options: { outputPath: "binary", publicPath: "/binary" } }, ], } ] }, plugins: [ new MiniCssExtractPlugin({ filename: isEnvProduction ? '[id].[hash].css' : '[name].bundle.css', }), new HtmlWebpackPlugin(), new CopyPlugin({ patterns: [ { from: 'src/static', to: '.' }, ], }), new Dotenv({ path: isEnvProduction ? path.join(__dirname, "./.env.automated") : path.join(__dirname, "./.env") }), ] } };
package.json
{ "name": "react-webapp", "version": "1.0.0", "description": "", "main": "src/index.ts", "scripts": { "dev": "webpack serve --env development", "build": "webpack --env production" }, "author": "", "license": "ISC", "dependencies": { "@aws-amplify/api": "^4.0.18", "@aws-amplify/api-graphql": "^2.2.7", "@aws-amplify/auth": "^4.3.8", "@aws-amplify/cache": "^4.0.20", "@aws-amplify/core": "^4.3.0", "aws-amplify": "^4.3.0", "classnames": "^2.3.1", "detect-browser": "^5.2.1", "dotenv-webpack": "^7.0.3", "graphql-tag": "^2.12.5", "ibantools": "^4.0.1", "react": "^17.0.2", "react-dom": "^17.0.2", "react-loading": "^2.0.3", "react-router-dom": "^5.3.0", "regenerator-runtime": "^0.13.9" }, "devDependencies": { "@babel/core": "^7.20.2", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/preset-env": "^7.20.2", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", "@types/react": "^17.0.26", "@types/react-dom": "^17.0.9", "babel-loader": "^8.3.0", "copy-webpack-plugin": "^9.0.1", "css-loader": "^6.3.0", "dotenv": "^10.0.0", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.3.2", "mini-css-extract-plugin": "^2.3.0", "node-sass": "^6.0.1", "resolve-url-loader": "^4.0.0", "sass-loader": "^12.1.0", "typescript": "^4.4.3", "typescript-plugin-css-modules": "^3.4.0", "webpack": "^5.75.0", "webpack-cli": "^4.8.0", "webpack-dev-server": "^4.3.0" } }
解决方案
问题根源是Babel配置未启用TypeScript支持,也未配置处理类属性的插件,导致无法解析TypeScript类中的public static语法。
1. 修改babel-loader配置
在webpack.config.js的babel-loader选项中,添加TypeScript和React的预设,并启用类属性插件:
{ test: /\.(ts|js)x?$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: [ "@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript" ], plugins: [ "@babel/plugin-proposal-class-properties" ] } }, }
2. 验证文件匹配规则
appsettings.ts的路径不在node_modules下,且test规则/\.(ts|js)x?$/已包含.ts文件,会被babel-loader正常处理,无需额外调整。
3. 可选:简化全局变量写法(更推荐)
无需用类存储全局配置,直接用TypeScript常量对象更简洁,还能避免类语法相关问题:
// appsettings.ts export const APPSETTINGS = { EMAIL_SENDER: "name@example.com", EMAIL_RECIPIENT: "name@example.com", YEAR: (new Date()).getFullYear() } as const;
内容的提问来源于stack exchange,提问作者T. Jami
相关产品推荐
相关产品推荐

