UNPKG

@codesandbox/sandpack-client

Version:

<img style="width:100%" src="https://user-images.githubusercontent.com/4838076/143581035-ebee5ba2-9cb1-4fe8-a05b-2f44bd69bb4b.gif" alt="Component toolkit for live running code editing experiences" />

204 lines (200 loc) 8.88 kB
import { g as __extends, _ as __awaiter, a as __generator } from './utils-52664384.mjs'; import { PreviewController } from 'static-browser-server'; import { E as EventEmitter, c as consoleHook, g as generateRandomId, f as fromBundlerFilesToFS } from './consoleHook-59e792cb.mjs'; import { S as SandpackClient } from './base-80a1f760.mjs'; import 'outvariant'; import 'dequal'; var insertHtmlAfterRegex = function (regex, content, insertable) { var match = regex.exec(content); if (match && match.length >= 1) { var offset = match.index + match[0].length; var prefix = content.substring(0, offset); var suffix = content.substring(offset); return prefix + insertable + suffix; } }; var readBuffer = function (content) { if (typeof content === "string") { return content; } else { return new TextDecoder().decode(content); } }; var validateHtml = function (content) { // Make it a string var contentString = readBuffer(content); var domParser = new DOMParser(); var doc = domParser.parseFromString(contentString, "text/html"); if (!doc.documentElement.getAttribute("lang")) { doc.documentElement.setAttribute("lang", "en"); } var html = doc.documentElement.outerHTML; return "<!DOCTYPE html>\n".concat(html); }; var SandpackStatic = /** @class */ (function (_super) { __extends(SandpackStatic, _super); function SandpackStatic(selector, sandboxSetup, options) { if (options === void 0) { options = {}; } var _a; var _this = _super.call(this, selector, sandboxSetup, options) || this; _this.files = new Map(); _this.status = "initializing"; _this.emitter = new EventEmitter(); _this.previewController = new PreviewController({ baseUrl: (_a = options.bundlerURL) !== null && _a !== void 0 ? _a : "https://preview.sandpack-static-server.codesandbox.io", // filepath is always normalized to start with / and not end with a slash getFileContent: function (filepath) { var content = _this.files.get(filepath); if (!content) { throw new Error("File not found"); } if (filepath.endsWith(".html") || filepath.endsWith(".htm")) { try { content = validateHtml(content); content = _this.injectProtocolScript(content); content = _this.injectExternalResources(content, options.externalResources); content = _this.injectScriptIntoHead(content, { script: consoleHook, scope: { channelId: generateRandomId() }, }); } catch (err) { console.error("Runtime injection failed", err); } } return content; }, }); if (typeof selector === "string") { _this.selector = selector; var element = document.querySelector(selector); _this.element = element; _this.iframe = document.createElement("iframe"); } else { _this.element = selector; _this.iframe = selector; } if (!_this.iframe.getAttribute("sandbox")) { _this.iframe.setAttribute("sandbox", "allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts allow-downloads allow-pointer-lock"); _this.iframe.setAttribute("allow", "accelerometer; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; clipboard-read; clipboard-write; xr-spatial-tracking;"); } _this.eventListener = _this.eventListener.bind(_this); if (typeof window !== "undefined") { window.addEventListener("message", _this.eventListener); } // Dispatch very first compile action _this.updateSandbox(); return _this; } SandpackStatic.prototype.injectContentIntoHead = function (content, contentToInsert) { var _a; // Make it a string content = readBuffer(content); // Inject script content = (_a = insertHtmlAfterRegex(/<head[^<>]*>/g, content, "\n" + contentToInsert)) !== null && _a !== void 0 ? _a : contentToInsert + "\n" + content; return content; }; SandpackStatic.prototype.injectProtocolScript = function (content) { var scriptToInsert = "<script>\n window.addEventListener(\"message\", (message) => {\n if(message.data.type === \"refresh\") {\n window.location.reload();\n }\n })\n</script>"; return this.injectContentIntoHead(content, scriptToInsert); }; SandpackStatic.prototype.injectExternalResources = function (content, externalResources) { if (externalResources === void 0) { externalResources = []; } var tagsToInsert = externalResources .map(function (resource) { var match = resource.match(/\.([^.]*)$/); var fileType = match === null || match === void 0 ? void 0 : match[1]; if (fileType === "css" || resource.includes("fonts.googleapis")) { return "<link rel=\"stylesheet\" href=\"".concat(resource, "\">"); } if (fileType === "js") { return "<script src=\"".concat(resource, "\"></script>"); } throw new Error("Unable to determine file type for external resource: ".concat(resource)); }) .join("\n"); return this.injectContentIntoHead(content, tagsToInsert); }; SandpackStatic.prototype.injectScriptIntoHead = function (content, opts) { var script = opts.script, _a = opts.scope, scope = _a === void 0 ? {} : _a; var scriptToInsert = "\n <script>\n const scope = ".concat(JSON.stringify(scope), ";\n ").concat(script, "\n </script>\n ").trim(); return this.injectContentIntoHead(content, scriptToInsert); }; SandpackStatic.prototype.updateSandbox = function (setup, _isInitializationCompile) { if (setup === void 0) { setup = this.sandboxSetup; } var modules = fromBundlerFilesToFS(setup.files); /** * Pass init files to the bundler */ this.dispatch({ codesandbox: true, modules: modules, template: setup.template, type: "compile", }); }; SandpackStatic.prototype.compile = function (files) { return __awaiter(this, void 0, void 0, function () { var previewUrl; return __generator(this, function (_a) { switch (_a.label) { case 0: this.files = new Map(Object.entries(files)); return [4 /*yield*/, this.previewController.initPreview()]; case 1: previewUrl = _a.sent(); this.iframe.setAttribute("src", previewUrl); this.status = "done"; this.dispatch({ type: "done", compilatonError: false }); this.dispatch({ type: "urlchange", url: previewUrl, back: false, forward: false, }); return [2 /*return*/]; } }); }); }; // Handles message windows coming from iframes SandpackStatic.prototype.eventListener = function (evt) { // skip events originating from different iframes if (evt.source !== this.iframe.contentWindow) { return; } var message = evt.data; if (!message.codesandbox) { return; } this.dispatch(message); }; /** * Bundler communication */ SandpackStatic.prototype.dispatch = function (message) { var _a; switch (message.type) { case "compile": this.compile(message.modules); break; default: (_a = this.iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.postMessage(message, "*"); this.emitter.dispatch(message); } }; SandpackStatic.prototype.listen = function (listener) { return this.emitter.listener(listener); }; SandpackStatic.prototype.destroy = function () { this.emitter.cleanup(); if (typeof window !== "undefined") { window.removeEventListener("message", this.eventListener); } }; return SandpackStatic; }(SandpackClient)); export { SandpackStatic };