@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
JavaScript
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 };