Skip to content

Commit

Permalink
sandpack support auto import
Browse files Browse the repository at this point in the history
  • Loading branch information
mantou132 committed Nov 20, 2024
1 parent 7f505f6 commit cfba53f
Show file tree
Hide file tree
Showing 19 changed files with 154 additions and 109 deletions.
23 changes: 16 additions & 7 deletions crates/swc-plugin-gem/package.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
{
"name": "swc-plugin-gem",
"version": "0.1.0",
"description": "",
"author": "",
"license": "ISC",
"description": "swc plugin for Gem",
"keywords": [
"swc-plugin",
"gem",
"web components"
],
"main": "swc_gem_plugin.wasm",
"main": "swc_plugin_gem.wasm",
"files": [],
"scripts": {
"prepublishOnly": "cargo build-wasi --release && cp ../../target/wasm32-wasip1/release/swc_gem_plugin.wasm .",
"prepublishOnly": "cross-env CARGO_TARGET_DIR=target cargo build-wasi --release && cp target/wasm32-wasip1/release/swc_plugin_gem.wasm .",
"test": "cargo watch -x test"
},
"files": [],
"preferUnplugged": true
"preferUnplugged": true,
"author": "mantou132",
"license": "ISC",
"repository": {
"type": "git",
"url": "git+https://github.com/mantou132/gem.git",
"directory": "crates/swc-plugin-gem"
},
"bugs": {
"url": "https://github.com/mantou132/gem/issues"
},
"homepage": "https://github.com/mantou132/gem#readme"
}
62 changes: 62 additions & 0 deletions crates/swc-plugin-gem/src/auto-import.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"comment1": "SheetToken、UpdateToken、directive、repeat、render、connect 和 version 不自动导入",
"comment2": "types 不自动导入,例如 Emitter<T>",
"members": {
"@mantou/gem": [
"GemElement",
"TemplateResult",
"css",
"html",
"mathml",
"svg",

"aria",
"async",
"shadow",
"light",
"adoptedStyle",
"connectStore",
"customElement",

"part",
"slot",

"attribute",
"numattribute",
"boolattribute",
"property",
"emitter",
"globalemitter",
"state",

"effect",
"memo",
"willMount",
"mounted",
"unmounted",
"template",
"fallback",

"createRef",
"createState",
"createStore",

"raw",
"styled",
"styleMap",
"classMap",
"partMap",
"exportPartsMap"
]
},
"elements": {
"@mantou/gem": {
"gem-(gesture|link|reflect|route|title|unsafe|use)": "/elements/$1"
},
"duoyun-ui": {
"dy-pat-*": "/patterns/*",
"dy-input-*": "/elements/input",
"dy-*": "/elements/*"
}
}
}
4 changes: 1 addition & 3 deletions packages/duoyun-ui/docs/en/02-elements/coach-mark.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
<gbp-sandpack dependencies="@mantou/gem,duoyun-ui">

```ts
import { render, html } from '@mantou/gem';
import { render } from '@mantou/gem';
import { setTours } from 'duoyun-ui/elements/coach-mark';

import 'duoyun-ui/elements/side-navigation';

setTours(
[
{
Expand Down
4 changes: 1 addition & 3 deletions packages/duoyun-ui/docs/en/02-elements/map.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
<gbp-sandpack dependencies="@mantou/gem, duoyun-ui, geo-albers-usa-territories">

```ts
import { render, html } from '@mantou/gem';
import { render } from '@mantou/gem';
import { geoAlbersUsaTerritories } from 'geo-albers-usa-territories';

import 'duoyun-ui/elements/map';

const getProjection = (geoCommonProjection: GeoCommonProjection) => {
return geoAlbersUsaTerritories().scale(400).translate([0, 0]);
};
Expand Down
5 changes: 1 addition & 4 deletions packages/duoyun-ui/docs/en/02-elements/popover.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
<gbp-sandpack dependencies="@mantou/gem, duoyun-ui">

```ts
import { render, html } from '@mantou/gem';

import 'duoyun-ui/elements/popover';
import 'duoyun-ui/elements/button';
import { render } from '@mantou/gem';

render(
html`
Expand Down
4 changes: 1 addition & 3 deletions packages/duoyun-ui/docs/zh/02-elements/coach-mark.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
<gbp-sandpack dependencies="@mantou/gem,duoyun-ui">

```ts
import { render, html } from '@mantou/gem';
import { render } from '@mantou/gem';
import { setTours } from 'duoyun-ui/elements/coach-mark';

import 'duoyun-ui/elements/side-navigation';

setTours(
[
{
Expand Down
4 changes: 1 addition & 3 deletions packages/duoyun-ui/docs/zh/02-elements/map.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
<gbp-sandpack dependencies="@mantou/gem, duoyun-ui">

```ts
import { render, html } from '@mantou/gem';

import 'duoyun-ui/elements/map';
import { render } from '@mantou/gem';

const getProjection = (geoCommonProjection: GeoCommonProjection) => {
return geoCommonProjection()
Expand Down
5 changes: 1 addition & 4 deletions packages/duoyun-ui/docs/zh/02-elements/popover.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
<gbp-sandpack dependencies="@mantou/gem, duoyun-ui">

```ts
import { render, html } from '@mantou/gem';

import 'duoyun-ui/elements/popover';
import 'duoyun-ui/elements/button';
import { render } from '@mantou/gem';

render(
html`
Expand Down
70 changes: 66 additions & 4 deletions packages/gem-book/src/plugins/sandpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
import type { GemBookElement } from '../element';
import type { Pre } from '../element/elements/pre';

const AUTO_IMPORT = 'https://raw.githubusercontent.com/mantou132/gem/main/crates/swc-plugin-gem/src/auto-import.json';
const ESBUILD_URL = 'https://esm.sh/esbuild-wasm@0.24.0';
const CSB_URL = 'https://codesandbox.io/api/v1/sandboxes/define?json=1';
const SANDPACK_CLIENT_ESM = 'https://esm.sh/@codesandbox/sandpack-client@2.18.2?bundle';
Expand Down Expand Up @@ -79,6 +80,7 @@ const {
createState,
willMount,
mounted,
raw,
} = GemBookPluginElement.Gem;

const styles = css`
Expand Down Expand Up @@ -214,7 +216,7 @@ class _GbpSandpackElement extends GemBookPluginElement {

get #indexTemplate() {
const style = getComputedStyle(document.body);
return `
return raw`
<!DOCTYPE html>
<style>
body {
Expand Down Expand Up @@ -427,11 +429,71 @@ class _GbpSandpackElement extends GemBookPluginElement {
return loadSandpackClient;
};

#importConfig: { members: Record<string, Set<string>>; tagMap: Map<RegExp, string> };
#loadAutoImportConfig = async () => {
const { keys, fromEntries, entries } = Object;
const deps = new Set(keys(this.#dependencies));
const trans = (config: { members: Record<string, string[]>; elements: Record<string, Record<string, string>> }) => {
const pkgAutoImport = fromEntries(
entries(config.members)
.filter(([pkg]) => deps.has(pkg))
.map(([pkg, set]) => [pkg, new Set(set)] as const),
);
const tagReplacer = entries(config.elements)
.filter(([pkg]) => deps.has(pkg))
.map(([pkg, map]) =>
entries(map).map(
([tag, path]) => [new RegExp(tag.replace('*', '(.*)')), `${pkg}${path.replace('*', '$1')}`] as const,
),
);
return { members: pkgAutoImport, tagMap: new Map(tagReplacer.flat()) };
};
try {
this.#importConfig = trans(JSON.parse(await (await fetch(AUTO_IMPORT)).text()));
} catch {
// TODO: remove content;
this.#importConfig = trans({ members: {}, elements: {} });
}
};

// 在第一行加入自动导入内容,将导致 error stack 行数多报一行
#applyImport = ({ code, filename }: { filename: string; code: string }) => {
if (!filename.match(/\.m?(j|t)s$/i)) return code;
const { members, tagMap } = this.#importConfig;
const autoImportMembers = Object.fromEntries(Object.entries(members).map(([pkg, set]) => [pkg, new Set(set)]));
[...code.matchAll(/import\s*(type)?\s*{(?<line>.*?)}\s*from\s*('|")(?<pkg>.*?)\3/gs)].forEach((match) => {
const { line, pkg } = match.groups!;
const imported = line.split(',').map((e) => e.trim());
imported.forEach((member) => autoImportMembers[pkg]?.delete(member));
});
const importLines = new Set<string>();
Object.entries(autoImportMembers).forEach(([pkg, set]) => {
if (set.size) importLines.add(`import {${[...set].join(',')}} from '${pkg}'`);
});
new Set([...code.matchAll(/<(?<tag>\w+(-\w+)+)(\s|>)/gs)].map((match) => match.groups!.tag)).forEach((tag) => {
for (const [reg, replace] of tagMap) {
const importPath = tag.replace(reg, replace);
if (importPath !== tag) {
importLines.add(`import '${importPath}'`);
break;
}
}
// 自动导入元素
for (const file of this.#state.files) {
if (file.filename === `${tag}.ts`) {
importLines.add(`import './${tag}'`);
}
}
});
return [...importLines].join(';') + '\n' + code;
};

#initSandpackClient = async () => {
await this.#loadAutoImportConfig();
return (this.#useESMBuild ? this.#loadESBuildClient : await this.#getLoadSandpackClient())(
this.#iframeRef.value!,
{
files: this.#state.files.reduce((p, c) => ({ ...p, [c.filename]: { code: c.code } }), {
files: this.#state.files.reduce((p, c) => ({ ...p, [c.filename]: { code: this.#applyImport(c) } }), {
'sandbox.config.json': this.#sandBoxConfigFile,
'index.html': { code: this.#indexTemplate },
[this.#defaultEntryFilename]: { code: '' },
Expand All @@ -450,7 +512,7 @@ class _GbpSandpackElement extends GemBookPluginElement {

#updateSandbox = Utils.throttle(async () => {
(await this.#sandpackClient)?.updateSandbox({
files: this.#state.files.reduce((p, c) => ({ ...p, [c.filename]: { code: c.code } }), {
files: this.#state.files.reduce((p, c) => ({ ...p, [c.filename]: { code: this.#applyImport(c) } }), {
'sandbox.config.json': this.#sandBoxConfigFile,
'index.html': { code: this.#indexTemplate },
} as SandpackBundlerFiles),
Expand Down Expand Up @@ -483,7 +545,7 @@ class _GbpSandpackElement extends GemBookPluginElement {
const normalizedFiles = this.#state.files.reduce(
(p, c) => ({
...p,
[c.filename.replace('/', '')]: { content: c.code },
[c.filename.replace('/', '')]: { content: this.#applyImport(c) },
}),
{
'sandbox.config.json': { content: this.#sandBoxConfigFile.code },
Expand Down
11 changes: 1 addition & 10 deletions packages/gem/docs/en/001-guide/001-basic/001-reactive-element.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,7 @@ class MyElement extends GemElement {
<gbp-sandpack dependencies="@mantou/gem">

```js index.js
import {
createStore,
GemElement,
render,
html,
attribute,
property,
connectStore,
customElement,
} from '@mantou/gem';
import { render } from '@mantou/gem';

const store= createStore({ count: 0 });

Expand Down
4 changes: 0 additions & 4 deletions packages/gem/docs/en/001-guide/001-basic/004-route.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ Gem built-in elements `<gem-route>` and `<gem-link>` work like this.
<gbp-sandpack dependencies="@mantou/gem">

```js index.js
import { GemElement, html, customElement } from '@mantou/gem';
import '@mantou/gem/elements/link';
import '@mantou/gem/elements/route';

const routes = {
home: {
pattern: '/',
Expand Down
4 changes: 1 addition & 3 deletions packages/gem/docs/en/001-guide/002-advance/001-icon.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
<gbp-sandpack dependencies="@mantou/gem">

```js index.js
import { html, render } from '@mantou/gem';

import '@mantou/gem/elements/use';
import { render } from '@mantou/gem';

const icon = `
<svg width="24" height="24" viewBox="0 0 24 24">
Expand Down
2 changes: 0 additions & 2 deletions packages/gem/docs/en/001-guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import * as Gem from 'https://esm.sh/@mantou/gem';
<gbp-sandpack dependencies="@mantou/gem">

```js index.js
import { GemElement, html, customElement } from '@mantou/gem';

@customElement('my-element')
class MyElement extends GemElement {
render() {
Expand Down
20 changes: 0 additions & 20 deletions packages/gem/docs/en/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,8 @@ features:
<gbp-sandpack dependencies="@mantou/gem, duoyun-ui">

```ts
import { customElement, GemElement, html, render, connectStore, createState } from '@mantou/gem';

import { todoData, addItem } from './store';

import 'duoyun-ui/elements/input';
import 'duoyun-ui/elements/button';
import 'duoyun-ui/elements/heading';
import './todo-list';

@customElement('app-root')
@connectStore(todoData)
export class AppRootElement extends GemElement {
Expand Down Expand Up @@ -79,21 +72,10 @@ export class AppRootElement extends GemElement {
```

```ts todo-list.ts
import {
customElement,
GemElement,
html,
render,
connectStore,
css,
adoptedStyle,
} from '@mantou/gem';
import { icons } from 'duoyun-ui/lib/icons';

import { todoData, deleteItem } from './store';

import 'duoyun-ui/elements/use';

const style = css`
ul {
padding: 0;
Expand Down Expand Up @@ -141,8 +123,6 @@ export class TodoListElement extends GemElement {
```

```ts store.ts
import { createStore } from '@mantou/gem';

type Store = { items: string[] };

export const todoData = createStore<Store>({ items: [] });
Expand Down
Loading

0 comments on commit cfba53f

Please sign in to comment.