0.0.3: Fixed a bug that showed up in watch mode
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Miel Truyen 2023-05-20 21:05:37 +02:00
parent b18ac5c361
commit 52c104f781
10 changed files with 183 additions and 5 deletions

View File

@ -105,6 +105,7 @@ This plugin is in an early state. As such not everything that is supported yet,
### Not (yet/properly) supported
- Sourcemaps (inlined script) (dev-note: we're already including magic-string for this, but do not use it yet, neeeds refactoring)
- Plugins importing CSS files
- CommonJS (cjs) and IIFI output formats. (Is UMD actually ever used?)
- Overriding which DOM-nodes and resulting URLS to ignore/include (in a clean way)

View File

@ -1,6 +1,6 @@
{
"name": "rollup-plugin-html-entry2",
"version": "0.0.2",
"version": "0.0.3",
"description": "Teaches rollup how to deal with HTML, allows to use HTML-files as entry-points.",
"license": "MIT",
"repository": {
@ -56,7 +56,8 @@
},
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"parse5": "^7.1.2"
"parse5": "^7.1.2",
"magic-string": "^0.30.0"
},
"devDependencies": {
"@types/node": "^18.15.11",

11
pnpm-lock.yaml generated
View File

@ -4,6 +4,9 @@ dependencies:
'@rollup/pluginutils':
specifier: ^5.0.1
version: 5.0.2(rollup@3.20.3)
magic-string:
specifier: ^0.30.0
version: 0.30.0
parse5:
specifier: ^7.1.2
version: 7.1.2
@ -475,7 +478,6 @@ packages:
/@jridgewell/sourcemap-codec@1.4.15:
resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
dev: true
/@jridgewell/trace-mapping@0.3.18:
resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
@ -2139,6 +2141,13 @@ packages:
yallist: 4.0.0
dev: true
/magic-string@0.30.0:
resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==}
engines: {node: '>=12'}
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
dev: false
/make-dir@3.1.0:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}

View File

@ -106,7 +106,8 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
}
}
},
load: {
load: { // TODO, not in the mood to fix this. Load-result is getting cached and that gives us issues. Seperate load/transform behavior and adapt to use magic string for transformations?
// Something to figure out: its counter intuitive that rollup expects the load-callback to already return JS. It implies we already do transformations and can't really use rollup to further transform any of it. (i.e handlebars > intermediate-html > html would not be possible?)
async handler(id: string) {
if(virtualSources.has(id)) return virtualSources.get(id);
if(!filter(id)) return;
@ -121,7 +122,7 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
}) : contents;
// Parse document and store it (TODO: check for watch mode, we should check if it needs reparsing or not)
const document = htmlModule.document = htmlModule.document ?? parseHtml(htmlSrc);
const document = htmlModule.document = parseHtml(htmlSrc);
// Figure out which references to load from this HTML by iterating all nodes (looking for src or href attributes)
let htmlImports: HtmlImport[] = htmlModule.imports = [];

View File

@ -49,6 +49,8 @@ export function makeInlineId(sourceId: string, node: DefaultTreeAdapterMap['chil
export function makeLoader(mappings: NodeMapping[] = defaultMapping){
const fn : LoadNodeCallback = async function ({node, sourceId}, load){
for(const mapping of mappings){
// Test the mapping for a match
if (mapping.tagName && mapping.tagName !== node.tagName) continue; // No match, skip
if (mapping.match){
if(typeof(mapping.match) === 'function'){
@ -67,7 +69,10 @@ export function makeLoader(mappings: NodeMapping[] = defaultMapping){
}
}
}
// If we've gotten this far its a valid mapping. (either inline or a src/href attribute)
if((<AttributeReference>mapping).attr){
// Mapped on attribute, resolve its src or href (or whatever was returned)
const attr = node.attrs.find(attr=>attr.name === (<AttributeReference>mapping).attr);
if(!attr) continue ;// No match, skip
const placeholder = await load({
@ -76,6 +81,7 @@ export function makeLoader(mappings: NodeMapping[] = defaultMapping){
});
attr.value = placeholder;
}else if((<BodyReference>mapping).body){
// Mapped as body, use the contents of the DOM element
const body = serializeHtml(node); // unlike what you' might expect, this doesn't serialize the <script>-tag itself, only its contents. Which is what we want.
if(!body) continue; // Empty body, skip
const placeholder = await load({

View File

@ -0,0 +1,7 @@
<html>
<head>
</head>
<body>
<script src="./watched-file.js" type="module"></script>
</body>
</html>

View File

@ -0,0 +1,3 @@
export const a = 1; // DO NOT CHANGE ME HERE, but in ../test.js

View File

@ -0,0 +1,53 @@
# Snapshot report for `test/watch/test.js`
The actual snapshot is saved in `test.js.snap`.
Generated by [AVA](https://avajs.dev).
## watch
> Snapshot 1
[
{
code: `const a = 2; // If i show up as a changed file, then the watch test has gone wrong!␊
export { a };␊
//# sourceMappingURL=watched-file-8c4729c5.js.map␊
`,
fileName: 'watched-file-8c4729c5.js',
map: SourceMap {
file: 'watched-file-8c4729c5.js',
mappings: 'AACgB,MAAC,CAAC,GAAG,EAAE;;;;',
names: [],
sources: [
'../watched-file.js',
],
sourcesContent: [
`␊
export const a = 2; // If i show up as a changed file, then the watch test has gone wrong!␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'watched-file-8c4729c5.js.map',
map: undefined,
source: '{"version":3,"file":"watched-file-8c4729c5.js","sources":["../watched-file.js"],"sourcesContent":["\\n export const a = 2; // If i show up as a changed file, then the watch test has gone wrong!\\n "],"names":[],"mappings":"AACgB,MAAC,CAAC,GAAG,EAAE;;;;"}',
},
{
code: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>
</head>
<body>
<script src="watched-file-8c4729c5.js" type="module"></script>
</body></html>`,
},
]

Binary file not shown.

97
test/watch/test.js Normal file
View File

@ -0,0 +1,97 @@
import {join, dirname} from "node:path";
import test from "ava";
import * as rollup from "rollup";
import {debugPrintOutput, getCode} from "../util/test.js";
import {resolve} from "node:path";
import {writeFile} from "node:fs/promises";
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";
import {pathToFileURL} from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures'));
test.serial('watch', async (t) => {
const origContent = `
export const a = 1; // DO NOT CHANGE ME HERE, but in ../test.js
`;
const changeContent = `
export const a = 2; // If i show up as a changed file, then the watch test has gone wrong!
`
const path = resolve(__dirname, 'fixtures/watched-file.js');
await writeFile(path, origContent, {encoding: 'utf-8'});
const watcher = rollup.watch({
input: 'index.html',
output,
plugins: [
html({
}),
],
watch: {
skipWrite: true,
}
});
const steps = [
async (bundle)=>{
await writeFile(path, changeContent, {encoding: 'utf-8'});
// Just wait on the watch mode to pick up on the changes
},
async (bundle)=>{
const code = await getCode(bundle, output, true);
debugPrintOutput('watch',code);
// Reset the source file
await writeFile(path, origContent, {encoding: 'utf-8'});
// Assert the output is what we exapect;
t.snapshot(code);
watcher
},
];
await new Promise((resolve, reject)=>{
watcher.on('event', async (event) => {
const {result} = event;
switch (event.code) {
case "START":
t.log(`WATCH STARTED`);
break;
case "BUNDLE_START":
t.log(`REBUILDING...`);
break;
case "BUNDLE_END":
t.log(`Rebuilt...`);
const cb = steps.shift();
const generated = await result.generate(output);
const cbResult = await cb(result);
if(steps.length===0){
watcher.close();
resolve();
}
break;
case "ERROR":
reject(event.error);
break;
}
if (result) {
result.close();
}
});
});
});