加入直播:美国东部时间周四上午 11 点,Storybook 9 版本发布及 AMA 问答

🎩 直接从代码块创建 CodeSandbox

在 Github 上查看

remark-codesandbox

🎩 一个 remark 插件,可直接从代码块创建 CodeSandbox

npm version

在 CodeSandbox 上在线试试吧!(没错,我们在 CodeSandbox 里演示 CodeSandbox,为什么不呢!?)

Edit remark-codesandbox demo

特性

  • 🔗 直接从代码块创建 CodeSandbox URL
  • ✨ 支持 3 种不同的模式metaiframebutton
  • 🚀 无需创建额外的文件夹或 package.json 文件
  • 🎉 支持 MDXGatsbyStorybook Docsdocz 等...
  • 📦 支持引入自定义模板,甚至可以直接从同一个仓库引入!
  • ⚡ 一行代码设置,高度可定制
  • 💪 非常适合库作者直接从文档中演示用法!

示例

安装

yarn add -D remark-codesandbox

快速入门

remark-codesandbox 导入到你的 remark 插件中。

const codesandbox = require('remark-codesandbox');

remark

remark().use(codesandbox, { mode: 'button' });

MDX

mdx(mdxCode, {
  remarkPlugins: [[codesandbox, { mode: 'button' }]],
});

Gatsby (gatsby-plugin-mdx)

使用 /gatsby 端点来使用 Gatsby 版本的插件。

module.exports = {
  plugins: [
    {
      resolve: 'gatsby-plugin-mdx',
      options: {
        gatsbyRemarkPlugins: [
          {
            resolve: 'remark-codesandbox/gatsby',
            options: {
              mode: 'button',
            },
          },
        ],
      },
    },
  ],
};

Gatsby (gatsby-transformer-remark)

使用 /gatsby 端点来使用 Gatsby 版本的插件。

module.exports = {
  plugins: [
    {
      resolve: 'gatsby-transformer-remark',
      options: {
        plugins: [
          {
            resolve: 'remark-codesandbox/gatsby',
            options: {
              mode: 'button',
            },
          },
        ],
      },
    },
  ],
};

Storybook docs

config.module.rules.push({
  test: /\.(stories|story)\.mdx$/,
  use: [
    {
      loader: '@mdx-js/loader',
      options: {
        compilers: [createCompiler({})],
        remarkPlugins: [[codesandbox, { mode: 'button' }]],
      },
    },
  ],
});

用法

为你的代码块添加一个特殊的元标签

```js codesandbox=react
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello remark-codesandbox!</h1>,
  document.getElementById('root')
);
```

然后... 就完成了!

上面将 mode 设置为 button 的示例将在代码块后面附加一个 CodeSandbox 按钮。点击它将打开生成的沙箱。是不是很酷!

还有其他模式和额外配置,请查阅下面的文档了解更多信息。

文档

Markdown 语法

在代码块后面附加 codesandbox 元数据以启用 remark-codesandbox。这里的值是沙箱的 id

```js codesandbox=new
// ...
```

有一组默认的官方沙箱模板,你可以在这里找到列表。一些例子包括 new(react)vanilla(parcel)vuestatic 等...

代码块的内容将完全替换入口文件。因此对于 new 模板,内容将完全替换 src/index.js 文件。请确保导入模板所需的包以使其正常工作。

该插件还提供了一些默认的别名reactnew 的别名。react-component 也是 new 的别名,但将入口文件更改为 src/App.js。这样你就可以在代码块中只导出一个 React 组件。

```js codesandbox=react-component
import React from 'react';

export default function App() {
  return <h1>Hello remark-codesandbox!</h1>;
}
```

也可以使用任何现有的沙箱。只需从 URL 中获取沙箱的 idid 通常是沙箱 URL 的最后 ~5 个随机字符。从 Github 导入的沙箱也受支持,其 id 通常是沙箱预览 URL 的子域名(~10 个随机字符)。

```js codesandbox=mqpp1d4r0
// ...
```

想使用自定义模板并将其与代码一同版本控制在同一个仓库中?使用 file: 方案直接从文件系统加载模板!下面的代码将从路径 ./templates/vanilla-console 加载模板,该路径是相对于 Markdown 文件而言的。文件模板是至少包含一个 package.json 文件的目录。

与前面的示例一样,代码块的内容将替换模板中的入口文件。

```js codesandbox=file:./templates/vanilla-console
console.log('this code will replace the entry file content');
```

路径太长,每次都要输入?考虑将其创建为自定义模板。这也是推荐的方式!

专业提示:你可以直接在 codesandbox.io/s 上创建文件模板,然后通过菜单栏选择 File -> Export to ZIP 下载。解压到某个地方... 神奇地!你就得到了一个文件模板!

查询参数

也可以通过附加查询参数来自定义 URL。只需将其附加在沙箱 ID 后面即可。所有选项都允许使用。

```js codesandbox=new?codemirror=1&fontsize=12
// ...
```

有几个可以内联设置的特殊查询参数。下面的所有特殊查询参数都不会传递给生成的 CodeSandbox URL,因为它们不是官方支持的。

entry

引入了一个特殊查询参数 entry,允许你使用代码块的内容覆盖特定文件。

```js codesandbox=new?entry=src/App.js
// Override `src/App.js` rather than the default `src/index.js` with this contents of the code block
```

overrideEntry

默认情况下,代码块中的内容将覆盖入口文件中的所有内容。你可以通过设置特殊查询参数 overrideEntry 来更改此行为。

overrideEntry 设置为行号范围,以指定代码块要覆盖入口文件的哪一部分。下面的示例将用代码块中的内容替换 react 模板(src/index.js)入口文件的第 4 到 12 行。

```js codesandbox=react?overrideEntry=4-12
ReactDOM.render(
  <h1>Hello remark-codesandbox!</h1>,
  document.getElementById('root')
);
```

通过这个技巧,你可以避免将不相关的代码放入代码块中,从而让读者专注于真正重要的内容。

还有一个便捷的快捷方式,只指定起始行而不指定结束行,就可以从指定的行号开始替换整个入口文件,而无需知道它有多长。

```js codesandbox=react?overrideEntry=4-
ReactDOM.render(
  <h1>Hello remark-codesandbox!</h1>,
  document.getElementById('root')
);
```

如果你想原样使用模板,不包含代码块中的任何内容,添加 ?overrideEntry=false 查询字符串即可。

```js codesandbox=file:./templates/vanilla-console?overrideEntry=false
// This code will not be added to the sandbox
```

style

你也可以覆盖在 iframe 模式中使用的默认样式。

```js codesandbox=react?style=height:1000px
// The generated iframe will have height of 1000px instead of the default 500px
```

你可以传入多个样式,用 ; 分隔。所有样式都将合并并覆盖默认样式 (width:100%; height:500px; border:0; border-radius:4px; overflow:hidden;)。

```js codesandbox=react?style=height:1000px;width:600px;
// The result style will be: "width:600px; height:1000px; border:0; border-radius:4px; overflow:hidden;"
```

选项

该插件接受一组选项,默认值如下

{
  remarkPlugins: [
    codesandbox,
    {
      // Can be one of `meta`, `iframe`, or `button`
      mode: 'meta',
      // The query here will be appended to the generated url for every sandbox. Can be `string`, `object`, `URLSearchParams` instance, or `undefined`
      query:
        mode === 'iframe'
          ? {
              fontsize: '14px',
              hidenavigation: 1,
              theme: 'dark',
            }
          : undefined,
      // Define custom templates or override existing ones
      customTemplates: {},
      // Whether to automatically deploy code blocks via CodeSandbox API
      autoDeploy: false,
    },
  ];
}

mode

  • meta:生成 CodeSandbox URL 并将其存储在 AST 中。这种模式本身不会对 markdown 产生任何视觉变化,它对于其他插件或用户介入并对沙箱 URL 执行任何操作非常有用。URL 将存储在 node.data.codesandboxUrlnode.data.hProperties.dataCodesandboxUrl 中。一个示例用法是自定义 UI 中的 CodeSandbox 按钮。

  • iframe:这种模式将完全用生成的沙箱 iframe 标签替换代码块。iframe 带有默认的查询参数,但你可以通过 iframeQuery 覆盖它们。

  • button:这种模式将保持代码块不变,并在代码块后面立即附加一个CodeSandbox 按钮,如下所示。

    Edit React

query

默认情况下,除了附加到生成 URL 的 module 键之外,没有其他查询。你可以在此处为每个 URL 自定义查询。但是,当 modeiframe 时,将有一组预定义的自定义查询,如下所示。

query =
  mode === 'iframe'
    ? {
        fontsize: '14px',
        hidenavigation: 1,
        theme: 'dark',
      }
    : undefined;

你可以通过将 query 传递给选项来覆盖它们。请注意,传递的对象将替换默认对象,如果你想保留默认查询,请确保再次包含它们。

customTemplates

定义在代码块中使用的自定义模板。预期一个对象,其中键是模板 ID,值是模板信息。

模板信息是一个对象,其接口如下所示。

interface TemplateInfo {
  extends: string;
  entry?: string;
  query?: string | { [key: string]: string } | URLSearchParams;
  files?: { [filePath: string]: { content: string | Object } };
}
  • extends:为了让定义自定义模板更容易,插件接受一个 extends 键,让你扩展任何现有模板。值可以是任何 CodeSandbox ID,或 file: 路径,或任何其他自定义模板 ID。如果使用 file: 路径,建议使用绝对路径。默认情况下,相对路径是相对于 process.cwd() 的,这与在代码块中内联定义的相对路径不同。
  • entry:要在模板中显示的入口文件,也是代码块将替换到的文件。允许用户使用同一个模板/沙箱覆盖不同的文件。
  • query:要附加到生成 URL 的查询参数。它将合并并覆盖上面 options.query 中的任何键。但是,它会被代码块元数据中内联定义的查询合并和覆盖。
  • files:要合并和覆盖现有文件的附加文件。其签名遵循官方 API。建议尽可能在 extends 字段中使用 file: 路径,因为它更容易管理和版本控制。

下面是默认的自定义模板。

{
  // Alias `react` to `new`
  react: {
    extends: 'new',
  },
  // Alias `react-component` to `new`, but also override `entry` to `src/App.js`
  'react-component': {
    extends: 'new',
    entry: 'src/App.js',
  },
}

autoDeploy

默认情况下,URL 是在本地生成,而无需调用官方 API。仅当用户点击按钮或查看 iframe 时才会调用 API。这是通过在本地手动构建 parameters 并通过 lz-string 压缩它们来完成的。请注意,有通用指南建议 URL 保持在 2000 字符以内,较长的 URL 可能在某些浏览器中不起作用。

你可以通过将 autoDeploy 设置为 true 来绕过此限制。这样会得到一个带有唯一 codesandbox_id 的短 URL。缺点是生成 URL 需要更多时间。

通常的做法是在生产环境(或当结果 URL 对于你支持的浏览器来说太长时)将其设置为 true,而在开发时保持 false 以加快重载速度。

{
  autoDeploy: process.env.NODE_ENV === 'production';
}

贡献

运行 git clonecd

yarn # Install dependencies

yarn test # Run tests

yarn example # Run build on all examples

yarn bump [patch|minor|major] # Bump version of remark-codesandbox

yarn release # Publish remark-codesandbox to npm

许可

MIT