Skip to content

嵌入与 SDK ​

基于 developer.stackblitz.com 与 @webcontainer/api 2025–2026 现状编写

速查 ​

  • 安装:npm install @stackblitz/sdk(~3kB gzip);import sdk from '@stackblitz/sdk';CDN UMD 暴露全局 StackBlitzSDK
  • 7 个入口:embedProject / embedProjectId / embedGithubProject(→ Promise<VM>,iframe 替换目标元素);openProject / openProjectId / openGithubProject(开新标签,不返回 VM);connect(iframe) → Promise<VM>
  • Project 对象:{ title*, description?, template*, files*, dependencies?, settings? }
  • SDK 8 模板:angular-cli create-react-app html javascript node polymer typescript vue——只有 node 跑在 WebContainers
  • dependencies 仅 EngineBlock 生效;node 模板依赖必须写进 package.json 文件
  • POST API:表单 POST 到 https://stackblitz.com/run,模板仅 4 个:typescript angular-cli create-react-app javascript
  • 关键映射:clickToLoad→ctl、forceEmbedLayout→embed、crossOriginIsolated→corp、openFile→file
  • view 取值:'default' / 'editor' / 'preview'(没有 'both',分屏即 default)
  • VM API:applyFsDiff / getFsSnapshot / getDependencies / editor.* / preview.*;多数方法 resolve 的是 Promise<null>
  • .stackblitzrc 仅 4 字段:installDependencies / startCommand / compileTrigger / env
  • 文档:https://developer.stackblitz.com/platform/api/javascript-sdk

安装与引入 ​

bash
npm install @stackblitz/sdk

SDK 极轻量(约 3kB gzip),ESM 默认导出一个 sdk 对象:

js
import sdk from "@stackblitz/sdk";

也可用 CDN 的 UMD 构建,此时全局变量是 StackBlitzSDK。

7 个入口方法 ​

SDK 的全部入口分三类。记住一条铁律:embed* 返回 VM(可后续控制),open* 跳转新标签、不返回 VM。

方法返回行为
embedProject(elOrId, project, options?)Promise<VM>用 iframe 替换目标元素,嵌入内联项目
embedProjectId(elOrId, projectId, options?)Promise<VM>同上,嵌入一个已存在的项目 ID
embedGithubProject(elOrId, repoSlug, options?)Promise<VM>同上,从 GitHub 仓库嵌入
openProject(project, options?)—开新标签打开内联项目,不返回 VM
openProjectId(projectId, options?)—开新标签打开项目 ID
openGithubProject(repoSlug, options?)—开新标签打开 GitHub 仓库
connect(iframeEl)Promise<VM>连接一个已存在的 StackBlitz iframe
  • elOrId:DOM 元素或其 id 字符串。embed 会用生成的 iframe 替换这个元素。
  • repoSlug:"owner/repo",可带分支 / tag / commit 与子目录,形如 "owner/repo/tree/{branch|tag|commit}/{folder}"。
js
// 嵌入并拿到 VM
const vm = await sdk.embedProjectId("embed-target", "vitejs-vite-abc123", {
  height: 500,
  view: "preview",
});

// open* 不返回 VM,仅跳转
sdk.openGithubProject("vitejs/vite");

Project 对象 ​

内联项目(embedProject / openProject)接收一个 Project 对象:

ts
{
  title: string;          // 必填
  description?: string;
  template: string;       // 必填,见下方模板表
  files: Record<string, string>;  // 必填,路径 → 文件内容
  dependencies?: Record<string, string>;
  settings?: { compile?: { /* ... */ } };
}

SDK 模板:8 个(只有 node 在 WebContainers) ​

template 必须取下面 8 个之一:

模板运行引擎
nodeWebContainers
angular-cliEngineBlock
create-react-appEngineBlock
htmlEngineBlock
javascriptEngineBlock
polymerEngineBlock
typescriptEngineBlock
vueEngineBlock

只有 node 跑在 WebContainers

其余 7 个模板都跑在旧的 EngineBlock 引擎上。需要真实 Node 环境 / 自定义 dev server,必须用 node 模板。

dependencies 字段仅 EngineBlock 生效

顶层的 dependencies 字段只对 EngineBlock 模板有效。node 模板(WebContainers)会忽略它——node 模板的依赖必须写进 files 里的 package.json 文件,由 WebContainer 在终端里 npm install。

settings.compile ​

settings.compile 控制嵌入项目的编译 / 刷新行为:

字段取值默认
triggerauto / keystroke / saveauto
actionhmr / refreshhmr
clearConsoletrue / falsetrue
js
const project = {
  title: "Vite Demo",
  description: "可运行示例",
  template: "node",
  files: {
    "package.json": JSON.stringify({
      name: "demo",
      dependencies: { vite: "^5.0.0" },
      scripts: { dev: "vite" },
    }),
    "index.html": "<h1>Hello</h1>",
  },
  settings: {
    compile: { trigger: "save", action: "hmr", clearConsole: true },
  },
};

POST API:无 JS 也能建项目 ​

不想引 SDK 时,可以用纯 HTML 表单 POST 到 https://stackblitz.com/run 来动态创建并打开项目:

html
<form method="post" action="https://stackblitz.com/run" target="_blank">
  <input type="hidden" name="project[title]" value="My Project" />
  <input type="hidden" name="project[template]" value="javascript" />
  <input type="hidden" name="project[files][index.js]" value="console.log('hi')" />
  <input type="hidden" name="project[dependencies]" value='{"lodash":"^4.17.21"}' />
  <button type="submit">在 StackBlitz 打开</button>
</form>

字段约定:

  • project[title]、project[template]
  • project[files][<路径>]:每个文件一个字段
  • project[dependencies]:JSON 字符串

POST API 的模板只有 4 个

POST API 仅支持 4 个模板:typescript、angular-cli、create-react-app、javascript。它比 SDK 的 8 个模板更窄,且不含 node——POST 方式无法直接起 WebContainers 项目。

EmbedOptions / OpenOptions ​

二者都继承通用的 ProjectOptions。下面按「通用 / 仅 Embed / 仅 Open」分组。

通用选项(Embed 与 Open 都有) ​

选项取值 / 默认说明
clickToLoad默认 false(URL 参数 ctl)显示「点击运行」对话框,懒加载
openFile字符串 / 数组(URL 参数 file)打开并高亮文件,见下
view'default' / 'editor' / 'preview'没有 'both',分屏即 default
theme'default' / 'dark' / 'light'主题
hideExplorer默认 false隐藏文件树
hideDevTools默认 false隐藏开发者工具面板
showSidebar布尔是否展开侧边栏
sidebarView'project' / 'search' / 'ports' / 'settings'侧边栏默认面板
startScript字符串(仅 WebContainers)启动后自动跑的 npm script
terminalHeight0–100(仅 WebContainers,默认 30)终端高度百分比
origin字符串(Enterprise)自托管实例 origin
forceEmbedLayout已废弃 → embed旧的强制嵌入布局开关

openFile 支持多种写法:

js
// 单文件 + 行高亮
{ openFile: "src/App.tsx:L5-L8" }
// 逗号串多个文件
{ openFile: "src/App.tsx,src/main.tsx" }
// 数组 → 分屏
{ openFile: ["src/App.tsx", "src/main.tsx"] }

仅 Embed ​

选项默认说明
height300iframe 高度
width100%iframe 宽度
hideNavigation—隐藏顶部导航条
crossOriginIsolatedURL 参数 corp跨域隔离相关开关

仅 Open ​

选项默认说明
newWindowtrue是否开新窗口
zenMode—极简(禅)模式

VM API(embed* / connect 返回) ​

只有 embed* 与 connect 会 resolve 出一个 VM 句柄,用它能在嵌入运行后程序化操作项目:

js
const vm = await sdk.embedProjectId("target", "abc123");

// 文件系统
await vm.applyFsDiff({
  create: { "src/index.js": "console.log('updated')" },
  destroy: ["src/old.js"],
});
const snapshot = await vm.getFsSnapshot();
const deps = await vm.getDependencies();

// 编辑器
await vm.editor.openFile("src/App.tsx");
await vm.editor.setCurrentFile("src/main.tsx");
await vm.editor.setTheme("dark");
await vm.editor.setView("preview");
await vm.editor.showSidebar(true);

// 预览
const url = await vm.preview.getUrl();
await vm.preview.setUrl("/about");
const origin = vm.preview.origin; // 只读

applyFsDiff 改已有文件要给全量内容

applyFsDiff 的 create 是「写入 / 覆盖」语义:要修改一个已存在的文件,必须在 create 里给出该文件的完整新内容,而不是 diff 片段。destroy 接收要删除的路径数组。

多数 VM 方法 resolve 的是 Promise<null>

除了 getFsSnapshot / getDependencies / preview.getUrl 这三个 getter 会返回数据,其余 VM 方法 resolve 的都是 Promise<null>(仅表示「操作完成」,不是返回值)。别指望 await vm.editor.openFile(...) 拿到什么数据。

vm.preview.origin 在 WebContainers 上恒为 null

vm.preview.origin 是只读属性,但在 WebContainers 项目上它永远是 null——因为预览 URL 由 ServiceWorker 动态生成,没有固定 origin。需要预览地址请用 await vm.preview.getUrl()。

嵌入 URL 参数(大小写敏感) ​

不引 SDK 时,可以直接用带 query 的 iframe URL 嵌入。这些参数大小写敏感,写错就不生效:

参数取值对应 SDK 选项
embed0 / 1forceEmbedLayout
ctl0 / 1clickToLoad
file路径openFile
vieweditor / previewview
themelight / darktheme
hideNavigation0 / 1—
hideExplorer0 / 1hideExplorer
hidedevtools0 / 1(全小写)hideDevTools
devtoolsheight数字(全小写)—
terminalHeight0–100(camelCase)terminalHeight
showSidebar0 / 1showSidebar
initialpath路径(全小写,URI 编码)—
startScriptscript 名startScript
corp—crossOriginIsolated

大小写陷阱

hidedevtools、devtoolsheight、initialpath 是全小写,而 terminalHeight、showSidebar、hideNavigation、hideExplorer、startScript 是 camelCase。混淆大小写是嵌入参数「不生效」的头号原因。

官方示例:

html
<iframe src="https://stackblitz.com/edit/angular?embed=1"></iframe>

关键映射关系(SDK 选项 → URL 参数):clickToLoad → ctl、forceEmbedLayout → embed、crossOriginIsolated → corp、openFile → file。

.stackblitzrc:项目级配置 ​

在项目根放一个 .stackblitzrc(JSON,不支持注释),可声明项目打开时的行为;也可以把同样的内容放在 package.json 的 stackblitz 字段里。它只有 4 个字段:

json
{
  "installDependencies": true,
  "startCommand": "npm run dev",
  "compileTrigger": "auto",
  "env": {
    "NODE_ENV": "development"
  }
}
字段取值默认
installDependencies布尔true
startCommand字符串 / false按 package.json 推断
compileTrigger'auto' / 'keystroke' / 'save'auto
envRecord<string, string>—

终端 / 控制台高度不是 .stackblitzrc 字段

想调终端或控制台高度(terminalHeight / devtoolsheight)属于 SDK 嵌入选项 / URL 参数,不是 .stackblitzrc 的字段。.stackblitzrc 只管这 4 项,别往里塞高度配置。