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

如何在SULU项目中集成React并适配Twig与Webpack配置?

问题描述

我正在开发一个前端采用Twig模板、使用自定义Webpack构建的SULU项目。需要为部分具备高交互性、需状态管理的组件引入React,请问具体该如何实现?以及如何调整Webpack配置,使其同时兼容Twig组件与新增的React部分?

当前项目的Webpack配置如下:

const webpack = require("webpack");
const date = new Date();
const ESLintPlugin = require("eslint-webpack-plugin");

module.exports = () => {
    return {
        plugins: [
            new ESLintPlugin({
                emitWarning: true,
                failOnError: true,
            }),

            new webpack.DefinePlugin({
                BUILD: JSON.stringify(
                    `BUILD: ${date.getDate()}.${
                        date.getMonth() + 1
                    }.${date.getHours()}.${date.getMinutes()}`
                ),
            }),
        ],
    };
};

我尝试了以下配置,但似乎无法正常运行:

module.exports = () => {
    return {
        mode:
            process.env.NODE_ENV === "production"
                ? "production"
                : "development",
        entry: "./js/main.js",
        output: {
            path: path.resolve(__dirname, "../../public/build/website/js"),
            filename: "main.js",
        },
        module: {
            rules: [
                {
                    test: /\.(js|jsx)$/,
                    exclude: /node_modules/,
                    use: {
                        loader: "babel-loader",
                        options: {
                            presets: [
                                "@babel/preset-env",
                                "@babel/preset-react",
                            ],
                        },
                    },
                },
                {
                    test: /\.module\.scss$/,
                    use: [
                        "style-loader",
                        {
                            loader: "css-loader",
                            options: {
                                modules: {
                                    localIdentName:
                                        "[name]__[local]___[hash:base64:5]",
                                },
                            },
                        },
                        "sass-loader",
                    ],
                },
                {
                    test: /\.scss$/,
                    exclude: /\.module\.scss$/,
                    use: ["style-loader", "css-loader", "sass-loader"],
                },
            ],
        },
        resolve: {
            extensions: [".js", ".jsx"],
        },
        plugins: [
            new ESLintPlugin({
                emitWarning: true,
                failOnError: true,
            }),
            new webpack.DefinePlugin({
                BUILD: JSON.stringify(
                    `${new Date().getDate()}.${
                        new Date().getMonth() + 1
                    }.${new Date().getHours()}.${new Date().getMinutes()}`
                ),
            }),
        ],
    };
};

解决方案

一、安装必要依赖

先安装React核心库及编译、样式处理相关依赖:

npm install react react-dom
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader css-loader sass-loader style-loader sass path mini-css-extract-plugin

二、修正Webpack配置

你尝试的配置存在path未引入、生产环境样式处理不规范等问题,以下是调整后的完整配置:

const webpack = require("webpack");
const path = require("path");
const date = new Date();
const ESLintPlugin = require("eslint-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = () => {
    const isProduction = process.env.NODE_ENV === "production";

    return {
        mode: isProduction ? "production" : "development",
        entry: "./js/main.js",
        output: {
            path: path.resolve(__dirname, "../../public/build/website/js"),
            filename: isProduction ? "main.[contenthash].js" : "main.js",
            publicPath: "/build/website/js/",
        },
        module: {
            rules: [
                {
                    test: /\.(js|jsx)$/,
                    exclude: /node_modules/,
                    use: {
                        loader: "babel-loader",
                        options: {
                            presets: [
                                ["@babel/preset-env", { targets: "defaults" }],
                                "@babel/preset-react"
                            ],
                            plugins: ["@babel/plugin-transform-runtime"]
                        },
                    },
                },
                {
                    test: /\.module\.scss$/,
                    use: [
                        isProduction ? MiniCssExtractPlugin.loader : "style-loader",
                        {
                            loader: "css-loader",
                            options: {
                                modules: {
                                    localIdentName: isProduction ? "[hash:base64:8]" : "[name]__[local]___[hash:base64:5]",
                                },
                                sourceMap: !isProduction,
                            },
                        },
                        { loader: "sass-loader", options: { sourceMap: !isProduction } },
                    ],
                },
                {
                    test: /\.scss$/,
                    exclude: /\.module\.scss$/,
                    use: [
                        isProduction ? MiniCssExtractPlugin.loader : "style-loader",
                        { loader: "css-loader", options: { sourceMap: !isProduction } },
                        { loader: "sass-loader", options: { sourceMap: !isProduction } }
                    ],
                },
            ],
        },
        resolve: {
            extensions: [".js", ".jsx"],
        },
        plugins: [
            new ESLintPlugin({
                emitWarning: true,
                failOnError: true,
                extensions: ["js", "jsx"],
            }),
            new webpack.DefinePlugin({
                BUILD: JSON.stringify(
                    `BUILD: ${date.getDate()}.${date.getMonth() + 1}.${date.getHours()}.${date.getMinutes()}`
                ),
                "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV),
            }),
            ...(isProduction ? [new MiniCssExtractPlugin({ filename: "../css/[name].[contenthash].css" })] : []),
        ],
        devtool: isProduction ? "source-map" : "eval-cheap-module-source-map",
    };
};

三、React组件实现与Twig挂载

  1. 编写React组件
    创建js/components/InteractiveComponent.jsx:
import React, { useState } from 'react';
import styles from './InteractiveComponent.module.scss';

const InteractiveComponent = ({ initialCount }) => {
    const [count, setCount] = useState(initialCount || 0);

    return (
        <div className={styles.container}>
            <p>当前计数:{count}</p>
            <button onClick={() => setCount(count + 1)} className={styles.button}>
                点击增加
            </button>
        </div>
    );
};

export default InteractiveComponent;
  1. 入口文件挂载逻辑
    修改js/main.js,添加组件挂载逻辑:
import React from 'react';
import { createRoot } from 'react-dom/client';
import InteractiveComponent from './components/InteractiveComponent';

// 批量挂载页面中的React组件
document.querySelectorAll('[data-react-component]').forEach(el => {
    const componentName = el.dataset.reactComponent;
    const props = JSON.parse(el.dataset.props || '{}');

    if (componentName === 'InteractiveComponent') {
        const root = createRoot(el);
        root.render(<InteractiveComponent {...props} />);
    }
});
  1. Twig模板预留容器
    在需要插入React组件的Twig模板中添加挂载容器:
<div 
    data-react-component="InteractiveComponent" 
    data-props='{"initialCount": 5}'
></div>

四、状态管理方案

针对高交互组件的状态需求,可选择:

  • Redux Toolkit:适合复杂状态场景,安装@reduxjs/toolkit react-redux后,按常规方式配置Store和Provider即可
  • React Context API:轻量级状态共享方案,无需额外依赖,直接使用createContext和useContext实现跨组件状态传递

五、常见问题排查

  • Webpack报错"path is not defined":确保配置文件顶部引入const path = require('path')
  • React组件不渲染:检查Twig容器的data-react-component属性与main.js中的匹配关系,查看浏览器控制台报错信息
  • 样式不生效:确认SCSS文件导入路径正确,模块样式需通过styles.xxx方式引用类名
  • 生产环境构建异常:检查所有依赖是否安装完整,尤其是mini-css-extract-plugin这类生产环境专用插件

内容的提问来源于stack exchange,提问作者coral fish

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 09:25:10