WIP: Basic working version. Will import .html files and resolve its dependencies. But it will generate invalid html when sourcemaps are enabled, assets like <link..> do not yet work...
This commit is contained in:
78
src/index.ts
78
src/index.ts
@@ -7,7 +7,9 @@ import type {
|
||||
OutputAsset,
|
||||
NormalizedOutputOptions,
|
||||
// ModuleInfo,
|
||||
ResolvedId, PreRenderedChunk
|
||||
ResolvedId,
|
||||
PreRenderedChunk,
|
||||
RenderedChunk,
|
||||
} from 'rollup';
|
||||
|
||||
import type {
|
||||
@@ -18,6 +20,7 @@ import type {
|
||||
} from '../types/index.d.ts';
|
||||
import {createFilter} from '@rollup/pluginutils';
|
||||
import {parse as parseHtml, serialize as serializeHtml, DefaultTreeAdapterMap} from "parse5";
|
||||
// import {Script, SourceTextModule, createContext} from "node:vm";
|
||||
|
||||
const getFiles = (bundle: OutputBundle): Record<string, (OutputChunk | OutputAsset)[]> => {
|
||||
const result = {} as ReturnType<typeof getFiles>;
|
||||
@@ -88,6 +91,7 @@ type HtmlModule = {
|
||||
// TODO might want to impose an own unique id, in case this changes after multiple builds
|
||||
id: string,
|
||||
resolved: HtmlImport[];
|
||||
document: DefaultTreeAdapterMap['document'],
|
||||
}
|
||||
|
||||
export default function html(opts: RollupHtmlOptions = {}): Plugin {
|
||||
@@ -139,18 +143,19 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
|
||||
async handler(code: string, id: string){
|
||||
if(!filter(id)) return;
|
||||
|
||||
const handled : HtmlModule = {
|
||||
id,
|
||||
resolved: [],
|
||||
};
|
||||
handledHtmls.set(id, handled);
|
||||
|
||||
const htmlSrc = transform? await transform(code, {
|
||||
const htmlSrc = transform? await transform(code, {
|
||||
id,
|
||||
}) : code;
|
||||
|
||||
const document = parseHtml(htmlSrc);
|
||||
|
||||
const handled : HtmlModule = {
|
||||
id,
|
||||
resolved: [],
|
||||
document,
|
||||
};
|
||||
handledHtmls.set(id, handled);
|
||||
|
||||
// Figure out which references to load from this HTML by iterating all nodes (looking for src or href attributes)
|
||||
let loadResults : { reference: LoadReference, node: DefaultTreeAdapterMap['element'] }[] = [];
|
||||
if(document.childNodes){
|
||||
@@ -199,7 +204,7 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
|
||||
if(resolvedId){
|
||||
const rollupResolved = await this.resolve(resolvedId, id, {
|
||||
skipSelf: true,
|
||||
isEntry: true, // TODO: for href/src tags, this is probably the right option. For anything that is to be inlined into the HTML... probably no
|
||||
isEntry: true, // TODO: for href/src tags, this is probably the right option. For anything that is to be inlined into the HTML... probably not
|
||||
});
|
||||
// TODO: should we check if this is refused for resolving here. i.e. external?
|
||||
const htmlImport: HtmlImport = {
|
||||
@@ -216,6 +221,7 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
|
||||
index,
|
||||
};
|
||||
if(htmlImport.referenceId) {
|
||||
// only used when importing from javascript
|
||||
reference.set(`\${import.meta.ROLLUP_FILE_URL_${htmlImport.referenceId}\}`);
|
||||
}
|
||||
handled.resolved.push(htmlImport);
|
||||
@@ -227,8 +233,7 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
|
||||
// Transform to JS
|
||||
const serialized = serializeHtml(document);
|
||||
const jsModule = [
|
||||
//...resolveResults.map(x=>`import * as dep${x.index} from "${x.id}";`),
|
||||
// ...handled.resolved.map(x=>`import("${x.id}");`),// Inject as a dynamic import. We need to remove these before outputting // todo better solution to mark the ids as dependencies of this bundle...
|
||||
// This will only make sense when importing from javascript
|
||||
`export const html = \`${serialized.replaceAll(/`/g,'\\\`')}\`;`,
|
||||
`export default html;`
|
||||
].join('\n');
|
||||
@@ -236,39 +241,24 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
|
||||
return {code: jsModule};
|
||||
}
|
||||
},
|
||||
async generateBundle(output: NormalizedOutputOptions, bundle: OutputBundle) {
|
||||
const files = getFiles(bundle);
|
||||
console.log("must output?!", output, bundle, files);
|
||||
async renderChunk(
|
||||
code: string,
|
||||
chunk: RenderedChunk,
|
||||
options: NormalizedOutputOptions,
|
||||
meta: { chunks: Record<string, RenderedChunk> }
|
||||
){
|
||||
const htmlModule = chunk.facadeModuleId ? handledHtmls.get(chunk.facadeModuleId!) : null;
|
||||
if(htmlModule){
|
||||
let html = '';
|
||||
for(const htmlImport of htmlModule.resolved){
|
||||
if(htmlImport.referenceId) {
|
||||
const fileName = this.getFileName(htmlImport.referenceId);
|
||||
htmlImport.reference.set(fileName);
|
||||
}
|
||||
}
|
||||
html = serializeHtml(htmlModule.document);// This might contain temporary hashes, but it should be alright
|
||||
return {code: html};
|
||||
}
|
||||
},
|
||||
|
||||
// async generateBundle(output: NormalizedOutputOptions, bundle: OutputBundle) {
|
||||
// if (!supportedFormats.includes(output.format) && !opts.transform) {
|
||||
// this.warn(
|
||||
// `plugin-html: The output format '${
|
||||
// output.format
|
||||
// }' is not directly supported. A custom \`template\` is probably required. Supported formats include: ${supportedFormats.join(
|
||||
// ', '
|
||||
// )}`
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// if (output.format === 'es') {
|
||||
// attributes.script = Object.assign({}, attributes.script, {
|
||||
// type: 'module'
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// const files = getFiles(bundle);
|
||||
//
|
||||
//
|
||||
// const htmlFile: EmittedAsset = {
|
||||
// type: 'asset',
|
||||
// source,
|
||||
// name: 'Rollup HTML Asset',
|
||||
// fileName
|
||||
// };
|
||||
//
|
||||
// this.emitFile(htmlFile);
|
||||
// }
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user