diff --git a/src/index.ts b/src/index.ts index 19ded21..09d2973 100644 --- a/src/index.ts +++ b/src/index.ts @@ -64,8 +64,9 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin { let htmlModules = new Map();// todo clean this per new build? let virtualSources = new Map(); + const pluginName = 'html2'; return { - name: 'html2',// TODO: Need a better name, original plugin was just named `html` and might still make sense to use in conjunction with this one + name: pluginName,// TODO: Need a better name, original plugin was just named `html` and might still make sense to use in conjunction with this one resolveId: { async handler(specifier: string, @@ -95,6 +96,13 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin { htmlModules.set(htmlModule.id, htmlModule); // TODO: trigger special handling when imported from a JS file (in which case we want might want to export a module returning the HTML, instead of HTML directly) + return { + ...resolved, + meta: { + ...resolved.meta, + [pluginName]: {name: specifier} + } + } } } }, @@ -132,20 +140,18 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin { sourceId = makeInlineId(id, node, 'js'); } if(source){ - virtualSources.set(sourceId, source);// TODO actually loading in the virtual source (if any) + virtualSources.set(sourceId, source); } const resolved = await this.resolve(sourceId, id, { isEntry: type==='entryChunk', }); - // if(!resolved){ - // throw new Error(`Could not resolve ${sourceId} from ${id}`); - // } - // const loaded = await this.load({ - // id: sourceId, - // resolveDependencies: true, - // moduleSideEffects: 'no-treeshake' - // }); + if(!resolved){ + throw new Error(`Could not resolve ${sourceId} from ${id}`); + } + + const selfInfo = this.getModuleInfo(id); + const importName = (source && selfInfo?.meta[pluginName].name) ? makeInlineId(selfInfo?.meta[pluginName].name, node, extname(sourceId)) : undefined; const htmlImport: HtmlImport = { id: sourceId, @@ -158,6 +164,7 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin { (resolved && (['chunk','entryChunk'].includes(type!))) ? this.emitFile({ type: 'chunk', // Might want to adapt, or make configurable (see LoadType) id: resolved.id, + name: importName, importer: id, }) : null, placeholder: `html-import-${crypto.randomBytes(32).toString('base64')}`, @@ -198,6 +205,7 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin { } } + // TODO when importing html from .js this will not do. ( const htmlJSModule = [ ...moduleImports, ``, diff --git a/test/basic/snapshots/test.js.md b/test/basic/snapshots/test.js.md index 0930436..8e8f824 100644 --- a/test/basic/snapshots/test.js.md +++ b/test/basic/snapshots/test.js.md @@ -60,9 +60,9 @@ Generated by [AVA](https://avajs.dev). [ { code: undefined, - fileName: 'script.html.body.script-e3b82208.js.map', + fileName: 'script.html.body.script.js-e3b82208.js.map', map: undefined, - source: '{"version":3,"file":"script.html.body.script-e3b82208.js","sources":["../batman.js","../script.html.body.script.js"],"sourcesContent":["export const b = ()=>\'batman\';\\nconsole.log(b());\\n","\\n import {b} from \\"./batman.js\\";\\n document.body.appendChild(\\n document.createTextNode(`Inline script including ${b()}`)\\n );\\n "],"names":[],"mappings":"AAAO,MAAM,CAAC,GAAG,IAAI,QAAQ,CAAC;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;ACCJ,QAAQ,CAAC,IAAI,CAAC,WAAW;AACrC,gBAAgB,QAAQ,CAAC,cAAc,CAAC,CAAC,wBAAwB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACzE,aAAa"}', + source: '{"version":3,"file":"script.html.body.script.js-e3b82208.js","sources":["../batman.js","../script.html.body.script.js"],"sourcesContent":["export const b = ()=>\'batman\';\\nconsole.log(b());\\n","\\n import {b} from \\"./batman.js\\";\\n document.body.appendChild(\\n document.createTextNode(`Inline script including ${b()}`)\\n );\\n "],"names":[],"mappings":"AAAO,MAAM,CAAC,GAAG,IAAI,QAAQ,CAAC;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;ACCJ,QAAQ,CAAC,IAAI,CAAC,WAAW;AACrC,gBAAgB,QAAQ,CAAC,cAAc,CAAC,CAAC,wBAAwB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACzE,aAAa"}', }, { code: undefined, @@ -77,7 +77,7 @@ Generated by [AVA](https://avajs.dev). document.body.appendChild(␊ document.createTextNode(\`Inline script including ${b()}\`)␊ );␊ - //# sourceMappingURL=script.html.body.script-e3b82208.js.map␊ + //# sourceMappingURL=script.html.body.script.js-e3b82208.js.map␊ ␊ ␊ ␊ diff --git a/test/basic/snapshots/test.js.snap b/test/basic/snapshots/test.js.snap index b111688..e34aabd 100644 Binary files a/test/basic/snapshots/test.js.snap and b/test/basic/snapshots/test.js.snap differ diff --git a/test/multi-entry/fixtures/admin/index.html b/test/multi-entry/fixtures/admin/index.html new file mode 100644 index 0000000..79d7fea --- /dev/null +++ b/test/multi-entry/fixtures/admin/index.html @@ -0,0 +1,12 @@ + + + + +
+ + + diff --git a/test/multi-entry/fixtures/app/admin-deps.js b/test/multi-entry/fixtures/app/admin-deps.js new file mode 100644 index 0000000..4ff1c0d --- /dev/null +++ b/test/multi-entry/fixtures/app/admin-deps.js @@ -0,0 +1,3 @@ +export function adminDeps(){ + return "robin!"; +} diff --git a/test/multi-entry/fixtures/app/app.js b/test/multi-entry/fixtures/app/app.js new file mode 100644 index 0000000..ec24508 --- /dev/null +++ b/test/multi-entry/fixtures/app/app.js @@ -0,0 +1,6 @@ +export const bootstrap = (el,deps = [])=>{ + el.innerHtml = ` +
I'm "annoying" ${"in case we need to test \`string\` escaping."}. Hence this file \'tries\' to include all allowed forms of 'it'
+
Deps: ${deps}
+ `; +} diff --git a/test/multi-entry/fixtures/index.html b/test/multi-entry/fixtures/index.html new file mode 100644 index 0000000..73a0651 --- /dev/null +++ b/test/multi-entry/fixtures/index.html @@ -0,0 +1,11 @@ + + + + +
+ + + diff --git a/test/multi-entry/snapshots/test.js.md b/test/multi-entry/snapshots/test.js.md new file mode 100644 index 0000000..7048e2e --- /dev/null +++ b/test/multi-entry/snapshots/test.js.md @@ -0,0 +1,100 @@ +# Snapshot report for `test/multi-entry/test.js` + +The actual snapshot is saved in `test.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## multi-entry + +> Snapshot 1 + + [ + { + code: `const bootstrap = (el,deps = [])=>{␊ + el.innerHtml = \`␊ +
I'm "annoying" ${"in case we need to test \\\`string\\\` escaping."}. Hence this file \\'tries\\' to include all allowed forms of 'it'
␊ +
Deps: ${deps}
␊ + \`;␊ + };␊ + ␊ + export { bootstrap as b };␊ + //# sourceMappingURL=app-01141b67.js.map␊ + `, + fileName: 'app-01141b67.js', + map: SourceMap { + file: 'app-01141b67.js', + mappings: 'AAAY,MAAC,SAAS,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,GAAG;AACzC,IAAI,EAAE,CAAC,SAAS,GAAG,CAAC;AACpB,4BAA4B,EAAE,8CAA8C,CAAC;AAC7E,mBAAmB,EAAE,IAAI,CAAC;AAC1B,IAAI,CAAC,CAAC;AACN;;;;', + names: [], + sources: [ + '../app/app.js', + ], + sourcesContent: [ + `export const bootstrap = (el,deps = [])=>{␊ + el.innerHtml = \`␊ +
I'm "annoying" ${"in case we need to test \\\`string\\\` escaping."}. Hence this file \\'tries\\' to include all allowed forms of 'it'
␊ +
Deps: ${deps}
␊ + \`;␊ + }␊ + `, + ], + version: 3, + }, + source: undefined, + }, + { + code: undefined, + fileName: 'index.html.body.script.js-45303f0f.js.map', + map: undefined, + source: '{"version":3,"file":"index.html.body.script.js-45303f0f.js","sources":["../index.html.body.script.js"],"sourcesContent":["\\n import {bootstrap} from \\"./app/app.js\\"\\n bootstrap(document.getElementById(\'root\'), \\"\\");\\n "],"names":[],"mappings":";;AAEY,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC"}', + }, + { + code: undefined, + fileName: 'admin/index.html.body.script.js-15dfaff3.js.map', + map: undefined, + source: '{"version":3,"file":"index.html.body.script.js-15dfaff3.js","sources":["../../app/admin-deps.js","../../admin/index.html.body.script.js"],"sourcesContent":["export function adminDeps(){\\n return \\"robin!\\";\\n}\\n","\\n import {bootstrap} from \\"../app/app.js\\"\\n import {adminDeps} from \\"../app/admin-deps.js\\";\\n bootstrap(document.getElementById(\'root\'), adminDeps());\\n "],"names":[],"mappings":";;AAAO,SAAS,SAAS,EAAE;AAC3B,IAAI,OAAO,QAAQ,CAAC;AACpB;;ACCY,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC"}', + }, + { + code: undefined, + fileName: 'app-01141b67.js.map', + map: undefined, + source: '{"version":3,"file":"app-01141b67.js","sources":["../app/app.js"],"sourcesContent":["export const bootstrap = (el,deps = [])=>{\\n el.innerHtml = `\\n
I\'m \\"annoying\\" ${\\"in case we need to test \\\\`string\\\\` escaping.\\"}. Hence this file \\\\\'tries\\\\\' to include all allowed forms of \'it\'
\\n
Deps: ${deps}
\\n `;\\n}\\n"],"names":[],"mappings":"AAAY,MAAC,SAAS,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,GAAG;AACzC,IAAI,EAAE,CAAC,SAAS,GAAG,CAAC;AACpB,4BAA4B,EAAE,8CAA8C,CAAC;AAC7E,mBAAmB,EAAE,IAAI,CAAC;AAC1B,IAAI,CAAC,CAAC;AACN;;;;"}', + }, + { + code: undefined, + fileName: 'index.html', + map: undefined, + source: `␊ + ␊ + ␊ +
␊ + ␊ + ␊ + ␊ + `, + }, + { + code: undefined, + fileName: 'admin/index.html', + map: undefined, + source: `␊ + ␊ + ␊ +
␊ + ␊ + ␊ + ␊ + `, + }, + ] diff --git a/test/multi-entry/snapshots/test.js.snap b/test/multi-entry/snapshots/test.js.snap new file mode 100644 index 0000000..b9a63ee Binary files /dev/null and b/test/multi-entry/snapshots/test.js.snap differ diff --git a/test/multi-entry/test.js b/test/multi-entry/test.js new file mode 100644 index 0000000..f450631 --- /dev/null +++ b/test/multi-entry/test.js @@ -0,0 +1,40 @@ +import {join, dirname} from "node:path"; + +import test from "ava"; +import { rollup } from "rollup"; +import {debugPrintOutput, getCode} from "../util/test.js"; + +import html from "../../src/index.ts"; + +const output = { + dir: 'output', // Output all files + format: 'es', // iifi and cjs should be added to tests + sourcemap: true,// Test if #sourcemapUrl is not accidentally included in the html-output +}; + +import {fileURLToPath} from "node:url"; +const __dirname = dirname(fileURLToPath(import.meta.url)); +process.chdir(join(__dirname, 'fixtures')); + + +test.serial('multi-entry', async (t) => { + const bundle = await rollup({ + input: { + ['index']: 'index.html', + ['admin/index']: 'admin/index.html' + }, + plugins: [ + html({ + }), + ] + }); + const code = await getCode(bundle, output, true); + debugPrintOutput('multi-entry',code); + t.snapshot(code); +}); + +// TODO various parameters +// - format: cjs, iifi, ... +// - sourcemap: inline, false, (and the various exotic sourcemap options) +// Watch mode tests would be its own dir +// ...