如何配置Webpack编译TS版CRA供其他React应用引入并处理SCSS
实现可嵌入React类库的Webpack构建方案
需求背景
你需要将基于TypeScript开发的Create React App项目(MyApp)作为依赖嵌入现有React应用(ExistingApp)运行,预期引入方式如下:
import App from "@MyApp/src" function ExistingApp() { return ( <div className="App"> <App /> </div> ); } export default ExistingApp;
构建要求:
- 基于Webpack完成TS/TSX转译、样式处理等全流程编译
- 保留原有文件夹结构,不将所有代码合并为单个JS bundle
- 解决单独执行
tsc --module commonjs --outDir dist时,.scss文件未被处理、无法输出到dist目录的问题
实施步骤
1. 安装构建依赖
执行命令安装所有必需的构建工具和loader:
npm install webpack webpack-cli typescript ts-loader sass sass-loader css-loader mini-css-extract-plugin glob -D
2. 编写Webpack配置文件
在MyApp根目录新建webpack.config.js,核心逻辑为自动扫描src下所有业务文件作为独立入口,按原目录结构输出编译产物,分别处理TS、SCSS、静态资源三类文件:
const path = require('path'); const glob = require('glob'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 扫描src目录下所有ts/tsx文件作为构建入口,保留原文件路径映射 const entryMap = glob.sync('./src/**/*.{ts,tsx}').reduce((entry, filePath) => { const distPath = filePath.replace(/^\.\/src\//, '').replace(/\.(ts|tsx)$/, ''); entry[distPath] = filePath; return entry; }, {}); module.exports = { mode: process.env.NODE_ENV || 'production', entry: entryMap, output: { path: path.resolve(__dirname, 'dist'), filename: '[name].js', libraryTarget: 'commonjs2', // 输出CommonJS格式模块,适配宿主项目的导入方式 clean: true // 构建前清空旧的dist目录 }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx', '.scss'] }, externals: { // 将react、react-dom标记为外部依赖,和宿主ExistingApp共用实例,避免重复打包引发hooks报错 react: 'commonjs react', 'react-dom': 'commonjs react-dom' }, module: { rules: [ { test: /\.tsx?$/, exclude: /node_modules/, use: 'ts-loader' }, { test: /\.scss$/, use: [ MiniCssExtractPlugin.loader, // 抽离css为独立文件,不嵌入JS 'css-loader', 'sass-loader' // 编译scss为标准css ] }, { test: /\.(png|svg|jpg|jpeg|gif|woff|woff2|eot|ttf|otf)$/i, type: 'asset/resource', generator: { filename: '[path][name][ext]' // 静态资源按原目录结构输出 } } ] }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].css' // 输出的css文件保持和对应ts/tsx文件一致的路径 }) ] };
3. 调整配套配置
- 检查
tsconfig.json的核心配置项,保证模块解析正常:
{ "compilerOptions": { "jsx": "react-jsx", "module": "ESNext", "moduleResolution": "node", "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": ["src"] }
- 修改MyApp下
package.json的字段,适配包引入规则:
{ "name": "@MyApp", "main": "dist/index.js", "types": "src/index.ts", "files": ["dist"], "scripts": { "build": "webpack" } }
4. 执行构建
在MyApp目录下执行npm run build,生成的dist目录会完整复现src的文件夹结构:
- 所有.ts/.tsx文件转译为同路径同名的.js文件
- 所有.scss文件编译为同路径同名的.css文件,JS中引入的样式会被自动关联
- 图片、字体等静态资源按原路径输出
- 不存在单bundle打包的问题,宿主ExistingApp安装MyApp依赖后可直接按预期方式引入使用
可选优化
如果项目中存在全局scss变量、公共混入,可以在sass-loader的配置项中添加additionalData字段全局注入,不需要每个文件手动引入:
{ loader: 'sass-loader', options: { additionalData: `@use "@/styles/variables.scss" as *;` } }
内容的提问来源于stack exchange,提问作者Tatenda
相关产品推荐
相关产品推荐

