将任何组件封装成一个自包含的、独立的小组件
Warning: This project is very experimental. APIs may change without notice.
Package any component into a self-contained, isolated widget.
Works with React, Solid, Svelte, vanilla JS, or anything that can render into a DOM element. Ships as a script tag, ESM import, or CommonJS require.
npm install isolet-js
The core API is one function: createIsolet. You give it a name, a mount function, and optionally some CSS. It gives you back mount, update, and unmount.
import { createIsolet } from "isolet-js";
import { react } from "isolet-js/react";
function Hello({ name }: { name: string }) {
return
Hello, {name}!
;
}
const widget = createIsolet({
name: "hello",
mount: react(Hello),
css: `h1 { color: tomato; font-family: sans-serif; }`,
});
widget.mount(document.body, { name: "World" });
The component renders inside a shadow DOM by default. Styles are scoped. Nothing leaks in or out.
Distribute your component as a self-contained bundle. The CLI reads your config, resolves CSS + assets, and outputs a drop-in artifact.
npx isolet-js init # scaffold an isolet.config.ts
npx isolet-js build # bundle widget(s) from config
npx isolet-js build --watch # rebuild on changes
npx isolet-js build --minify # minified production build
…
You can also export an array for multiple widgets:
export default defineConfig([
{ name: "widget-a", entry: "./src/a.ts", styles: "./src/a.css" },
{ name: "widget-b", entry: "./src/b.ts", format: ["esm"] },
]);
styles from config, inlines all url() references (fonts, images) as data URIs__ISOLET_CSS__ in your entry code.css imports to JS string exports (shadow DOM safe).png, .woff2, .mp3, etc.) as data URIsstyles: "./path.css" in createIsolet/defineElement calls at build timeformatAdapters are thin wrappers that handle framework-specific mounting. The core doesn't import or depend on any framework.
import { createIsolet } from "isolet-js";
import { react } from "isolet-js/react";
import { MyComponent } from "./MyComponent";
const widget = createIsolet({
name: "my-widget",
mount: react(MyComponent),
css: styles,
});
widget.mount(document.body, { title: "Hello" });
widget.update({ title: "Updated" });
widget.unmount();
import { createIsolet } from "isolet-js";
import { vanilla } from "isolet-js/vanilla";
const widget = createIsolet({
name: "counter",
mount: vanilla((container, props) => {
let count = props.initial ?? 0;
const btn = document.createElement("button");
btn.textContent = `Count: ${count}`;
btn.onclick = () => { btn.textContent = `Count: ${++count}`; };
container.appendChild(btn);
return () => container.removeChild(btn);
}),
});
The mount function is just (container: HTMLElement, props) => cleanup | void. Use whatever you want:
// Solid
import { render } from "solid-js/web";
createIsolet({
name: "solid-widget",
mount(container, props) {
const dispose = render(() => , container);
return dispose;
},
});
// Svelte
import App from "./App.svelte";
createIsolet({
name: "svelte-widget",
mount(container, props) {
const app = new App({ target: container, props });
return () => app.$destroy();
},
});
Control how the widget is isolated from the host page.
createIsolet({
name: "my-widget",
mount: myMount,
isolation: "shadow-dom", // default: full CSS isolation via shadow DOM
});
createIsolet({
name: "my-widget",
mount: myMount,
isolation: "scoped", // plain div wrapper, styles injected globally
});
createIsolet({
name: "my-widget",
mount: myMount,
isolation: "none", // mount directly into the target element
});
isolet build automatically handles CSS and assets — no manual plugin setup required:
styles in config → CSS files are read, all url() references (fonts, images) are inlined as data URIs, and the result is available as __ISOLET_CSS__ in your entry.css imports → converted to JS string exports (shadow DOM safe).png, .woff2, .mp3, etc.) → inlined as data URIsstyles: "./path.css" in createIsolet/defineElement → resolved and inlined at build time// Your entry file — just reference css, the CLI handles the rest
createIsolet({
name: "my-widget",
css: __ISOLET_CSS__, // injected by isolet build from config styles field
mount: myMount,
});
// Or inline the path directly:
createIsolet({
name: "my-widget",
styles: "./widget.css", // auto-resolved at build time
mount: myMount,
});
If you're using vp pack or Vite directly instead of the CLI, add the plugins manually:
// vite.config.ts
import { cssTextPlugin, inlineAssetsPlugin, autoStylesPlugin } from "isolet-js/plugins";
The IIFE build exposes Isolet on the global scope:
createIsolet(options)| Option | Type | Default | Description |
|---|---|---|---|
name |
string |
required | Unique identifier for the widget |
mount |
(container, props) => cleanup? |
required | Render function |
css |
string |
- | CSS text to inject |
isolation |
"shadow-dom" | "scoped" | "none" |
"shadow-dom" |
Isolation strategy |
shadowMode |
"open" | "closed" |
"open" |
Shadow DOM mode |
hostAttributes |
Record |
- | Attributes on host element |
zIndex |
string | number |
- | z-index on host element |
Returns an IsoletInstance:
| Method/Property | Description |
|---|---|
mount(target?, props?) |
Mount into target (defaults to document.body) |
update(props) |
Update with partial props |
unmount() |
Unmount and clean up |
container |
The render container element |
shadowRoot |
The shadow root (if shadow DOM mode) |
mounted |
Whether currently mounted |
MIT
暂无开放 Issues,或尚未同步最近议题。