@sanity/ui-workshop
Version:
An environment for designing, reviewing, and quality-testing React components.
378 lines (371 loc) • 11.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: !0 });
var cpx = require("cpx"), promises = require("fs/promises"), path = require("path"), rimraf = require("rimraf"), vite = require("vite"), fs = require("fs"), globby = require("globby"), mkdirp = require("mkdirp"), react = require("@vitejs/plugin-react"), chokidar = require("chokidar"), express = require("express");
function _interopDefaultCompat(e) {
return e && typeof e == "object" && "default" in e ? e : { default: e };
}
var cpx__default = /* @__PURE__ */ _interopDefaultCompat(cpx), path__default = /* @__PURE__ */ _interopDefaultCompat(path), rimraf__default = /* @__PURE__ */ _interopDefaultCompat(rimraf), fs__default = /* @__PURE__ */ _interopDefaultCompat(fs), globby__default = /* @__PURE__ */ _interopDefaultCompat(globby), mkdirp__default = /* @__PURE__ */ _interopDefaultCompat(mkdirp), react__default = /* @__PURE__ */ _interopDefaultCompat(react), chokidar__default = /* @__PURE__ */ _interopDefaultCompat(chokidar), express__default = /* @__PURE__ */ _interopDefaultCompat(express);
function _fileExists(file) {
try {
return fs.accessSync(file), !0;
} catch {
return !1;
}
}
const RUNTIME_FILE_NAMES = ["workshop.runtime.js", "workshop.runtime.jsx", "workshop.runtime.mjs", "workshop.runtime.cjs", "workshop.runtime.ts", "workshop.runtime.tsx"];
function _findRuntimeFile(options) {
const {
packagePath
} = options;
for (const f of RUNTIME_FILE_NAMES) {
const file = path__default.default.resolve(packagePath, f);
if (_fileExists(file)) return file;
}
}
async function _loadRuntime(options) {
const {
packagePath
} = options, configPath = _findRuntimeFile({
packagePath
});
if (!configPath)
return;
const {
register
} = require("esbuild-register/dist/node"), eslintOptions = {
// eslint options
jsx: "automatic",
jsxFactory: "createElement",
jsxFragment: "Fragment",
jsxImportSource: "react",
logLevel: "silent"
}, {
unregister
} = globalThis.__DEV__ ? {
unregister: () => {
}
} : register(eslintOptions), config = require(configPath);
return unregister(), config?.default || config;
}
const DEFAULT_PATTERN = ["src/**/__workshop__/index.js", "src/**/__workshop__/index.jsx", "src/**/__workshop__/index.ts", "src/**/__workshop__/index.tsx"];
function _getFiles(options) {
const {
cwd,
pattern
} = options;
return {
subscribe(observer) {
return globby__default.default(pattern, {
cwd
}).then((files) => {
observer.next(files.map((f) => path__default.default.resolve(cwd, f)));
}), {
unsubscribe() {
}
};
}
};
}
function _sanitizeModulePath(modulePath) {
return modulePath.replace(/\.[^/.]+$/, "").replace(/\/index$/, "");
}
function _compileModule(paths) {
if (paths.length === 0)
return `// THIS FILE IS AUTO-GENERATED
export const scopes = []
`;
const sortedPaths = paths.sort(), imports = sortedPaths.map((p, idx) => `import _${idx} from '${_sanitizeModulePath(p)}'`).join(`
`), exports2 = sortedPaths.map((_p, idx) => ` _${idx}`).join(`,
`);
return ["// THIS FILE IS AUTO-GENERATED", imports, `export const scopes = [
${exports2},
]`].join(`
`) + `
`;
}
const HTML$1 = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, viewport-fit=cover"
/>
<style>
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
-webkit-font-smoothing: antialiased;
}
html,
body,
#root {
height: 100%;
margin: 0;
}
</style>
</head>
<body>
<div id="root"></div>
<script>
if (window.parent !== window) {
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__
}
<\/script>
<script type="module" src="/.workshop/frame/main.tsx"><\/script>
</body>
</html>
`;
async function _writeFrameHTML(options) {
await promises.writeFile(path__default.default.resolve(options.outDir, "frame/index.html"), HTML$1);
}
const SCRIPT$1 = `// THIS FILE IS AUTO-GENERATED
import {mountFrame} from '@sanity/ui-workshop'
import {scopes} from '../scopes'
import config from '../../workshop.config'
mountFrame({
config: {...config, scopes},
element: document.getElementById('root'),
})
`;
async function _writeFrameScript(options) {
await promises.writeFile(path__default.default.resolve(options.outDir, "frame/main.tsx"), SCRIPT$1);
}
const HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, viewport-fit=cover"
/>
<style>
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
-webkit-font-smoothing: antialiased;
}
html,
body,
#root {
height: 100%;
margin: 0;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="module" src="/.workshop/main.tsx"><\/script>
</body>
</html>
`;
async function _writeHTML(options) {
await promises.writeFile(path__default.default.resolve(options.outDir, "index.html"), HTML);
}
const SCRIPT = `// THIS FILE IS AUTO-GENERATED
import {mount} from '@sanity/ui-workshop'
import {scopes} from './scopes'
import config from '../workshop.config'
mount({
config: {...config, scopes},
element: document.getElementById('root'),
})
`;
async function _writeScript(options) {
await promises.writeFile(path__default.default.resolve(options.outDir, "main.tsx"), SCRIPT);
}
async function buildStaticFiles(options) {
const {
runtimeDir
} = options;
await mkdirp__default.default(runtimeDir), await _writeHTML({
outDir: runtimeDir
}), await _writeScript({
outDir: runtimeDir
}), await mkdirp__default.default(path__default.default.resolve(runtimeDir, "frame")), await _writeFrameHTML({
outDir: runtimeDir
}), await _writeFrameScript({
outDir: runtimeDir
});
}
function createViteConfig(options) {
const {
cwd,
outDir,
runtimeDir
} = options;
return {
build: {
outDir,
rollupOptions: {
input: {
main: path__default.default.resolve(runtimeDir, "index.html"),
frame: path__default.default.resolve(runtimeDir, "frame/index.html")
}
}
},
optimizeDeps: {
esbuildOptions: {
jsx: "automatic"
}
},
plugins: [react__default.default({
babel: {
plugins: [["babel-plugin-react-compiler", {
target: "19"
}]]
}
})],
root: cwd
};
}
function getScopes(options) {
return new Promise((resolve) => {
_getFiles(options).subscribe({
next: resolve
});
});
}
async function build(options) {
const {
cwd
} = options, runtime = await _loadRuntime({
packagePath: cwd
}), runtimeDir = path__default.default.resolve(cwd, ".workshop"), outDir = runtime?.build?.outDir || path__default.default.resolve(cwd, "dist");
await buildStaticFiles({
runtimeDir
});
const relativeScopes = (await getScopes({
cwd,
pattern: runtime?.pattern || DEFAULT_PATTERN
})).map((f) => path__default.default.relative(outDir, f)), code = _compileModule(relativeScopes);
await promises.writeFile(path__default.default.resolve(runtimeDir, "scopes.ts"), code);
const baseViteConfig = createViteConfig({
cwd,
outDir,
runtimeDir
});
let viteConfig = runtime?.vite?.(baseViteConfig) || baseViteConfig;
typeof viteConfig == "object" && "then" in viteConfig && (viteConfig = await viteConfig), await vite.build(viteConfig), cpx__default.default.copySync(path__default.default.resolve(outDir, ".workshop", "**/*"), outDir), await rimraf__default.default(path__default.default.resolve(outDir, ".workshop"));
}
function _watchFiles(options) {
const {
cwd,
pattern
} = options;
return {
subscribe(observer) {
const watcher = chokidar__default.default.watch(pattern, {
cwd,
ignoreInitial: !0
});
return watcher.on("all", (event, file) => {
observer.next({
type: event,
file: path__default.default.resolve(cwd, file)
});
}), {
unsubscribe() {
watcher.close();
}
};
}
};
}
function _watchScopes(options) {
return {
subscribe(observer) {
const initialFiles$ = _getFiles(options), fileEvent$ = _watchFiles(options);
let files;
initialFiles$.subscribe({
next(initialFiles) {
files = initialFiles, observer.next(files);
}
});
const fileEventSub = fileEvent$.subscribe({
next(event) {
if (event.type === "add" && (files.push(event.file), observer.next(files)), event.type === "unlink") {
const idx = files.indexOf(event.file);
idx && (files.splice(idx, 1), observer.next(files));
}
}
});
return {
unsubscribe() {
fileEventSub.unsubscribe();
}
};
}
};
}
async function createDevServer(options) {
const {
cwd,
outDir,
runtime,
runtimeDir
} = options, baseViteConfig = {
...createViteConfig({
cwd,
outDir,
runtimeDir
}),
appType: "custom",
// don't include HTML middlewares
configFile: !1,
logLevel: "info",
server: {
middlewareMode: !0
}
};
let viteConfig = runtime?.vite?.(baseViteConfig) || baseViteConfig;
typeof viteConfig == "object" && "then" in viteConfig && (viteConfig = await viteConfig);
const vite$1 = await vite.createServer(viteConfig), app = express__default.default();
return app.use(vite$1.middlewares), app.use("*all", async (req, res) => {
const url = req.originalUrl;
let htmlPath = "index.html";
req.path === "/frame/" && (htmlPath = "frame/index.html");
try {
const template = await promises.readFile(path__default.default.resolve(runtimeDir, htmlPath), "utf-8"), html = await vite$1.transformIndexHtml(url, template);
res.status(200).set({
"Content-Type": "text/html"
}).send(html);
} catch (e) {
e instanceof Error ? (vite$1.ssrFixStacktrace(e), console.log(e.stack), res.status(500).end(e.stack)) : res.status(500).end(String(e));
}
}), app;
}
async function dev(options) {
const {
cwd
} = options, runtime = await _loadRuntime({
packagePath: cwd
}), runtimeDir = path__default.default.resolve(cwd, ".workshop"), outDir = path__default.default.resolve(cwd, "dist");
await buildStaticFiles({
runtimeDir
});
const scopesSub = _watchScopes({
cwd,
pattern: runtime?.pattern || DEFAULT_PATTERN
}).subscribe({
next: (scopes) => {
const relativeScopes = scopes.map((f) => path__default.default.relative(runtimeDir, f)), code = _compileModule(relativeScopes);
fs__default.default.writeFileSync(path__default.default.resolve(runtimeDir, "scopes.ts"), code);
}
}), app = await createDevServer({
cwd,
outDir,
runtime,
runtimeDir
}), port = runtime?.server?.port || 1337;
app.listen(port, () => {
console.log(`listening on http://localhost:${port}`);
}).on("close", () => {
console.log("server closed"), scopesSub.unsubscribe(), process.exit(1);
});
}
exports.build = build;
exports.dev = dev;
//# sourceMappingURL=runtime.cjs.map