diorama-js 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +156 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +156 -15
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +159 -16
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -0
- package/dist/react.d.ts +10 -0
- package/dist/react.js +159 -16
- package/dist/react.js.map +1 -1
- package/dist/svelte.cjs +157 -15
- package/dist/svelte.cjs.map +1 -1
- package/dist/svelte.d.cts +10 -0
- package/dist/svelte.d.ts +10 -0
- package/dist/svelte.js +157 -15
- package/dist/svelte.js.map +1 -1
- package/dist/vue.cjs +159 -16
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.cts +8 -0
- package/dist/vue.d.ts +8 -0
- package/dist/vue.js +159 -16
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -85,6 +85,8 @@ interface ProjectConfig {
|
|
|
85
85
|
jsEntryPoint?: string;
|
|
86
86
|
/** Whether the project uses Vite as its build tool. */
|
|
87
87
|
isVite: boolean;
|
|
88
|
+
/** Whether the project relies on Tailwind CSS (directives or a config file). */
|
|
89
|
+
usesTailwind?: boolean;
|
|
88
90
|
}
|
|
89
91
|
type CDNProviderName = 'esm.sh' | 'skypack' | 'unpkg';
|
|
90
92
|
type CacheStrategy = 'normal' | 'aggressive';
|
|
@@ -141,6 +143,11 @@ interface RenderOptions {
|
|
|
141
143
|
projectType?: ProjectType;
|
|
142
144
|
/** Override entry point detection. */
|
|
143
145
|
entryPoint?: string;
|
|
146
|
+
/**
|
|
147
|
+
* Tailwind CSS handling. `'auto'` (default) loads Tailwind's Play CDN when the
|
|
148
|
+
* project is detected to use Tailwind; `true` forces it on; `false` disables it.
|
|
149
|
+
*/
|
|
150
|
+
tailwind?: 'auto' | boolean;
|
|
144
151
|
/** Glob patterns of files to include. */
|
|
145
152
|
include?: string[];
|
|
146
153
|
/** Glob patterns of files to exclude. */
|
package/dist/index.d.ts
CHANGED
|
@@ -85,6 +85,8 @@ interface ProjectConfig {
|
|
|
85
85
|
jsEntryPoint?: string;
|
|
86
86
|
/** Whether the project uses Vite as its build tool. */
|
|
87
87
|
isVite: boolean;
|
|
88
|
+
/** Whether the project relies on Tailwind CSS (directives or a config file). */
|
|
89
|
+
usesTailwind?: boolean;
|
|
88
90
|
}
|
|
89
91
|
type CDNProviderName = 'esm.sh' | 'skypack' | 'unpkg';
|
|
90
92
|
type CacheStrategy = 'normal' | 'aggressive';
|
|
@@ -141,6 +143,11 @@ interface RenderOptions {
|
|
|
141
143
|
projectType?: ProjectType;
|
|
142
144
|
/** Override entry point detection. */
|
|
143
145
|
entryPoint?: string;
|
|
146
|
+
/**
|
|
147
|
+
* Tailwind CSS handling. `'auto'` (default) loads Tailwind's Play CDN when the
|
|
148
|
+
* project is detected to use Tailwind; `true` forces it on; `false` disables it.
|
|
149
|
+
*/
|
|
150
|
+
tailwind?: 'auto' | boolean;
|
|
144
151
|
/** Glob patterns of files to include. */
|
|
145
152
|
include?: string[];
|
|
146
153
|
/** Glob patterns of files to exclude. */
|
package/dist/index.js
CHANGED
|
@@ -638,6 +638,7 @@ function analyzeProject(project, overrideType, overrideEntry) {
|
|
|
638
638
|
hasBareImports: hasBareImports(files),
|
|
639
639
|
isVite
|
|
640
640
|
});
|
|
641
|
+
const usesTailwind = usesTailwindCSS(files);
|
|
641
642
|
return {
|
|
642
643
|
type,
|
|
643
644
|
entryPoint: htmlEntry,
|
|
@@ -646,7 +647,8 @@ function analyzeProject(project, overrideType, overrideEntry) {
|
|
|
646
647
|
hasJSX,
|
|
647
648
|
hasTypeScript,
|
|
648
649
|
jsEntryPoint: jsEntry,
|
|
649
|
-
isVite
|
|
650
|
+
isVite,
|
|
651
|
+
usesTailwind
|
|
650
652
|
};
|
|
651
653
|
}
|
|
652
654
|
function detectProjectType(input) {
|
|
@@ -668,6 +670,17 @@ function hasBareImports(files) {
|
|
|
668
670
|
}
|
|
669
671
|
return false;
|
|
670
672
|
}
|
|
673
|
+
function usesTailwindCSS(files) {
|
|
674
|
+
for (const [path, content] of files) {
|
|
675
|
+
if (/(?:^|\/)tailwind\.config\.(?:js|cjs|mjs|ts)$/.test(path)) {
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
if (path.endsWith(".css") && /@tailwind\b|@apply\b/.test(content)) {
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return false;
|
|
683
|
+
}
|
|
671
684
|
|
|
672
685
|
// src/core/sandbox.ts
|
|
673
686
|
function buildErrorHTML(message) {
|
|
@@ -1522,6 +1535,18 @@ function getCDNProvider(name) {
|
|
|
1522
1535
|
return esmShProvider;
|
|
1523
1536
|
}
|
|
1524
1537
|
}
|
|
1538
|
+
function buildCSSURL(specifier, options = {}) {
|
|
1539
|
+
const { dependencies = {}, cdnProvider = "esm.sh" } = options;
|
|
1540
|
+
const clean = specifier.replace(/[?#].*$/, "");
|
|
1541
|
+
const { packageName, subpath } = parseSpecifier(clean);
|
|
1542
|
+
const version = dependencies[packageName];
|
|
1543
|
+
const ver = version ? `@${version}` : "";
|
|
1544
|
+
const sub = subpath ? `/${subpath}` : "";
|
|
1545
|
+
if (cdnProvider === "unpkg") {
|
|
1546
|
+
return `https://unpkg.com/${packageName}${ver}${sub}`;
|
|
1547
|
+
}
|
|
1548
|
+
return `https://esm.sh/${packageName}${ver}${sub}`;
|
|
1549
|
+
}
|
|
1525
1550
|
function rewriteImports(source, options = {}) {
|
|
1526
1551
|
const {
|
|
1527
1552
|
dependencies = {},
|
|
@@ -1535,6 +1560,9 @@ function rewriteImports(source, options = {}) {
|
|
|
1535
1560
|
if (raw.startsWith(".") || raw.startsWith("/") || /^https?:\/\//.test(raw)) {
|
|
1536
1561
|
return raw;
|
|
1537
1562
|
}
|
|
1563
|
+
if (/\.css(?:[?#]|$)/.test(raw)) {
|
|
1564
|
+
return raw;
|
|
1565
|
+
}
|
|
1538
1566
|
const { packageName, subpath } = parseSpecifier(raw);
|
|
1539
1567
|
if (NODE_BUILTINS.has(packageName) || NODE_BUILTINS.has(packageName.replace("node:", ""))) {
|
|
1540
1568
|
throw new NodeBuiltinError(packageName);
|
|
@@ -1737,20 +1765,25 @@ var ASSET_IMPORT_EXTENSIONS = {
|
|
|
1737
1765
|
".otf": "font/otf"
|
|
1738
1766
|
};
|
|
1739
1767
|
function assembleHTML(options) {
|
|
1740
|
-
const { project, config, transformedFiles } = options;
|
|
1768
|
+
const { project, config, transformedFiles, cdnProvider, tailwind = "auto" } = options;
|
|
1741
1769
|
const files = transformedFiles ?? project.files;
|
|
1770
|
+
let result;
|
|
1742
1771
|
switch (config.type) {
|
|
1743
1772
|
case "static":
|
|
1744
|
-
|
|
1773
|
+
result = assembleStatic(files, project, config);
|
|
1774
|
+
break;
|
|
1745
1775
|
case "static-esm":
|
|
1746
1776
|
case "jsx":
|
|
1747
1777
|
case "typescript":
|
|
1748
1778
|
case "jsx-typescript":
|
|
1749
1779
|
case "vite":
|
|
1750
|
-
|
|
1780
|
+
result = assembleESM(files, project, config, cdnProvider);
|
|
1781
|
+
break;
|
|
1751
1782
|
default:
|
|
1752
1783
|
throw new AssemblyError(`Unsupported project type: ${config.type}`);
|
|
1753
1784
|
}
|
|
1785
|
+
result.html = applyTailwindRuntime(result.html, project, config, tailwind);
|
|
1786
|
+
return result;
|
|
1754
1787
|
}
|
|
1755
1788
|
function assembleStatic(files, project, config) {
|
|
1756
1789
|
let html = files.get(config.entryPoint);
|
|
@@ -1764,10 +1797,13 @@ function assembleStatic(files, project, config) {
|
|
|
1764
1797
|
html = inlineAssets(html, project, config.entryPoint);
|
|
1765
1798
|
return { html, usesESM: false };
|
|
1766
1799
|
}
|
|
1767
|
-
function assembleESM(files, project, config) {
|
|
1800
|
+
function assembleESM(files, project, config, cdnProvider) {
|
|
1768
1801
|
const isGenerated = config.entryPoint === "__generated__/index.html";
|
|
1769
1802
|
rewriteAssetImports(files, project);
|
|
1770
|
-
const cssFromJS = extractCSSImports(files
|
|
1803
|
+
const { css: cssFromJS, links: cssLinks } = extractCSSImports(files, {
|
|
1804
|
+
dependencies: config.dependencies,
|
|
1805
|
+
cdnProvider
|
|
1806
|
+
});
|
|
1771
1807
|
if (config.isVite) {
|
|
1772
1808
|
injectImportMetaEnv(files);
|
|
1773
1809
|
}
|
|
@@ -1786,6 +1822,9 @@ function assembleESM(files, project, config) {
|
|
|
1786
1822
|
html = rewriteScriptSrcsToImportMap(html, config.entryPoint);
|
|
1787
1823
|
html = inlineAssets(html, project, config.entryPoint);
|
|
1788
1824
|
}
|
|
1825
|
+
for (const href of cssLinks) {
|
|
1826
|
+
html = injectIntoHead(html, `<link rel="stylesheet" href="${href}">`);
|
|
1827
|
+
}
|
|
1789
1828
|
if (cssFromJS) {
|
|
1790
1829
|
html = injectIntoHead(html, `<style>
|
|
1791
1830
|
${cssFromJS}
|
|
@@ -2035,20 +2074,32 @@ function rewriteAssetImports(files, project) {
|
|
|
2035
2074
|
}
|
|
2036
2075
|
}
|
|
2037
2076
|
}
|
|
2038
|
-
function extractCSSImports(files) {
|
|
2077
|
+
function extractCSSImports(files, options = {}) {
|
|
2039
2078
|
const cssChunks = [];
|
|
2040
|
-
const
|
|
2079
|
+
const links = [];
|
|
2080
|
+
const seenLinks = /* @__PURE__ */ new Set();
|
|
2081
|
+
const cssImportRe = /import\s+['"]([^'"]+\.css(?:[?#][^'"]*)?)['"]\s*;?/g;
|
|
2041
2082
|
for (const [path, content] of files) {
|
|
2042
2083
|
if (!/\.(js|ts|jsx|tsx|mjs)$/.test(path)) continue;
|
|
2043
2084
|
let modified = content;
|
|
2044
2085
|
let match;
|
|
2086
|
+
cssImportRe.lastIndex = 0;
|
|
2045
2087
|
while ((match = cssImportRe.exec(content)) !== null) {
|
|
2046
|
-
const
|
|
2047
|
-
const
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2088
|
+
const specifier = match[1];
|
|
2089
|
+
const bare = specifier.replace(/[?#].*$/, "");
|
|
2090
|
+
if (bare.startsWith(".") || bare.startsWith("/")) {
|
|
2091
|
+
const resolved = resolvePath(directoryOf(path), bare);
|
|
2092
|
+
const css = files.get(resolved);
|
|
2093
|
+
if (css) {
|
|
2094
|
+
cssChunks.push(`/* ${resolved} */
|
|
2051
2095
|
${css}`);
|
|
2096
|
+
}
|
|
2097
|
+
} else {
|
|
2098
|
+
const href = /^https?:\/\//.test(bare) ? bare : buildCSSURL(bare, options);
|
|
2099
|
+
if (!seenLinks.has(href)) {
|
|
2100
|
+
seenLinks.add(href);
|
|
2101
|
+
links.push(href);
|
|
2102
|
+
}
|
|
2052
2103
|
}
|
|
2053
2104
|
modified = modified.replace(match[0], "");
|
|
2054
2105
|
}
|
|
@@ -2056,7 +2107,95 @@ ${css}`);
|
|
|
2056
2107
|
files.set(path, modified);
|
|
2057
2108
|
}
|
|
2058
2109
|
}
|
|
2059
|
-
return cssChunks.join("\n\n");
|
|
2110
|
+
return { css: cssChunks.join("\n\n"), links };
|
|
2111
|
+
}
|
|
2112
|
+
var TAILWIND_DIRECTIVE_RE = /@tailwind\b|@apply\b/;
|
|
2113
|
+
var TAILWIND_CDN_URL = "https://cdn.tailwindcss.com";
|
|
2114
|
+
function hasTailwindDirectives(css) {
|
|
2115
|
+
return TAILWIND_DIRECTIVE_RE.test(css);
|
|
2116
|
+
}
|
|
2117
|
+
function applyTailwindRuntime(html, project, config, tailwind) {
|
|
2118
|
+
const enabled = tailwind === true || tailwind === "auto" && (config.usesTailwind ?? usesTailwindCSS(project.files));
|
|
2119
|
+
if (!enabled) return html;
|
|
2120
|
+
html = html.replace(
|
|
2121
|
+
/<style>([\s\S]*?)<\/style>/g,
|
|
2122
|
+
(match, css) => hasTailwindDirectives(css) ? `<style type="text/tailwindcss">${css}</style>` : match
|
|
2123
|
+
);
|
|
2124
|
+
let injection = `<script src="${TAILWIND_CDN_URL}"></script>`;
|
|
2125
|
+
const configObject = extractTailwindConfig(project.files);
|
|
2126
|
+
if (configObject) {
|
|
2127
|
+
injection += `
|
|
2128
|
+
<script>tailwind.config = ${configObject};</script>`;
|
|
2129
|
+
}
|
|
2130
|
+
return injectIntoHead(html, injection);
|
|
2131
|
+
}
|
|
2132
|
+
function extractTailwindConfig(files) {
|
|
2133
|
+
let source;
|
|
2134
|
+
for (const [path, content] of files) {
|
|
2135
|
+
if (/(?:^|\/)tailwind\.config\.(?:js|cjs|mjs|ts)$/.test(path)) {
|
|
2136
|
+
source = content;
|
|
2137
|
+
break;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
if (!source) return null;
|
|
2141
|
+
const object = extractBalancedObject(source);
|
|
2142
|
+
if (!object || !isSafeConfigObject(object)) return null;
|
|
2143
|
+
return object;
|
|
2144
|
+
}
|
|
2145
|
+
function extractBalancedObject(source) {
|
|
2146
|
+
const opener = source.match(/(?:export\s+default|module\.exports\s*=)\s*\{/);
|
|
2147
|
+
if (!opener || opener.index === void 0) return null;
|
|
2148
|
+
const start = opener.index + opener[0].length - 1;
|
|
2149
|
+
let depth = 0;
|
|
2150
|
+
let str = null;
|
|
2151
|
+
let lineComment = false;
|
|
2152
|
+
let blockComment = false;
|
|
2153
|
+
for (let i = start; i < source.length; i++) {
|
|
2154
|
+
const c = source[i];
|
|
2155
|
+
const n = source[i + 1];
|
|
2156
|
+
if (lineComment) {
|
|
2157
|
+
if (c === "\n") lineComment = false;
|
|
2158
|
+
continue;
|
|
2159
|
+
}
|
|
2160
|
+
if (blockComment) {
|
|
2161
|
+
if (c === "*" && n === "/") {
|
|
2162
|
+
blockComment = false;
|
|
2163
|
+
i++;
|
|
2164
|
+
}
|
|
2165
|
+
continue;
|
|
2166
|
+
}
|
|
2167
|
+
if (str) {
|
|
2168
|
+
if (c === "\\") {
|
|
2169
|
+
i++;
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2172
|
+
if (c === str) str = null;
|
|
2173
|
+
continue;
|
|
2174
|
+
}
|
|
2175
|
+
if (c === "/" && n === "/") {
|
|
2176
|
+
lineComment = true;
|
|
2177
|
+
i++;
|
|
2178
|
+
continue;
|
|
2179
|
+
}
|
|
2180
|
+
if (c === "/" && n === "*") {
|
|
2181
|
+
blockComment = true;
|
|
2182
|
+
i++;
|
|
2183
|
+
continue;
|
|
2184
|
+
}
|
|
2185
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2186
|
+
str = c;
|
|
2187
|
+
continue;
|
|
2188
|
+
}
|
|
2189
|
+
if (c === "{") depth++;
|
|
2190
|
+
else if (c === "}") {
|
|
2191
|
+
depth--;
|
|
2192
|
+
if (depth === 0) return source.slice(start, i + 1);
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
return null;
|
|
2196
|
+
}
|
|
2197
|
+
function isSafeConfigObject(object) {
|
|
2198
|
+
return !(/\brequire\s*\(/.test(object) || /\bimport\b/.test(object) || /=>/.test(object) || /\bfunction\b/.test(object) || /`/.test(object) || /\bprocess\b/.test(object) || /\b__dirname\b|\b__filename\b/.test(object));
|
|
2060
2199
|
}
|
|
2061
2200
|
function injectImportMetaEnv(files) {
|
|
2062
2201
|
const shim = `if(!import.meta.env){Object.defineProperty(import.meta,'env',{value:{MODE:'production',BASE_URL:'/',PROD:true,DEV:false,SSR:false}});}`;
|
|
@@ -2167,7 +2306,9 @@ var Diorama = class {
|
|
|
2167
2306
|
const { html: html2, usesESM: usesESM2 } = assembleHTML({
|
|
2168
2307
|
project,
|
|
2169
2308
|
config,
|
|
2170
|
-
transformedFiles: files
|
|
2309
|
+
transformedFiles: files,
|
|
2310
|
+
cdnProvider: this.options.cdnProvider,
|
|
2311
|
+
tailwind: options.tailwind ?? "auto"
|
|
2171
2312
|
});
|
|
2172
2313
|
return { html: html2, usesESM: usesESM2, repoName: repoName2 };
|
|
2173
2314
|
};
|