普通视图

发现新文章,点击刷新页面。
今天 — 2026年3月1日首页

当「多应用共享组件」成了刚需:我们从需求到模块联邦的落地小史

作者 兆子龙
2026年2月28日 22:35

当「多应用共享组件」成了刚需:我们从需求到模块联邦的落地小史

以真实项目需求为背景,讲我们如何从「NPM 发包、iframe 子应用」的坑里走出来,用 Webpack 5 的模块联邦实现多应用运行时共享组件,并给出落地要点与避坑小结。


一、需求从哪来:多产品线要共用一套「家当」

我们这边有一条业务线,同时维护着中台配置端运营活动页数据看板 等多个独立前端应用。这些应用技术栈统一(React + Webpack),但各自独立仓库、独立部署。产品希望:设计系统里的按钮、表格、图表组件能在各应用里共用,且改一处、处处生效,而不是每个项目 copy 一份或各维护各的。

换句话说:多应用共享组件成了刚需,而且要尽量少耦合发版节奏——中台发版不能绑死活动页的发版。


二、我们试过的方案与痛点

在接触模块联邦之前,我们试过两种常见做法,都遇到了明显的瓶颈。

2.1 方案一:NPM 发包

把设计系统打成 @company/design-system 发到内网 NPM,各应用 npm install 后按需引用。

痛点

  • 版本强耦合:设计系统修个 bug 或加个组件,要发一版 NPM,各应用再升级依赖、再构建发布,链条长、节奏难对齐。
  • 多应用不同步:有的应用还在用旧版,有的已升级,线上会同时存在多版本,排查问题时要先看「当前应用装的是哪一版」。
  • 发版心理负担:小改动也要走发包流程,大家更倾向于在业务项目里 copy 一份改,时间一长又变成多份实现。

2.2 方案二:iframe 嵌子应用

把「组件展示页」做成独立应用,主应用用 iframe 嵌进去。

痛点

  • 隔离过重:样式、主题、路由、登录态都要额外打通,通信靠 postMessage,心智负担大。
  • 体验和性能:多一层 iframe,布局、滚动、弹窗都要特殊处理;首屏多一次文档加载,观感上也容易「慢一截」。
  • 不适合「组件级」复用:我们更需要的是「在页面里嵌一个按钮、一个图表」,而不是「嵌一整页」,iframe 更适合整页级的隔离。

这两条路走下来,我们意识到:需要一种运行时按需拉取、独立构建部署、又能像本地模块一样用的机制。后来在 Webpack 5 的文档里看到了 Module Federation(模块联邦),和我们要的场景非常契合。


三、模块联邦是什么:一句话 + 三个角色

模块联邦是 Webpack 5 内置的能力,让多个独立构建、独立部署的应用,在运行时像用本地模块一样加载彼此的代码。不用先发 NPM、不用 npm install,只要构建时配置好「谁暴露、谁消费」,运行时就能动态拉取并执行。

三个角色可以这么记:

角色 做什么
Remote(远程应用) 通过 exposes 把组件/模块暴露出去,打包出 remoteEntry.js,供别人加载。
Host(宿主应用) 通过 remotes 配置 Remote 的入口地址,用 import('remoteName/Button') 消费。
shared 双方声明共享依赖(如 React),可配 singleton: true,保证只加载一份,避免多实例冲突。

我们落地的形态是:设计系统单独一个应用作为 Remote,打包并部署 remoteEntry.js中台、活动页、看板等作为 Host,在需要的地方 import('designSystem/Button'),运行时从 CDN 拉取设计系统的 chunk,和本地代码一起跑在同一页面里。


四、我们怎么落地的:配置要点与坑

4.1 Remote 侧:暴露入口与 shared

设计系统项目里用 ModuleFederationPlugin 暴露组件,并和 Host 约定好 shared(React、ReactDOM 等)版本一致且设为单例,否则容易出现「Invalid hook call」之类的问题。

const { ModuleFederationPlugin } = require('webpack').container;

// Remote 的 webpack 配置片段
new ModuleFederationPlugin({
    name: 'designSystem',
    filename: 'remoteEntry.js',
    exposes: {
        './Button': './src/Button.jsx',
        './Table': './src/Table.jsx',
    },
    shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
    },
});

注意output.publicPath 必须能让 Host 正确拼出所有 chunk 的完整 URL(我们生产环境用 CDN 域名),否则运行时会 404。

4.2 Host 侧:配置 remotes 与动态加载

各业务应用在 Webpack 里配置 remotes 指向设计系统的 remoteEntry.js 地址(开发环境用本机或内网地址,生产用 CDN),然后用 React.lazy + Suspense 加载远程组件,对业务代码来说就像在用异步组件。

// Host 的 webpack 配置片段
new ModuleFederationPlugin({
    name: 'hostApp',
    remotes: {
        designSystem: 'designSystem@https://cdn.example.com/design-system/remoteEntry.js',
    },
    shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
    },
});
// 业务里使用
const RemoteButton = lazy(() => import('designSystem/Button'));

<Suspense fallback={<Spin />}>
    <RemoteButton>来自设计系统</RemoteButton>
</Suspense>

4.3 我们踩过的坑

  • publicPath:Remote 上线后若没配对,Host 拉 chunk 会 404,我们是在 CI 里把 Remote 的 publicPath 打成当前 CDN 前缀。
  • shared 版本:Host 和 Remote 的 requiredVersion 要兼容,否则可能加载两份 React,导致 hook 报错;我们统一用 ^18.0.0 并锁大版本。
  • CORS:Remote 的静态资源要允许业务域名的 origin,我们 Nginx 里对 remoteEntry.js 和 chunk 加了对应 Access-Control-Allow-Origin

五、结果与小结

落地模块联邦之后:设计系统单独发版、单独部署,各业务应用不用改依赖、不用重新装包,刷新页面即可拿到最新组件;多应用共享组件、发版解耦这两个目标都满足了。后续我们也在部分场景下用同一套机制做了「活动页作为 Remote、中台作为 Host」的集成,实现了一应用既可当 Host 也可当 Remote。

小结几句

  • 需求驱动:多应用共享组件、又要独立发版时,NPM 发包和 iframe 各有短板,模块联邦的「运行时拉取 + 独立构建部署」很贴这类场景。
  • 核心三件套:Remote 用 exposes 暴露并产出 remoteEntry.js,Host 用 remotes 拉取并用 import('remote/xx') 消费,shared 配成单例避免多实例。
  • 落地注意:publicPath、shared 版本、CORS 三点配好,再配合 CDN 和 CI,线上就能稳定跑。

如果你也在做多应用组件共享或微前端选型,希望这篇「从需求到落地」的小史能给你一点参考。更细的配置与手把手 Demo 可以看 Webpack 官方 Module Federation 文档module-federation-examples。觉得有用的话,欢迎点赞、收藏或评论区聊聊你的场景。

昨天 — 2026年2月28日首页

React Compiler 来了:少写 useMemo,照样稳

作者 兆子龙
2026年2月27日 19:14

React Compiler 来了:少写 useMemo,照样稳

编译期自动分析依赖、帮你做 memoization,从此不用再纠结「这段要不要包 useMemo」——用愉悦分享的语气,带你认识 React 官方的这份新礼物。


一、先说说我们都在纠结啥

写 React 的时候,咱们多少都经历过这种灵魂拷问:这个算出来的值要不要包一层 useMemo?这个回调要不要 useCallback?这个子组件要不要 React.memo? 不包怕重渲染,包多了又觉得代码啰嗦,还容易依赖数组写错。

有没有一种可能——我们只管写逻辑,谁来帮我们自动做「该记的记一下」? 有,这就是 React Compiler 想做的事。


二、React Compiler 是什么

React Compiler(以前叫 React Forget)是 React 官方出的一个 编译期插件:在构建时分析你的组件代码,搞清楚「谁依赖谁」,然后在需要的地方自动插入 memoization,相当于帮你自动加 useMemo / useCallback / React.memo,而不是你自己一个个手写。

  • 是什么:Babel 插件(或与 Vite / Next 等集成),跑在构建阶段。
  • 解决啥:减少手写 useMemo/useCallback/React.memo 的心智负担,同时尽量保持「只在该变的时候重算、重渲染」。
  • 和手写区别:你写的是「普通」React 代码,编译器在背后做优化;依赖分析由工具完成,更一致、也少踩依赖数组的坑。

一句话:写得更爽,性能交给编译器。


三、它有什么用、适合谁

  • 典型场景:中大型列表、表单、多状态联动组件,以前你要反复想「这里要不要 memo」的地方,可以优先交给编译器试一试。
  • 适用人群:用 React 17/18/19 的团队,尤其是已经在用 Vite、Next.js、Babel 的;想统一优化策略、减少 useMemo 样板代码的。
  • 你能得到:更少的样板代码、更少的依赖数组 bug、以及(在编译器覆盖到的路径上)更可预期的重渲染行为。注意:它不会取代所有手写优化,但在很多场景下能覆盖大部分需求。

四、官方链接(方便你溯源)

建议先看官方 Learn 里的介绍,再看 Installation,按你的构建工具选一条路即可。


五、从零跑起来(以 Vite + React 为例)

环境要求

  • Node 18+
  • React 17 / 18 / 19 均可(React 19 体验最佳)
  • 已有 Vite + React 项目(或 npm create vite@latest 选 React)

安装

pnpm add -D babel-plugin-react-compiler
# 若 React 版本 < 19,再装运行时
pnpm add react-compiler-runtime

Vite 里怎么开

@vitejs/plugin-react 时,在 vite.config.ts 里打开 compiler 开关即可:

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [
        react({
            babel: {
                plugins: [['babel-plugin-react-compiler', {}]],
            },
        }),
    ],
});

保存后重新跑 pnpm dev,编译器就会参与构建。注意:Babel 里若有其他插件,官方建议把 React Compiler 放在第一个,这样它能拿到更完整的源码信息做分析。

用 Next.js 的话

Next.js 15+ 已内置支持,在 next.config.js 里开:

// next.config.js
const nextConfig = {
    experimental: {
        reactCompiler: true,
    },
};

六、写一小段「不写 useMemo」的代码试试

下面是一段没写任何 useMemo / useCallback 的组件——在开启 React Compiler 后,编译器会在编译期分析依赖,并在需要时自动做 memoization,你可以对比开启前后的重渲染行为(例如用 React DevTools 的 Profiler)。

function TodoList({ todos, onToggle }) {
    const [filter, setFilter] = useState('all');
    const filtered = todos.filter((t) =>
        filter === 'done' ? t.done : filter === 'pending' ? !t.done : true
    );
    return (
        <div>
            <select value={filter} onChange={(e) => setFilter(e.target.value)}>
                <option value="all">全部</option>
                <option value="done">已完成</option>
                <option value="pending">未完成</option>
            </select>
            <ul>
                {filtered.map((t) => (
                    <li key={t.id} onClick={() => onToggle(t.id)}>
                        {t.title}
                    </li>
                ))}
            </ul>
        </div>
    );
}

以前我们可能会给 filtered 包一层 useMemo、给 onToggle 包 useCallback;在开启 React Compiler 之后,这类简单依赖可以交给编译器处理,你先专注把逻辑写清楚就行。


七、一点注意与小结

  • 兼容性:推荐 React 19;若用 17/18,需安装 react-compiler-runtime 并按官方文档配置。
  • 渐进使用:可以先在部分页面或分支开启,观察构建与运行是否稳定,再逐步铺开。
  • 不是银弹:极端性能敏感、或已有精细手写 memo 的地方,可以保留;编译器是「默认帮你省心」,而不是禁止你手写。

小结几句:React Compiler 用「编译期分析依赖 + 自动 memoization」的方式,让我们少写 useMemo/useCallback/React.memo,代码更干净、心智负担更小。如果你一直在纠结「这段要不要包 useMemo」,不妨在项目里开一次 React Compiler,用愉悦的心态试一把——说不定你会喜欢上这种「写逻辑、优化交给编译器」的感觉。

如果这篇对你有帮助,欢迎点赞 / 收藏;你有在项目里用过 React Compiler 吗?欢迎在评论区聊聊你的体验。


标签建议React前端性能优化ViteReact Compiler

昨天以前首页

用 React + Remotion 做视频:入门与 AI 驱动生成

作者 兆子龙
2026年2月27日 16:40

用 React + Remotion 做视频:入门与 AI 驱动生成

科普向:Remotion 是什么、能做什么、官方在哪看;从零创建项目、做一个可导出的 demo;并介绍 AI(Remotion Skills)结合 React 做视频的思路与周边生态。

一、这东西是什么

Remotion 是一个用 React 组件 来「写」视频的框架。你可以把它理解成:视频 = 按时间轴一帧一帧渲染出来的 React 页面

  • 和传统视频的区别:传统用 After Effects、Premiere 做剪辑,改文案要重新做一版;用 FFmpeg 写脚本又很难和业务数据、前端技术栈打通。Remotion 把每一帧都交给 React 渲染:你用组件描述「这一帧长什么样」,用 当前帧号useCurrentFrame())算动画进度,最后由 Remotion 用 Chromium 逐帧截图并合成 MP4。
  • 核心抽象
    • Composition:一个「视频画布」,规定宽、高、帧率(fps)、总帧数(durationInFrames)。
    • Sequence:时间轴上的一个片段,在指定帧区间内渲染某个组件,用来排先后顺序。
    • useCurrentFrame() / useVideoConfig():在组件里拿到当前帧号和画布配置,用来算透明度、位移、缩放等,实现关键帧动画。

所以:会写 React,就能用同一套技能做可编程、数据驱动的视频;改数据或文案后重新渲染即可,适合模板化、批量和 CI 集成。


二、这东西有什么用

  • 数据驱动视频:接口、配置、文案都从 props 或 API 来,改数据即改视频,无需手剪。适合:产品介绍、数据可视化、个性化贺卡、批量短视频。
  • 复用前端能力:CSS、Canvas、SVG、Three.js、Lottie 等都能用,和写页面一致,学习成本低。
  • 可编程与自动化:和 Node 脚本、CI 结合,批量生成不同分辨率、不同文案的视频;也可和 AI(如 Remotion Skills 或自建 LLM)结合,用自然语言描述「做一个 15 秒产品介绍」,由 AI 生成脚本,Remotion 负责渲染,实现「描述 → 视频」。

适用人群:前端/全栈、需要做产品动画或批量视频的团队、想用代码替代部分剪辑工作的开发者。


三、官方链接

  • 官网www.remotion.dev
  • 文档www.remotion.dev/docs
  • GitHubgithub.com/remotion-de…
  • 模板/示例npx create-video@latest 会拉取官方脚手架;文档中有多语言、多分辨率等示例。
  • Remotion Skills(AI 生成视频):见官网或仓库关于 Skills 的说明,用自然语言驱动 Remotion 渲染。

写文时 API 与用法以当前官方文档为准。


四、从零跑起来一个项目

环境要求

  • Node.js:建议 18+(以 Remotion 当前文档为准)。
  • 系统:macOS / Windows / Linux 均可;渲染依赖 Chromium,首次可能需下载。

创建与运行

npx create-video@latest my-video
cd my-video
npm run dev

执行后会在浏览器打开本地预览:左侧是时间轴,右侧是当前帧的 React 渲染结果,改代码会热更新。默认带一个示例 Composition,可直接改着玩。

目录结构(常见)

  • src/Root.tsx:入口,里面对应多个 <Composition>,每个代表一个可选的「视频」。
  • src/Compositions/ 或类似:各个视频的组件,例如 HelloWorld.tsx
  • remotion.config.ts:Remotion 配置(如 Chromium 路径、并发数等)。
  • package.json 里会有 remotion@remotion/cli@remotion/bundler 等依赖。

首次跑通后,你会看到一个几秒的示例动画;接下来就是在组件里用 useCurrentFrame() 做自己的内容。


五、如何做一个 demo 出来

下面是一个最小可运行 demo:一个 5 秒的标题渐显 + 一段副标题在 2 秒后出现。

1. 在 Root 里注册一个 Composition

src/Root.tsx(或你项目中的根组件)里增加:

import { Composition } from "remotion";
import { MyFirstVideo } from "./Compositions/MyFirstVideo";

export const RemotionRoot: React.FC = () => {
    return (
        <>
            <Composition
                id="MyFirstVideo"
                component={MyFirstVideo}
                durationInFrames={150}
                fps={30}
                width={1920}
                height={1080}
                defaultProps={{ title: "Remotion + React", subtitle: "用代码做视频" }}
            />
        </>
    );
};
  • durationInFrames={150}fps={30} → 5 秒。
  • defaultProps 会传给下面的 MyFirstVideo 组件。

2. 写 MyFirstVideo 组件(用帧号做动画)

新建 src/Compositions/MyFirstVideo.tsx

import React from "react";
import { useCurrentFrame, useVideoConfig } from "remotion";

export const MyFirstVideo: React.FC<{ title: string; subtitle: string }> = ({ title, subtitle }) => {
    const frame = useCurrentFrame();
    const { fps } = useVideoConfig();

    const titleOpacity = Math.min(1, frame / (fps * 0.8));
    const subtitleStart = fps * 2;
    const subtitleOpacity = frame < subtitleStart ? 0 : Math.min(1, (frame - subtitleStart) / (fps * 0.5));

    return (
        <div style={{ flex: 1, justifyContent: "center", alignItems: "center", display: "flex", flexDirection: "column", background: "#0a0a0a", color: "#fff" }}>
            <div style={{ fontSize: 72, opacity: titleOpacity }}>{title}</div>
            <div style={{ fontSize: 36, marginTop: 24, opacity: subtitleOpacity }}>{subtitle}</div>
        </div>
    );
};
  • 前 0.8 秒标题渐显;2 秒后副标题渐显。
  • titlesubtitle 或时长,保存即可在预览里看到效果。

3. 导出为 MP4

在项目根目录执行:

npx remotion render MyFirstVideo out/my-first-video.mp4

会在 out/ 下得到 my-first-video.mp4
服务端批量渲染可用 @remotion/renderer 在 Node 里调同样逻辑(见官方文档)。


六、AI + React 做视频:Remotion Skills 思路

Remotion Skills 是 Remotion 官方推出的、用自然语言驱动视频生成的方案:你描述「做一个 15 秒的产品介绍,突出三个卖点」,AI 解析意图并生成 Remotion 可用的脚本/结构,再交给 Remotion 渲染。

  • 典型流程:用户输入描述 → LLM 输出分镜或组件配置(如每段文案、时长)→ 映射成 Sequence 和组件 props → Remotion 渲染。
  • 自建方式:不用官方 Skills 时,可用任意 LLM API 根据描述生成 JSON(每段文案、时长、图片 URL 等),再在 Node 里转成 Remotion 的 Composition/Sequence 与 props,用 @remotion/renderer 渲染。这样「AI 生成脚本 + React 组件渲染」就打通了,适合产品动画、批量短视频、数据可视化讲解。

七、周边生态推荐

  • 模板create-video 自带示例;GitHub / 社区有「字幕模板」「数据图表视频」等,可搜 remotion template
  • 相关库:Remotion 官方包如 @remotion/lottie@remotion/media-utils 等,文档中有列表;与 Three.js、Framer Motion 等结合可做更复杂动效。
  • 社区:GitHub Discussions、Discord(见官网),有问题可查 issue 或提问。
  • 进阶:服务端渲染(Lambda / 自建 Node)、多分辨率输出、与 CI 集成自动生成发布视频,文档里都有示例。

八、注意点与总结

  • 性能:复杂动画或大画布会拉长渲染时间,可先用低分辨率预览再全分辨率导出。
  • 字体与资源:服务端渲染时注意字体路径、图片/视频 URL 在渲染环境可访问。
  • 版本:Remotion 更新较快,API 以当前官方文档为准。

总结:Remotion 用 React 组件 + 帧号 描述视频,数据驱动、易和前端与 CI 集成;配合 AI(Remotion Skills 或自建 LLM)可实现「描述 → 视频」的自动化。科普部分你只要记住:是什么、有什么用、官方链接、从零跑起来、做一个 demo、周边生态,就能把 Remotion 讲清楚、带读者上手。

如果这篇对你有帮助,欢迎点赞 / 收藏;想深入可看 Remotion 文档 与 Remotion Skills 相关介绍。


标签ReactRemotion前端人工智能视频

❌
❌