Add Tailwind CSS toggle, Markdown/WASM modes, and npm import resolution
- Tailwind CSS: toolbar checkbox injects Play CDN into preview, persisted per-fiddle via new options JSON column - Markdown mode: uses marked.js CDN, renders markdown to HTML preview with CSS tab for custom styling - WASM mode: starter template with inline WebAssembly add function, supports top-level await via module detection - npm imports: auto-detect bare import specifiers in module code and inject importmap pointing to esm.sh CDN - Module auto-detection for html-css-js mode (import/export statements) - DB migration adds options column, server passes through all API endpoints - All features work across preview, export, and embed
This commit is contained in:
43
public/js/import-map.js
Normal file
43
public/js/import-map.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Extract bare import specifiers from JS code.
|
||||
* Matches `from 'pkg'`, `from "pkg"`, `import 'pkg'`, `import "pkg"`
|
||||
* where the specifier doesn't start with `.`, `/`, `http:`, or `https:`.
|
||||
*/
|
||||
export function extractBareImports(jsCode) {
|
||||
const imports = new Set();
|
||||
const re = /(?:import\s+(?:[\s\S]*?\s+from\s+)?['"])([^'"\s][^'"]*?)(?=['"])/g;
|
||||
let match;
|
||||
while ((match = re.exec(jsCode)) !== null) {
|
||||
const spec = match[1];
|
||||
// Skip relative, absolute, and URL imports
|
||||
if (spec.startsWith('.') || spec.startsWith('/') || spec.startsWith('http:') || spec.startsWith('https:')) {
|
||||
continue;
|
||||
}
|
||||
// Skip svelte internal imports (already rewritten by the compiler)
|
||||
if (spec.startsWith('svelte')) continue;
|
||||
imports.add(spec);
|
||||
}
|
||||
return Array.from(imports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an HTML <script type="importmap"> tag from bare import specifiers.
|
||||
* Maps each bare import to its esm.sh URL.
|
||||
*/
|
||||
export function buildImportMapTag(bareImports) {
|
||||
if (!bareImports.length) return '';
|
||||
const imports = {};
|
||||
for (const spec of bareImports) {
|
||||
// Get the package name (handle scoped packages like @scope/pkg)
|
||||
const parts = spec.split('/');
|
||||
const pkgName = spec.startsWith('@') ? `${parts[0]}/${parts[1]}` : parts[0];
|
||||
// Map the full specifier (e.g. 'lodash/fp' -> 'https://esm.sh/lodash/fp')
|
||||
imports[spec] = `https://esm.sh/${spec}`;
|
||||
// Also map the base package if it's different
|
||||
if (spec !== pkgName) {
|
||||
imports[pkgName] = `https://esm.sh/${pkgName}`;
|
||||
}
|
||||
}
|
||||
const map = JSON.stringify({ imports }, null, 2);
|
||||
return `<script type="importmap">\n${map}\n<\/script>`;
|
||||
}
|
||||
Reference in New Issue
Block a user