4 Commits

53 changed files with 2266 additions and 1641 deletions

View File

@@ -0,0 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="true" type="JavaScriptTestRunnerJest">
<node-interpreter value="/usr/bin/node" />
<node-options value="--experimental-vm-modules" />
<jest-options value="--detectOpenHandles" />
<envs />
<scope-kind value="ALL" />
<method v="2" />
</configuration>
</component>

View File

@@ -2,7 +2,6 @@
const babelConfig ={ const babelConfig ={
presets: [ presets: [
["@babel/preset-typescript", { ["@babel/preset-typescript", {
}], }],
], ],
plugins: [ plugins: [

View File

@@ -1,6 +1,6 @@
{ {
"name": "rollup-plugin-html-entry2", "name": "rollup-plugin-html-entry2",
"version": "0.0.6", "version": "0.0.7",
"description": "Teaches rollup how to deal with HTML, allows to use HTML-files as entry-points.", "description": "Teaches rollup how to deal with HTML, allows to use HTML-files as entry-points.",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@@ -30,8 +30,8 @@
"ci:coverage": "nyc pnpm test && nyc report --reporter=text-lcov > coverage.lcov", "ci:coverage": "nyc pnpm test && nyc report --reporter=text-lcov > coverage.lcov",
"ci:lint": "pnpm build && pnpm lint-staged", "ci:lint": "pnpm build && pnpm lint-staged",
"ci:test": "pnpm test -- --verbose", "ci:test": "pnpm test -- --verbose",
"test": "NODE_OPTIONS='--import tsx' ava", "test": "NODE_OPTIONS='--experimental-vm-modules' jest",
"save-test": "NODE_OPTIONS='--import tsx' ava --update-snapshots" "save-test": "NODE_OPTIONS='--experimental-vm-modules' jest -u"
}, },
"files": [ "files": [
"dist", "dist",
@@ -47,7 +47,7 @@
"template" "template"
], ],
"peerDependencies": { "peerDependencies": {
"rollup": "^3.0.0" "rollup": "^4.0.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"rollup": { "rollup": {
@@ -75,41 +75,29 @@
"@types/node": "^18.18.12", "@types/node": "^18.18.12",
"@types/react": "^18.2.0", "@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0", "@types/react-dom": "^18.2.0",
"ava": "^5.3.1",
"chalk": "^5.3.0", "chalk": "^5.3.0",
"del-cli": "^5.1.0", "del-cli": "^5.1.0",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"lint-staged": "^13.3.0", "lint-staged": "^13.3.0",
"nyc": "^15.1.0", "nyc": "^15.1.0",
"postcss": "^8.4.31", "postcss": "^8.4.31",
"rollup": "^3.29.4", "rollup": "^4.12.0",
"rollup-plugin-delete": "^2.0.0", "rollup-plugin-delete": "^2.0.0",
"rollup-plugin-livereload": "^2.0.5", "rollup-plugin-livereload": "^2.0.5",
"rollup-plugin-postcss": "^4.0.2", "rollup-plugin-postcss": "^4.0.2",
"tslib": "^2.6.2",
"tsx": "^4.4.0",
"typescript": "^5.3.2", "typescript": "^5.3.2",
"puppeteer": "^21.5.2", "puppeteer": "^21.5.2",
"mime": "^4.0.0", "mime": "^4.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0" "react-dom": "^18.2.0",
"jest": "^29.7.0",
"@types/jest": "^29.5.12",
"ts-jest": "^29.1.2",
"@jest/globals": "^29.7.0"
}, },
"types": "./types/index.d.ts", "types": "./types/index.d.ts",
"ava": { "jest": {
"workerThreads": false, "preset":"ts-jest/presets/default-esm",
"files": [ "setupFiles": ["./test/setup.js"]
"!**/fixtures/**",
"!**/util/**",
"!**/helpers/**",
"!**/recipes/**",
"!**/types.ts"
],
"extensions": {
"ts": "module",
"js": true
},
"nodeArguments": [
"--experimental-vm-modules"
]
} }
} }

1899
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ import type {
import type { import type {
LoadedReference LoadedReference
} from "../types/load.d.ts"; } from "../types/load.d.ts";
import {DefaultTreeAdapterMap} from "parse5"; import type {DefaultTreeAdapterMap} from "parse5";
// Internal type // Internal type
export type HtmlImport = LoadedReference & { export type HtmlImport = LoadedReference & {

View File

@@ -34,8 +34,8 @@ import posix from "node:path/posix";
import crypto from "node:crypto"; import crypto from "node:crypto";
// utilities // utilities
import {makeLoader, makeInlineId} from "./loader.js"; import {makeLoader, makeInlineId} from "./loader.ts";
import {HtmlImport, HtmlModule} from "./html-module.js"; import {HtmlImport, HtmlModule} from "./html-module.ts";
const defaults: RollupHtmlOptions = { const defaults: RollupHtmlOptions = {
@@ -99,7 +99,8 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
* *
* *
* Rework by testing a stripped down version with JS imports? * Rework by testing a stripped down version with JS imports?
* - the logic in load should be moved to a transform, properly use rollups ability to specify the plugin should run 'pre' other hooks and see if that allows us to intercept before a commonjs or some other tool horribly transpiles our code * - the logic in load should be moved to a transform, properly use rollups ability to specify the plugin should
* run 'pre' other hooks and see if that allows us to intercept before a commonjs or some other tool horribly transpiles our code
* - we might need to know which output is being used to properly extract the html back from the result? (in case of not being included in a JS file) * - we might need to know which output is being used to properly extract the html back from the result? (in case of not being included in a JS file)
*/ */
return { return {
@@ -113,9 +114,9 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
}, },
resolveId: { resolveId: {
async handler(specifier: string, async handler(specifier,
importer: string | undefined, importer,
options: { assertions: Record<string, string> }){ options){
if(virtualSources.has(specifier)) return specifier; if(virtualSources.has(specifier)) return specifier;
if(!filter(specifier)) return; if(!filter(specifier)) return;
@@ -206,6 +207,7 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
virtualSources.set(sourceId, source); virtualSources.set(sourceId, source);
} }
const resolved = await this.resolve(sourceId, id, { const resolved = await this.resolve(sourceId, id, {
skipSelf: false, // defaults to true since rollup 4, and for virtual files this is problematic
isEntry: type==='entryChunk', isEntry: type==='entryChunk',
}); });
if(!resolved){ if(!resolved){
@@ -265,6 +267,8 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin {
} while (nodeQueue.length > 0); } while (nodeQueue.length > 0);
} }
// Beware leak of AST (we're starting MagicString on a parsed and modified version of the HTML file, sourcemappings in the HTML file will be off. (can't add a sourcemap for a html file anyway, unless it is outputted as JS module)
// @ts-ignore
let htmlJS = new MagicString(serializeHtml(htmlModule.document)); let htmlJS = new MagicString(serializeHtml(htmlModule.document));
htmlJS.replaceAll(/`/g,'\\\`').replaceAll(/\$\{/g,'\\${'); htmlJS.replaceAll(/`/g,'\\\`').replaceAll(/\$\{/g,'\\${');

View File

@@ -9,7 +9,7 @@ import type {
} from '../types/index.d.ts'; } from '../types/index.d.ts';
import {parseFragment as parseHtmlFragment, serialize as serializeHtml, DefaultTreeAdapterMap} from "parse5"; import {parseFragment as parseHtmlFragment, serialize as serializeHtml, DefaultTreeAdapterMap} from "parse5";
import {KnownMappings, defaultMapping} from "./loader-mappings.js"; import {KnownMappings, defaultMapping} from "./loader-mappings.ts";
/** /**
* Makes a unique but human-readable name from a path within a HTML file. * Makes a unique but human-readable name from a path within a HTML file.

View File

@@ -0,0 +1,78 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`basic inline-script 1`] = `
[
{
"code": undefined,
"fileName": "script.body.script.js.js.map",
"map": undefined,
"source": "{"version":3,"file":"script.body.script.js.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,
"fileName": "script.html",
"map": undefined,
"source": "<html><head>
</head>
<body>
<script type="module">const b = ()=>'batman';
console.log(b());
document.body.appendChild(
document.createTextNode(\`Inline script including \${b()}\`)
);
//# sourceMappingURL=script.body.script.js.js.map
</script>
</body></html>",
},
]
`;
exports[`basic simple 1`] = `
[
{
"code": "const b = ()=>'batman';
console.log(b());
export { b };
//# sourceMappingURL=batman.js.map
",
"fileName": "batman.js",
"map": SourceMap {
"file": "batman.js",
"mappings": "AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;",
"names": [],
"sources": [
"../batman.js",
],
"sourcesContent": [
"export const b = ()=>'batman';
console.log(b());
",
],
"version": 3,
},
"source": undefined,
},
{
"code": undefined,
"fileName": "batman.js.map",
"map": undefined,
"source": "{"version":3,"file":"batman.js","sources":["../batman.js"],"sourcesContent":["export const b = ()=>'batman';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}",
},
{
"code": undefined,
"fileName": "index.html",
"map": undefined,
"source": "<html><head>
</head>
<body>
<script src="batman.js" type="module"></script>
</body></html>",
},
]
`;

View File

@@ -1,86 +0,0 @@
# Snapshot report for `test/basic/test.js`
The actual snapshot is saved in `test.js.snap`.
Generated by [AVA](https://avajs.dev).
## simple
> Snapshot 1
[
{
code: `const b = ()=>'batman';␊
console.log(b());␊
export { b };␊
//# sourceMappingURL=batman-c7fa228c.js.map␊
`,
fileName: 'batman-c7fa228c.js',
map: SourceMap {
file: 'batman-c7fa228c.js',
mappings: 'AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;',
names: [],
sources: [
'../batman.js',
],
sourcesContent: [
`export const b = ()=>'batman';␊
console.log(b());␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'batman-c7fa228c.js.map',
map: undefined,
source: '{"version":3,"file":"batman-c7fa228c.js","sources":["../batman.js"],"sourcesContent":["export const b = ()=>\'batman\';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}',
},
{
code: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>␊
</head>␊
<body>␊
<script src="batman-c7fa228c.js" type="module"></script>␊
</body></html>`,
},
]
## inline-script
> Snapshot 1
[
{
code: undefined,
fileName: 'script.body.script.js-e3b82208.js.map',
map: undefined,
source: '{"version":3,"file":"script.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,
fileName: 'script.html',
map: undefined,
source: `<html><head>␊
</head>␊
<body>␊
<script type="module">const b = ()=>'batman';␊
console.log(b());␊
document.body.appendChild(␊
document.createTextNode(\`Inline script including ${b()}\`)␊
);␊
//# sourceMappingURL=script.body.script.js-e3b82208.js.map␊
</script>␊
</body></html>`,
},
]

Binary file not shown.

View File

@@ -1,50 +1,47 @@
import {join, dirname} from "node:path"; import {join, dirname} from "node:path";
import test from "ava"; import {test, expect} from "@jest/globals";
import { rollup } from "rollup"; import { rollup } from "rollup";
import {debugPrintOutput, getCode} from "../util/index.ts"; import {debugPrintOutput, getCode} from "../util/index.ts";
import html from "../../src/index.ts"; 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 {fileURLToPath} from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures')); process.chdir(join(__dirname, 'fixtures'));
describe("basic", ()=> {
test.serial('simple', async (t) => { test('simple', async () => {
const bundle = await rollup({ const bundle = await rollup({
input: 'index.html', input: 'index.html',
plugins: [ plugins: [
html({ html({}),
}), ]
] });
const code = await getCode(bundle);
await bundle.close();
debugPrintOutput('simple', code);
expect(code).toMatchSnapshot();
}); });
const code = await getCode(bundle, output);
debugPrintOutput('simple',code);
t.snapshot(code);
});
test.serial('inline-script', async (t) => { test('inline-script', async () => {
const bundle = await rollup({ const bundle = await rollup({
input: 'script.html', input: 'script.html',
plugins: [ plugins: [
html({ html({}),
}), ]
] });
const code = await getCode(bundle);
await bundle.close();
debugPrintOutput('inline-script', code);
expect(code).toMatchSnapshot();
}); });
const code = await getCode(bundle, output);
debugPrintOutput('inline-script',code);
t.snapshot(code);
});
// TODO various parameters // TODO various parameters
// - format: cjs, iifi, ... // - format: cjs, iifi, ...
// - sourcemap: inline, false, (and the various exotic sourcemap options) // - sourcemap: inline, false, (and the various exotic sourcemap options)
// Watch mode tests would be its own dir // Watch mode tests would be its own dir
// ... // ...
});

View File

@@ -0,0 +1,36 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`evaluated-web-bundle 1`] = `
{
"console": [
"[log] Bootstrapped, ready to go!",
"[log] Test my sourcemap: App started",
"[log] Test my sourcemap: App tick",
"[log] Test my sourcemap: App ended",
],
"errors": [],
"html": "<html lang="en"><head>
<meta charset="UTF-8">
<title>
Test bundle!
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%20%20%20%20%3Ctitle%3EHTML5%20Logo%3C%2Ftitle%3E%20%20%20%20%3Cpath%20d%3D%22M108.4%200h23v22.8h21.2V0h23v69h-23V46h-21v23h-23.2M206%2023h-20.3V0h63.7v23H229v46h-23M259.5%200h24.1l14.8%2024.3L313.2%200h24.1v69h-23V34.8l-16.1%2024.8l-16.1-24.8v34.2h-22.6M348.7%200h23v46.2h32.6V69h-55.6%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23e44d26%22%20d%3D%22M107.6%20471l-33-370.4h362.8l-33%20370.2L255.7%20512%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23f16529%22%20d%3D%22M256%20480.5V131H404.3L376%20447%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23ebebeb%22%20d%3D%22M142%20176.3h114v45.4h-64.2l4.2%2046.5h60v45.3H154.4M156.4%20336.3H202l3.2%2036.3%2050.8%2013.6v47.4l-93.2-26%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M369.6%20176.3H255.8v45.4h109.6M361.3%20268.2H255.8v45.4h56l-5.3%2059-50.7%2013.6v47.2l93-25.8%22%2F%3E%3C%2Fsvg%3E">
<title>I'm cool!</title>
</head>
<body>
<div id="root"><div style="align-self: center"><b>App ended</b></div></div>
<script src="index.js" type="module"></script>
</body></html>",
"requestsFailed": [],
"responses": [
"200 http://localhost/index.html",
"200 http://localhost/index.js",
"200 http://localhost/app.js",
],
}
`;

View File

@@ -1,42 +0,0 @@
# Snapshot report for `test/evaluated-web-bundle/test.js`
The actual snapshot is saved in `test.js.snap`.
Generated by [AVA](https://avajs.dev).
## web-bundle
> Snapshot 1
{
console: [
'[log] Bootstrapped, ready to go!',
'[log] Test my sourcemap: App started',
'[log] Test my sourcemap: App tick',
'[log] Test my sourcemap: App ended',
],
errors: [],
html: `<html lang="en"><head>␊
<meta charset="UTF-8">␊
<title>␊
Test bundle!␊
</title>␊
<meta name="viewport" content="width=device-width, initial-scale=1">␊
<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%20%20%20%20%3Ctitle%3EHTML5%20Logo%3C%2Ftitle%3E%20%20%20%20%3Cpath%20d%3D%22M108.4%200h23v22.8h21.2V0h23v69h-23V46h-21v23h-23.2M206%2023h-20.3V0h63.7v23H229v46h-23M259.5%200h24.1l14.8%2024.3L313.2%200h24.1v69h-23V34.8l-16.1%2024.8l-16.1-24.8v34.2h-22.6M348.7%200h23v46.2h32.6V69h-55.6%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23e44d26%22%20d%3D%22M107.6%20471l-33-370.4h362.8l-33%20370.2L255.7%20512%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23f16529%22%20d%3D%22M256%20480.5V131H404.3L376%20447%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23ebebeb%22%20d%3D%22M142%20176.3h114v45.4h-64.2l4.2%2046.5h60v45.3H154.4M156.4%20336.3H202l3.2%2036.3%2050.8%2013.6v47.4l-93.2-26%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M369.6%20176.3H255.8v45.4h109.6M361.3%20268.2H255.8v45.4h56l-5.3%2059-50.7%2013.6v47.2l93-25.8%22%2F%3E%3C%2Fsvg%3E">␊
<title>I'm cool!</title>␊
</head>␊
<body>␊
<div id="root"><div style="align-self: center"><b>App ended</b></div></div>␊
<script src="index.js" type="module"></script>␊
</body></html>`,
requestsFailed: [],
responses: [
'200 http://localhost/index.html',
'200 http://localhost/index.js',
'200 http://localhost/app.js',
],
}

View File

@@ -1,26 +1,14 @@
import {join, dirname} from "node:path"; import {join, dirname} from "node:path";
import {test, expect} from "@jest/globals";
import test from "ava";
import { rollup } from "rollup";
import urlPlugin from "@rollup/plugin-url"; import urlPlugin from "@rollup/plugin-url";
import html from "../../src/index.ts"; import html from "../../src/index.ts";
import serveTest from "../util/test-server.ts"; import {runBrowserTest} from "../util/browser-test.ts";
/**
* @type {OutputOptions}
*/
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
chunkFileNames: '[name].js',
entryFileNames: '[name].[extname]',
assetFileNames: '[name].[extname]',
};
import {fileURLToPath} from "node:url"; import {fileURLToPath} from "node:url";
import handlebars from "handlebars"; import handlebars from "handlebars";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures')); process.chdir(join(__dirname, 'fixtures'));
@@ -31,8 +19,8 @@ const defaultAssetInclude = [
'**/*.(webm|mp4)',// video '**/*.(webm|mp4)',// video
]; ];
test.serial('web-bundle', async (t) => { test('evaluated-web-bundle', async ()=>{
const bundle = await rollup({ const out = await runBrowserTest({
input: 'index.hbs', input: 'index.hbs',
treeshake: 'smallest', treeshake: 'smallest',
plugins: [ plugins: [
@@ -46,13 +34,16 @@ test.serial('web-bundle', async (t) => {
urlPlugin({ urlPlugin({
include: defaultAssetInclude, include: defaultAssetInclude,
}), }),
serveTest({
path: 'index.html',
t,
})
], ],
}, {
path: 'index.html',
},{
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
chunkFileNames: '[name].js',
entryFileNames: '[name].[extname]',
assetFileNames: '[name].[extname]',
}); });
await bundle.generate(output); expect(out).toMatchSnapshot();
}); });

View File

@@ -0,0 +1,69 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`js-import 1`] = `
[
{
"code": "var asset0 = "data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2032%2032%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3A%2300ff0d%3Bstroke-width%3A5%3Bstroke-linecap%3Asquare%3Bstroke-linejoin%3Amiter%3Bstroke-dasharray%3Anone%3Bstroke-opacity%3A1%22%20d%3D%22M4.1%2014.72%2016%2026.31%2028.38%205.09%22%2F%3E%3C%2Fsvg%3E";
const html = \`<html><head>
<link rel="icon" href="\${asset0}">
<!-- TODO: support for css imports are yet to be added (as simple assets or through a preprocessor-->
<!-- <link rel="stylesheet" href="./joker.css">-->
</head>
<body>
<!-- TODO: this shouldn't have been commented out, but our plugin fails if it is included (which shoudn't happen!!) -->
<!--<script src="./batman.js" type="module"></script>-->
</body></html>\`;
function render(){
return html;
}
export { render };
//# sourceMappingURL=index.js.map
",
"fileName": "index.js",
"map": SourceMap {
"file": "index.js",
"mappings": "AAAA,aAAe;;ACAf,MAAA,IAAA,GAAA,CAAA;AACA,+BAA+B,EAAwD,MAAA,CAAA;AACvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAa,CAAA;;ACRN,SAAS,MAAM,EAAE;AACxB,IAAI,OAAO,IAAI,CAAC;AAChB;;;;",
"names": [],
"sources": [
"../icon.svg",
"../index.html",
"../index.js",
],
"sourcesContent": [
"export default "data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2032%2032%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3A%2300ff0d%3Bstroke-width%3A5%3Bstroke-linecap%3Asquare%3Bstroke-linejoin%3Amiter%3Bstroke-dasharray%3Anone%3Bstroke-opacity%3A1%22%20d%3D%22M4.1%2014.72%2016%2026.31%2028.38%205.09%22%2F%3E%3C%2Fsvg%3E"",
"<html>
<head>
<link rel="icon" href="./icon.svg">
<!-- TODO: support for css imports are yet to be added (as simple assets or through a preprocessor-->
<!-- <link rel="stylesheet" href="./joker.css">-->
</head>
<body>
<!-- TODO: this shouldn't have been commented out, but our plugin fails if it is included (which shoudn't happen!!) -->
<!--<script src="./batman.js" type="module"></script>-->
</body>
</html>
",
"import html from "./index.html"
export function render(){
return html;
}
",
],
"version": 3,
},
"source": undefined,
},
{
"code": undefined,
"fileName": "index.js.map",
"map": undefined,
"source": "{"version":3,"file":"index.js","sources":["../icon.svg","../index.html","../index.js"],"sourcesContent":["export default \\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2032%2032%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3A%2300ff0d%3Bstroke-width%3A5%3Bstroke-linecap%3Asquare%3Bstroke-linejoin%3Amiter%3Bstroke-dasharray%3Anone%3Bstroke-opacity%3A1%22%20d%3D%22M4.1%2014.72%2016%2026.31%2028.38%205.09%22%2F%3E%3C%2Fsvg%3E\\"","<html>\\n <head>\\n <link rel=\\"icon\\" href=\\"./icon.svg\\">\\n <!-- TODO: support for css imports are yet to be added (as simple assets or through a preprocessor-->\\n<!-- <link rel=\\"stylesheet\\" href=\\"./joker.css\\">-->\\n </head>\\n <body>\\n <!-- TODO: this shouldn't have been commented out, but our plugin fails if it is included (which shoudn't happen!!) -->\\n <!--<script src=\\"./batman.js\\" type=\\"module\\"></script>-->\\n </body>\\n</html>\\n","import html from \\"./index.html\\"\\n\\nexport function render(){\\n return html;\\n}\\n"],"names":[],"mappings":"AAAA,aAAe;;ACAf,MAAA,IAAA,GAAA,CAAA;AACA,+BAA+B,EAAwD,MAAA,CAAA;AACvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAa,CAAA;;ACRN,SAAS,MAAM,EAAE;AACxB,IAAI,OAAO,IAAI,CAAC;AAChB;;;;"}",
},
]
`;

View File

@@ -1,75 +0,0 @@
# Snapshot report for `test/js-import/test.js`
The actual snapshot is saved in `test.js.snap`.
Generated by [AVA](https://avajs.dev).
## js-import
> Snapshot 1
[
{
code: `var asset0 = "data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2032%2032%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3A%2300ff0d%3Bstroke-width%3A5%3Bstroke-linecap%3Asquare%3Bstroke-linejoin%3Amiter%3Bstroke-dasharray%3Anone%3Bstroke-opacity%3A1%22%20d%3D%22M4.1%2014.72%2016%2026.31%2028.38%205.09%22%2F%3E%3C%2Fsvg%3E";␊
const html = \`<html><head>␊
<link rel="icon" href="${asset0}">␊
<!-- TODO: support for css imports are yet to be added (as simple assets or through a preprocessor-->␊
<!-- <link rel="stylesheet" href="./joker.css">-->␊
</head>␊
<body>␊
<!-- TODO: this shouldn't have been commented out, but our plugin fails if it is included (which shoudn't happen!!) -->␊
<!--<script src="./batman.js" type="module"></script>-->␊
</body></html>\`;␊
function render(){␊
return html;␊
}␊
export { render };␊
//# sourceMappingURL=index-3d1ca61b.js.map␊
`,
fileName: 'index-3d1ca61b.js',
map: SourceMap {
file: 'index-3d1ca61b.js',
mappings: 'AAAA,aAAe;;ACAf,MAAA,IAAA,GAAA,CAAA;AACA,+BAA+B,EAAwD,MAAA,CAAA;AACvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAa,CAAA;;ACRN,SAAS,MAAM,EAAE;AACxB,IAAI,OAAO,IAAI,CAAC;AAChB;;;;',
names: [],
sources: [
'../icon.svg',
'../index.html',
'../index.js',
],
sourcesContent: [
'export default "data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2032%2032%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3A%2300ff0d%3Bstroke-width%3A5%3Bstroke-linecap%3Asquare%3Bstroke-linejoin%3Amiter%3Bstroke-dasharray%3Anone%3Bstroke-opacity%3A1%22%20d%3D%22M4.1%2014.72%2016%2026.31%2028.38%205.09%22%2F%3E%3C%2Fsvg%3E"',
`<html>␊
<head>␊
<link rel="icon" href="./icon.svg">␊
<!-- TODO: support for css imports are yet to be added (as simple assets or through a preprocessor-->␊
<!-- <link rel="stylesheet" href="./joker.css">-->␊
</head>␊
<body>␊
<!-- TODO: this shouldn't have been commented out, but our plugin fails if it is included (which shoudn't happen!!) -->␊
<!--<script src="./batman.js" type="module"></script>-->␊
</body>␊
</html>␊
`,
`import html from "./index.html"␊
export function render(){␊
return html;␊
}␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'index-3d1ca61b.js.map',
map: undefined,
source: '{"version":3,"file":"index-3d1ca61b.js","sources":["../icon.svg","../index.html","../index.js"],"sourcesContent":["export default \\"data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2032%2032%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3A%2300ff0d%3Bstroke-width%3A5%3Bstroke-linecap%3Asquare%3Bstroke-linejoin%3Amiter%3Bstroke-dasharray%3Anone%3Bstroke-opacity%3A1%22%20d%3D%22M4.1%2014.72%2016%2026.31%2028.38%205.09%22%2F%3E%3C%2Fsvg%3E\\"","<html>\\n <head>\\n <link rel=\\"icon\\" href=\\"./icon.svg\\">\\n <!-- TODO: support for css imports are yet to be added (as simple assets or through a preprocessor-->\\n<!-- <link rel=\\"stylesheet\\" href=\\"./joker.css\\">-->\\n </head>\\n <body>\\n <!-- TODO: this shouldn\'t have been commented out, but our plugin fails if it is included (which shoudn\'t happen!!) -->\\n <!--<script src=\\"./batman.js\\" type=\\"module\\"></script>-->\\n </body>\\n</html>\\n","import html from \\"./index.html\\"\\n\\nexport function render(){\\n return html;\\n}\\n"],"names":[],"mappings":"AAAA,aAAe;;ACAf,MAAA,IAAA,GAAA,CAAA;AACA,+BAA+B,EAAwD,MAAA,CAAA;AACvF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAa,CAAA;;ACRN,SAAS,MAAM,EAAE;AACxB,IAAI,OAAO,IAAI,CAAC;AAChB;;;;"}',
},
]

View File

@@ -1,6 +1,6 @@
import {join, dirname} from "node:path"; import {join, dirname} from "node:path";
import {test, expect} from "@jest/globals";
import test from "ava";
import { rollup } from "rollup"; import { rollup } from "rollup";
import {debugPrintOutput, getCode} from "../util/index.ts"; import {debugPrintOutput, getCode} from "../util/index.ts";
@@ -8,11 +8,6 @@ import {debugPrintOutput, getCode} from "../util/index.ts";
import html from "../../src/index.ts"; import html from "../../src/index.ts";
import handlebars from "handlebars"; import handlebars from "handlebars";
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 {fileURLToPath} from "node:url";
import urlPlugin from "@rollup/plugin-url"; import urlPlugin from "@rollup/plugin-url";
@@ -25,7 +20,8 @@ const defaultAssetInclude = [
'**/*.(webm|mp4)',// video '**/*.(webm|mp4)',// video
]; ];
test.serial('js-import', async (t) => {
test('js-import', async () => {
const bundle = await rollup({ const bundle = await rollup({
input: 'index.js', input: 'index.js',
plugins: [ plugins: [
@@ -38,9 +34,9 @@ test.serial('js-import', async (t) => {
}), }),
] ]
}); });
const code = await getCode(bundle, output); const code = await getCode(bundle);
debugPrintOutput('js-import',code); debugPrintOutput('js-import',code);
t.snapshot(code); expect(code).toMatchSnapshot();
}); });

View File

@@ -0,0 +1,36 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`web-bundle 1`] = `
{
"console": [
"[info] %cDownload the React DevTools for a better development experience: https://reactjs.org/link/react-devtools font-weight:bold",
"[log] Bootstrapped, ready to go!",
"[log] Test my sourcemap: tick",
"[log] Test my sourcemap: ended",
],
"errors": [],
"html": "<html lang="en"><head>
<meta charset="UTF-8">
<title>
Test bundle!
</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%20%20%20%20%3Ctitle%3EHTML5%20Logo%3C%2Ftitle%3E%20%20%20%20%3Cpath%20d%3D%22M108.4%200h23v22.8h21.2V0h23v69h-23V46h-21v23h-23.2M206%2023h-20.3V0h63.7v23H229v46h-23M259.5%200h24.1l14.8%2024.3L313.2%200h24.1v69h-23V34.8l-16.1%2024.8l-16.1-24.8v34.2h-22.6M348.7%200h23v46.2h32.6V69h-55.6%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23e44d26%22%20d%3D%22M107.6%20471l-33-370.4h362.8l-33%20370.2L255.7%20512%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23f16529%22%20d%3D%22M256%20480.5V131H404.3L376%20447%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23ebebeb%22%20d%3D%22M142%20176.3h114v45.4h-64.2l4.2%2046.5h60v45.3H154.4M156.4%20336.3H202l3.2%2036.3%2050.8%2013.6v47.4l-93.2-26%22%2F%3E%20%20%20%20%3Cpath%20fill%3D%22%23fff%22%20d%3D%22M369.6%20176.3H255.8v45.4h109.6M361.3%20268.2H255.8v45.4h56l-5.3%2059-50.7%2013.6v47.2l93-25.8%22%2F%3E%3C%2Fsvg%3E">
<title>I'm cool!</title>
</head>
<body>
<div id="root"><div style="align-self: center;"><b>ended</b></div></div>
<script src="index.js" type="module"></script>
</body></html>",
"requestsFailed": [],
"responses": [
"200 http://localhost/index.html",
"200 http://localhost/index.js",
"200 http://localhost/app.js",
],
}
`;

View File

@@ -1,6 +1,5 @@
import {join, dirname} from "node:path"; import {join, dirname} from "node:path";
import {test, expect, jest} from "@jest/globals";
import test from "ava";
// Rollup * plugins // Rollup * plugins
import { rollup } from "rollup"; import { rollup } from "rollup";
@@ -12,24 +11,11 @@ import typescriptPlugin from "@rollup/plugin-typescript";
import replacePlugin from "@rollup/plugin-replace"; import replacePlugin from "@rollup/plugin-replace";
import html from "../../src/index.ts"; import html from "../../src/index.ts";
import serveTest from "../util/test-server.ts"; import {runBrowserTest} from "../util/browser-test.ts";
/**
* @type {OutputOptions}
*/
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
chunkFileNames: '[name].js',
entryFileNames: '[name].[extname]',
assetFileNames: '[name].[extname]',
};
import {fileURLToPath} from "node:url"; import {fileURLToPath} from "node:url";
import handlebars from "handlebars"; import handlebars from "handlebars";
// import {debugPrintOutput, getCode, runBrowserTest} from "../util/index.ts";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures')); process.chdir(join(__dirname, 'fixtures'));
@@ -40,8 +26,10 @@ const defaultAssetInclude = [
'**/*.(webm|mp4)',// video '**/*.(webm|mp4)',// video
]; ];
test.serial('web-bundle', async (t) => {
const bundle = await rollup({ jest.setTimeout(30*1000);// Bundling react + typescript is getting heavy
test('web-bundle', async () => {
const out = await runBrowserTest({
input: 'index.hbs', input: 'index.hbs',
treeshake: 'smallest', treeshake: 'smallest',
plugins: [ plugins: [
@@ -78,13 +66,20 @@ test.serial('web-bundle', async (t) => {
urlPlugin({ urlPlugin({
include: defaultAssetInclude, include: defaultAssetInclude,
}), }),
serveTest({
path: 'index.html',
t,
})
], ],
}, {
path: 'index.html'
},{
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
chunkFileNames: '[name].js',
entryFileNames: '[name].[extname]',
assetFileNames: '[name].[extname]',
}); });
const generated = await bundle.generate(output); expect(out).toMatchSnapshot();
// const code = await getCode(bundle, output);
// debugPrintOutput('jsx-web-app',code);
}); });

View File

@@ -0,0 +1,54 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`live-reload 1`] = `
[
{
"code": "
(function(l, r) { if (!l || l.getElementById('livereloadscript')) return; r = l.createElement('script'); r.async = 1; r.src = '//' + (self.location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1'; r.id = 'livereloadscript'; l.getElementsByTagName('head')[0].appendChild(r) })(self.document);
const test = ()=>{
return \`I'm "annoying" \${"in case we need to test \\\`string\\\` escaping."}. Hence this files \\'tries\\' to include all allowed forms of 'it'\`;
};
console.log(test());
export { test };
//# sourceMappingURL=batman.js.map
",
"fileName": "batman.js",
"map": SourceMap {
"file": "batman.js",
"mappings": ";;AAAY,MAAC,IAAI,GAAG,IAAI;AACxB,IAAI,OAAO,CAAC,eAAe,EAAE,8CAA8C,CAAC,iEAAiE,CAAC,CAAC;AAC/I,EAAC;AACD,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;;;;",
"names": [],
"sources": [
"../batman.js",
],
"sourcesContent": [
"export const test = ()=>{
return \`I'm "annoying" \${"in case we need to test \\\`string\\\` escaping."}. Hence this files \\'tries\\' to include all allowed forms of 'it'\`;
}
console.log(test());
",
],
"version": 3,
},
"source": undefined,
},
{
"code": undefined,
"fileName": "batman.js.map",
"map": undefined,
"source": "{"version":3,"file":"batman.js","sources":["../batman.js"],"sourcesContent":["export const test = ()=>{\\n return \`I'm \\"annoying\\" \${\\"in case we need to test \\\\\`string\\\\\` escaping.\\"}. Hence this files \\\\'tries\\\\' to include all allowed forms of 'it'\`;\\n}\\nconsole.log(test());\\n"],"names":[],"mappings":";;AAAY,MAAC,IAAI,GAAG,IAAI;AACxB,IAAI,OAAO,CAAC,eAAe,EAAE,8CAA8C,CAAC,iEAAiE,CAAC,CAAC;AAC/I,EAAC;AACD,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;;;;"}",
},
{
"code": undefined,
"fileName": "index.html",
"map": undefined,
"source": "<html><head>
</head>
<body>
<script src="batman.js" type="module"></script>
</body></html>",
},
]
`;

View File

@@ -1,60 +0,0 @@
# Snapshot report for `test/live-reload/test.js`
The actual snapshot is saved in `test.js.snap`.
Generated by [AVA](https://avajs.dev).
## live-reload
> Snapshot 1
[
{
code: `␊
(function(l, r) { if (!l || l.getElementById('livereloadscript')) return; r = l.createElement('script'); r.async = 1; r.src = '//' + (self.location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1'; r.id = 'livereloadscript'; l.getElementsByTagName('head')[0].appendChild(r) })(self.document);␊
const test = ()=>{␊
return \`I'm "annoying" ${"in case we need to test \\\`string\\\` escaping."}. Hence this files \\'tries\\' to include all allowed forms of 'it'\`;␊
};␊
console.log(test());␊
export { test };␊
//# sourceMappingURL=batman-1a5fc364.js.map␊
`,
fileName: 'batman-1a5fc364.js',
map: SourceMap {
file: 'batman-1a5fc364.js',
mappings: ';;AAAY,MAAC,IAAI,GAAG,IAAI;AACxB,IAAI,OAAO,CAAC,eAAe,EAAE,8CAA8C,CAAC,iEAAiE,CAAC,CAAC;AAC/I,EAAC;AACD,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;;;;',
names: [],
sources: [
'../batman.js',
],
sourcesContent: [
`export const test = ()=>{␊
return \`I'm "annoying" ${"in case we need to test \\\`string\\\` escaping."}. Hence this files \\'tries\\' to include all allowed forms of 'it'\`;␊
}␊
console.log(test());␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'batman-1a5fc364.js.map',
map: undefined,
source: '{"version":3,"file":"batman-1a5fc364.js","sources":["../batman.js"],"sourcesContent":["export const test = ()=>{\\n return `I\'m \\"annoying\\" ${\\"in case we need to test \\\\`string\\\\` escaping.\\"}. Hence this files \\\\\'tries\\\\\' to include all allowed forms of \'it\'`;\\n}\\nconsole.log(test());\\n"],"names":[],"mappings":";;AAAY,MAAC,IAAI,GAAG,IAAI;AACxB,IAAI,OAAO,CAAC,eAAe,EAAE,8CAA8C,CAAC,iEAAiE,CAAC,CAAC;AAC/I,EAAC;AACD,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;;;;"}',
},
{
code: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>␊
</head>␊
<body>␊
<script src="batman-1a5fc364.js" type="module"></script>␊
</body></html>`,
},
]

View File

@@ -1,24 +1,18 @@
import {join, dirname} from "node:path"; import {join, dirname} from "node:path";
import {test, expect} from "@jest/globals";
import test from "ava";
import {rollup} from "rollup"; import {rollup} from "rollup";
import liveReload from "rollup-plugin-livereload"; import liveReload from "rollup-plugin-livereload";
import {debugPrintOutput, getCode} from "../util/index.ts"; import {debugPrintOutput, getCode} from "../util/index.ts";
import html from "../../src/index.ts"; 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 {fileURLToPath} from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures')); process.chdir(join(__dirname, 'fixtures'));
test.serial('live-reload', async (t) => { test('live-reload', async () => {
const bundle = await rollup({ const bundle = await rollup({
input: 'index.html', input: 'index.html',
plugins: [ plugins: [
@@ -29,10 +23,10 @@ test.serial('live-reload', async (t) => {
}) })
] ]
}); });
const code = await getCode(bundle, output); const code = await getCode(bundle);
await bundle.close();// Make sure live-reload closes itself await bundle.close();// Make sure live-reload closes itself
debugPrintOutput('live-reload',code); debugPrintOutput('live-reload',code);
t.snapshot(code); expect(code).toMatchSnapshot();
}); });
// TODO various parameters // TODO various parameters

View File

@@ -0,0 +1,125 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`multi-entry 1`] = `
[
{
"code": "const b = ()=>'batman';
console.log(b());
export { b };
//# sourceMappingURL=batman.js.map
",
"fileName": "admin/batman.js",
"map": SourceMap {
"file": "batman.js",
"mappings": "AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;",
"names": [],
"sources": [
"../../admin/batman.js",
],
"sourcesContent": [
"export const b = ()=>'batman';
console.log(b());
",
],
"version": 3,
},
"source": undefined,
},
{
"code": undefined,
"fileName": "admin/batman.js.map",
"map": undefined,
"source": "{"version":3,"file":"batman.js","sources":["../../admin/batman.js"],"sourcesContent":["export const b = ()=>'batman';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}",
},
{
"code": undefined,
"fileName": "admin/index.body.script0.js.js.map",
"map": undefined,
"source": "{"version":3,"file":"index.body.script0.js.js","sources":["../../app/admin-deps.js","../../admin/index.html.body.script0.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": "admin/index.html",
"map": undefined,
"source": "<html><head>
</head>
<body>
<div id="root"></div>
<script type="module">import { b as bootstrap } from '../app.js';
function adminDeps(){
return "robin!";
}
bootstrap(document.getElementById('root'), adminDeps());
//# sourceMappingURL=index.body.script0.js.js.map
</script>
<script src="batman.js" type="module"></script>
</body></html>",
},
{
"code": "const bootstrap = (el,deps = [])=>{
el.innerHtml = \`
<div>I'm "annoying" \${"in case we need to test \\\`string\\\` escaping."}. Hence this file \\'tries\\' to include all allowed forms of 'it'</div>
<div>Deps: \${deps}</div>
\`;
};
export { bootstrap as b };
//# sourceMappingURL=app.js.map
",
"fileName": "app.js",
"map": SourceMap {
"file": "app.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 = \`
<div>I'm "annoying" \${"in case we need to test \\\`string\\\` escaping."}. Hence this file \\'tries\\' to include all allowed forms of 'it'</div>
<div>Deps: \${deps}</div>
\`;
}
",
],
"version": 3,
},
"source": undefined,
},
{
"code": undefined,
"fileName": "app.js.map",
"map": undefined,
"source": "{"version":3,"file":"app.js","sources":["../app/app.js"],"sourcesContent":["export const bootstrap = (el,deps = [])=>{\\n el.innerHtml = \`\\n <div>I'm \\"annoying\\" \${\\"in case we need to test \\\\\`string\\\\\` escaping.\\"}. Hence this file \\\\'tries\\\\' to include all allowed forms of 'it'</div>\\n <div>Deps: \${deps}</div>\\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.body.script.js.js.map",
"map": undefined,
"source": "{"version":3,"file":"index.body.script.js.js","sources":["../index.html.body.script.js"],"sourcesContent":["\\n import {bootstrap} from \\"./app/app.js\\"\\n bootstrap(document.getElementById('root'), \\"<none>\\");\\n "],"names":[],"mappings":";;AAEY,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC"}",
},
{
"code": undefined,
"fileName": "index.html",
"map": undefined,
"source": "<html><head>
</head>
<body>
<div id="root"></div>
<script type="module">import { b as bootstrap } from './app.js';
bootstrap(document.getElementById('root'), "<none>");
//# sourceMappingURL=index.body.script.js.js.map
</script>
</body></html>",
},
]
`;

View File

@@ -1,131 +0,0 @@
# 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 b = ()=>'batman';␊
console.log(b());␊
export { b };␊
//# sourceMappingURL=batman-c7fa228c.js.map␊
`,
fileName: 'admin/batman-c7fa228c.js',
map: SourceMap {
file: 'batman-c7fa228c.js',
mappings: 'AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;',
names: [],
sources: [
'../../admin/batman.js',
],
sourcesContent: [
`export const b = ()=>'batman';␊
console.log(b());␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'admin/batman-c7fa228c.js.map',
map: undefined,
source: '{"version":3,"file":"batman-c7fa228c.js","sources":["../../admin/batman.js"],"sourcesContent":["export const b = ()=>\'batman\';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}',
},
{
code: undefined,
fileName: 'admin/index.body.script0.js-15dfaff3.js.map',
map: undefined,
source: '{"version":3,"file":"index.body.script0.js-15dfaff3.js","sources":["../../app/admin-deps.js","../../admin/index.html.body.script0.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: 'admin/index.html',
map: undefined,
source: `<html><head>␊
</head>␊
<body>␊
<div id="root"></div>␊
<script type="module">import { b as bootstrap } from '../app-01141b67.js';␊
function adminDeps(){␊
return "robin!";␊
}␊
bootstrap(document.getElementById('root'), adminDeps());␊
//# sourceMappingURL=index.body.script0.js-15dfaff3.js.map␊
</script>␊
<script src="batman-c7fa228c.js" type="module"></script>␊
</body></html>`,
},
{
code: `const bootstrap = (el,deps = [])=>{␊
el.innerHtml = \`
<div>I'm "annoying" ${"in case we need to test \\\`string\\\` escaping."}. Hence this file \\'tries\\' to include all allowed forms of 'it'</div>␊
<div>Deps: ${deps}</div>␊
\`;␊
};␊
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 = \`␊
<div>I'm "annoying" ${"in case we need to test \\\`string\\\` escaping."}. Hence this file \\'tries\\' to include all allowed forms of 'it'</div>␊
<div>Deps: ${deps}</div>␊
\`;␊
}␊
`,
],
version: 3,
},
source: undefined,
},
{
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 <div>I\'m \\"annoying\\" ${\\"in case we need to test \\\\`string\\\\` escaping.\\"}. Hence this file \\\\\'tries\\\\\' to include all allowed forms of \'it\'</div>\\n <div>Deps: ${deps}</div>\\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.body.script.js-45303f0f.js.map',
map: undefined,
source: '{"version":3,"file":"index.body.script.js-45303f0f.js","sources":["../index.html.body.script.js"],"sourcesContent":["\\n import {bootstrap} from \\"./app/app.js\\"\\n bootstrap(document.getElementById(\'root\'), \\"<none>\\");\\n "],"names":[],"mappings":";;AAEY,SAAS,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC"}',
},
{
code: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>␊
</head>␊
<body>␊
<div id="root"></div>␊
<script type="module">import { b as bootstrap } from './app-01141b67.js';␊
bootstrap(document.getElementById('root'), "<none>");␊
//# sourceMappingURL=index.body.script.js-45303f0f.js.map␊
</script>␊
</body></html>`,
},
]

View File

@@ -1,23 +1,17 @@
import {resolve, join, dirname} from "node:path"; import {resolve, join, dirname} from "node:path";
import {test, expect} from "@jest/globals";
import test from "ava";
import { rollup } from "rollup"; import { rollup } from "rollup";
import {debugPrintOutput, getCode} from "../util/index.ts"; import {debugPrintOutput, getCode} from "../util/index.ts";
import html from "../../src/index.ts"; 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 {fileURLToPath} from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures')); process.chdir(join(__dirname, 'fixtures'));
test.serial('multi-entry', async (t) => { test('multi-entry', async () => {
const bundle = await rollup({ const bundle = await rollup({
input: { input: {
['index']: 'index.html', ['index']: 'index.html',
@@ -28,9 +22,9 @@ test.serial('multi-entry', async (t) => {
}), }),
] ]
}); });
const code = await getCode(bundle, output); const code = await getCode(bundle);
debugPrintOutput('multi-entry',code); debugPrintOutput('multi-entry',code);
t.snapshot(code); expect(code).toMatchSnapshot();
}); });
// TODO various parameters // TODO various parameters

View File

@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`rewrite-url 1`] = `undefined`;

View File

@@ -1,74 +0,0 @@
# Snapshot report for `test/rewrite-url/test.js`
The actual snapshot is saved in `test.js.snap`.
Generated by [AVA](https://avajs.dev).
## rewrite-url
> Snapshot 1
[
{
code: `const bootstrap = (el,deps = [])=>{␊
el.innerHtml = \`
<div>load the app</div>␊
\`;␊
};␊
export { bootstrap };␊
//# sourceMappingURL=app-88ed8fd6.js.map␊
`,
fileName: 'admin/app-88ed8fd6.js',
map: SourceMap {
file: 'app-88ed8fd6.js',
mappings: 'AAAY,MAAC,SAAS,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,GAAG;AACzC,IAAI,EAAE,CAAC,SAAS,GAAG,CAAC;AACpB;AACA,IAAI,CAAC,CAAC;AACN;;;;',
names: [],
sources: [
'../../admin/app.js',
],
sourcesContent: [
`export const bootstrap = (el,deps = [])=>{␊
el.innerHtml = \`␊
<div>load the app</div>␊
\`;␊
}␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'admin/app-88ed8fd6.js.map',
map: undefined,
source: '{"version":3,"file":"app-88ed8fd6.js","sources":["../../admin/app.js"],"sourcesContent":["export const bootstrap = (el,deps = [])=>{\\n el.innerHtml = `\\n <div>load the app</div>\\n `;\\n}\\n"],"names":[],"mappings":"AAAY,MAAC,SAAS,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,GAAG;AACzC,IAAI,EAAE,CAAC,SAAS,GAAG,CAAC;AACpB;AACA,IAAI,CAAC,CAAC;AACN;;;;"}',
},
{
code: undefined,
fileName: 'admin/index.html',
map: undefined,
source: `<html><head>␊
</head>␊
<body>␊
<div id="root"></div>␊
<script src="/admin/app-88ed8fd6.js" type="module"></script>␊
</body></html>`,
},
{
code: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>␊
</head>␊
<body>␊
<div id="root"></div>␊
<script src="/admin/app-88ed8fd6.js" type="module"></script>␊
</body></html>`,
},
]

View File

@@ -1,24 +1,17 @@
import {resolve, join, dirname} from "node:path"; import {resolve, join, dirname} from "node:path";
import * as path from "node:path"; import {test, expect} from "@jest/globals";
import test from "ava";
import { rollup } from "rollup"; import {runBrowserTest} from "../util/index.ts";
import {debugPrintOutput, getCode} from "../util/index.ts";
import html from "../../src/index.ts"; 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 {fileURLToPath} from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures')); process.chdir(join(__dirname, 'fixtures'));
test.serial('rewrite-url', async (t) => { test('rewrite-url', async () => {
const bundle = await rollup({ const out = await runBrowserTest({
input: { input: {
['index']: 'index.html', ['index']: 'index.html',
['admin/index']: resolve(__dirname,'fixtures','admin/index.html'), ['admin/index']: resolve(__dirname,'fixtures','admin/index.html'),
@@ -30,11 +23,36 @@ test.serial('rewrite-url', async (t) => {
return `/${rootPath}`; return `/${rootPath}`;
} }
}), }),
] ],
},{
filterOutput:{
// TODO: Currently only need the "await getCode(bundle, output);" as output
},
path: '/admin'
}, {
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
}); });
const code = await getCode(bundle, output); expect(out.code).toMatchSnapshot(); // Snapshot the result code
debugPrintOutput('rewrite-url',code);
t.snapshot(code); // const bundle = await rollup({
// input: {
// ['index']: 'index.html',
// ['admin/index']: resolve(__dirname,'fixtures','admin/index.html'),
// ['admin/app']: resolve(__dirname,'fixtures','admin/app.js'),
// },
// plugins: [
// html({
// rewriteUrl(relative, {rootPath, from}){
// return `/${rootPath}`;
// }
// }),
// ]
// });
// const code = await getCode(bundle, output);
// debugPrintOutput('rewrite-url',code);
// t.snapshot(code);
}); });
// TODO various parameters // TODO various parameters

2
test/setup.js Normal file
View File

@@ -0,0 +1,2 @@
// Replace the jest console with the normal one (jest makes console.log too verbose)
global.console = await import("node:console");

View File

@@ -0,0 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`handlebars 1`] = `
[
{
"code": "const b = ()=>'batman';
console.log(b());
export { b };
//# sourceMappingURL=batman.js.map
",
"fileName": "batman.js",
"map": SourceMap {
"file": "batman.js",
"mappings": "AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;",
"names": [],
"sources": [
"../batman.js",
],
"sourcesContent": [
"export const b = ()=>'batman';
console.log(b());
",
],
"version": 3,
},
"source": undefined,
},
{
"code": undefined,
"fileName": "batman.js.map",
"map": undefined,
"source": "{"version":3,"file":"batman.js","sources":["../batman.js"],"sourcesContent":["export const b = ()=>'batman';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}",
},
{
"code": undefined,
"fileName": "index.html",
"map": undefined,
"source": "<html><head>
<meta data-test="a">
</head>
<body>
<script src="batman.js" type="module"></script>
</body></html>",
},
]
`;

View File

@@ -1,55 +0,0 @@
# Snapshot report for `test/templating/test.js`
The actual snapshot is saved in `test.js.snap`.
Generated by [AVA](https://avajs.dev).
## handlebars
> Snapshot 1
[
{
code: `const b = ()=>'batman';␊
console.log(b());␊
export { b };␊
//# sourceMappingURL=batman-c7fa228c.js.map␊
`,
fileName: 'batman-c7fa228c.js',
map: SourceMap {
file: 'batman-c7fa228c.js',
mappings: 'AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;',
names: [],
sources: [
'../batman.js',
],
sourcesContent: [
`export const b = ()=>'batman';␊
console.log(b());␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'batman-c7fa228c.js.map',
map: undefined,
source: '{"version":3,"file":"batman-c7fa228c.js","sources":["../batman.js"],"sourcesContent":["export const b = ()=>\'batman\';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}',
},
{
code: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>␊
<meta data-test="a">␊
</head>␊
<body>␊
<script src="batman-c7fa228c.js" type="module"></script>␊
</body></html>`,
},
]

View File

@@ -1,6 +1,6 @@
import {join, dirname} from "node:path"; import {join, dirname} from "node:path";
import {test, expect} from "@jest/globals";
import test from "ava";
import { rollup } from "rollup"; import { rollup } from "rollup";
import {debugPrintOutput, getCode} from "../util/index.ts"; import {debugPrintOutput, getCode} from "../util/index.ts";
@@ -8,18 +8,11 @@ import {debugPrintOutput, getCode} from "../util/index.ts";
import html from "../../src/index.ts"; import html from "../../src/index.ts";
import handlebars from "handlebars"; import handlebars from "handlebars";
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 {fileURLToPath} from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures')); process.chdir(join(__dirname, 'fixtures'));
test('handlebars', async () => {
test.serial('handlebars', async (t) => {
const bundle = await rollup({ const bundle = await rollup({
input: 'index.hbs', input: 'index.hbs',
plugins: [ plugins: [
@@ -30,9 +23,9 @@ test.serial('handlebars', async (t) => {
}) })
] ]
}); });
const code = await getCode(bundle, output); const code = await getCode(bundle);
debugPrintOutput('handlebars',code); debugPrintOutput('handlebars',code);
t.snapshot(code); expect(code).toMatchSnapshot();
}); });

View File

@@ -0,0 +1,97 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`url-plugin copied-assets 1`] = `
[
{
"code": "const b = ()=>'batman';
console.log(b());
export { b };
//# sourceMappingURL=batman.js.map
",
"fileName": "batman.js",
"map": SourceMap {
"file": "batman.js",
"mappings": "AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;",
"names": [],
"sources": [
"../batman.js",
],
"sourcesContent": [
"export const b = ()=>'batman';
console.log(b());
",
],
"version": 3,
},
"source": undefined,
},
{
"code": undefined,
"fileName": "batman.js.map",
"map": undefined,
"source": "{"version":3,"file":"batman.js","sources":["../batman.js"],"sourcesContent":["export const b = ()=>'batman';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}",
},
{
"code": undefined,
"fileName": "index.html",
"map": undefined,
"source": "<html><head>
<link rel="icon" href="fb585fdb6db313c9.svg">
</head>
<body>
<script src="batman.js" type="module"></script>
</body></html>",
},
]
`;
exports[`url-plugin inlined-assets 1`] = `
[
{
"code": "const b = ()=>'batman';
console.log(b());
export { b };
//# sourceMappingURL=batman.js.map
",
"fileName": "batman.js",
"map": SourceMap {
"file": "batman.js",
"mappings": "AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;",
"names": [],
"sources": [
"../batman.js",
],
"sourcesContent": [
"export const b = ()=>'batman';
console.log(b());
",
],
"version": 3,
},
"source": undefined,
},
{
"code": undefined,
"fileName": "batman.js.map",
"map": undefined,
"source": "{"version":3,"file":"batman.js","sources":["../batman.js"],"sourcesContent":["export const b = ()=>'batman';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}",
},
{
"code": undefined,
"fileName": "index.html",
"map": undefined,
"source": "<html><head>
<link rel="icon" href="data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2032%2032%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3A%2300ff0d%3Bstroke-width%3A5%3Bstroke-linecap%3Asquare%3Bstroke-linejoin%3Amiter%3Bstroke-dasharray%3Anone%3Bstroke-opacity%3A1%22%20d%3D%22M4.1%2014.72%2016%2026.31%2028.38%205.09%22%2F%3E%3C%2Fsvg%3E">
</head>
<body>
<script src="batman.js" type="module"></script>
</body></html>",
},
]
`;

View File

@@ -1,105 +0,0 @@
# Snapshot report for `test/url-plugin/test.js`
The actual snapshot is saved in `test.js.snap`.
Generated by [AVA](https://avajs.dev).
## copied-assets
> Snapshot 1
[
{
code: `const b = ()=>'batman';␊
console.log(b());␊
export { b };␊
//# sourceMappingURL=batman-c7fa228c.js.map␊
`,
fileName: 'batman-c7fa228c.js',
map: SourceMap {
file: 'batman-c7fa228c.js',
mappings: 'AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;',
names: [],
sources: [
'../batman.js',
],
sourcesContent: [
`export const b = ()=>'batman';␊
console.log(b());␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'batman-c7fa228c.js.map',
map: undefined,
source: '{"version":3,"file":"batman-c7fa228c.js","sources":["../batman.js"],"sourcesContent":["export const b = ()=>\'batman\';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}',
},
{
code: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>␊
<link rel="icon" href="fb585fdb6db313c9.svg">␊
</head>␊
<body>␊
<script src="batman-c7fa228c.js" type="module"></script>␊
</body></html>`,
},
]
## inlined-assets
> Snapshot 1
[
{
code: `const b = ()=>'batman';␊
console.log(b());␊
export { b };␊
//# sourceMappingURL=batman-c7fa228c.js.map␊
`,
fileName: 'batman-c7fa228c.js',
map: SourceMap {
file: 'batman-c7fa228c.js',
mappings: 'AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;',
names: [],
sources: [
'../batman.js',
],
sourcesContent: [
`export const b = ()=>'batman';␊
console.log(b());␊
`,
],
version: 3,
},
source: undefined,
},
{
code: undefined,
fileName: 'batman-c7fa228c.js.map',
map: undefined,
source: '{"version":3,"file":"batman-c7fa228c.js","sources":["../batman.js"],"sourcesContent":["export const b = ()=>\'batman\';\\nconsole.log(b());\\n"],"names":[],"mappings":"AAAY,MAAC,CAAC,GAAG,IAAI,SAAS;AAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;;;;"}',
},
{
code: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>␊
<link rel="icon" href="data:image/svg+xml,%3Csvg%20viewBox%3D%220%200%2032%2032%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%3Cpath%20style%3D%22fill%3Anone%3Bstroke%3A%2300ff0d%3Bstroke-width%3A5%3Bstroke-linecap%3Asquare%3Bstroke-linejoin%3Amiter%3Bstroke-dasharray%3Anone%3Bstroke-opacity%3A1%22%20d%3D%22M4.1%2014.72%2016%2026.31%2028.38%205.09%22%2F%3E%3C%2Fsvg%3E">␊
</head>␊
<body>␊
<script src="batman-c7fa228c.js" type="module"></script>␊
</body></html>`,
},
]

View File

@@ -1,6 +1,6 @@
import {join, dirname} from "node:path"; import {join, dirname} from "node:path";
import {test, expect} from "@jest/globals";
import test from "ava";
import { rollup } from "rollup"; import { rollup } from "rollup";
import urlPlugin from "@rollup/plugin-url"; import urlPlugin from "@rollup/plugin-url";
@@ -8,11 +8,6 @@ import {debugPrintOutput, getCode} from "../util/index.ts";
import html from "../../src/index.ts"; 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 {fileURLToPath} from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
@@ -25,40 +20,43 @@ const defaultAssetInclude = [
'**/*.(webm|mp4)',// video '**/*.(webm|mp4)',// video
]; ];
test.serial('copied-assets', async (t) => { describe("url-plugin", ()=>{
const bundle = await rollup({ test('copied-assets', async () => {
input: 'index.html', const bundle = await rollup({
plugins: [ input: 'index.html',
html({ plugins: [
}), html({
urlPlugin({ }),
include: defaultAssetInclude, urlPlugin({
limit: 0,// Never inline something include: defaultAssetInclude,
}), limit: 0,// Never inline something
], }),
],
});
const code = await getCode(bundle);
debugPrintOutput('copied-assets',code);
expect(code).toMatchSnapshot();
}); });
const code = await getCode(bundle, output);
debugPrintOutput('copied-assets',code);
t.snapshot(code);
});
test.serial('inlined-assets', async (t) => { test('inlined-assets', async () => {
const bundle = await rollup({ const bundle = await rollup({
input: 'index.html', input: 'index.html',
plugins: [ plugins: [
html({ html({
}), }),
urlPlugin({ urlPlugin({
include: defaultAssetInclude, include: defaultAssetInclude,
limit: Number.MAX_SAFE_INTEGER,// Always inline things limit: Number.MAX_SAFE_INTEGER,// Always inline things
}), }),
] ]
});
const code = await getCode(bundle);
debugPrintOutput('inlined-assets',code);
expect(code).toMatchSnapshot();
}); });
const code = await getCode(bundle, output); })
debugPrintOutput('inlined-assets',code);
t.snapshot(code);
});
// TODO various parameters // TODO various parameters
// - format: cjs, iifi, ... // - format: cjs, iifi, ...

69
test/util/browser-test.ts Normal file
View File

@@ -0,0 +1,69 @@
import {Plugin, InputPluginOption, RollupOptions, OutputOptions, RollupOutput} from "rollup";
import {TestOptions as BrowserTestOptions, TestOutput as PuppeteerTestOutput} from "./puppeteer-run-test.js";
import { rollup } from "rollup";
import serveTest, {LogCallback} from "./serve-test.ts";
import {getCode, TestOutput} from "./code-output.ts";
import {defaultOutput} from "./default-output.ts";
export interface OutputFilterOptions {
html?: boolean
console?: ('log'|'error'|'warn')[] | true
errors?: boolean, // again don't know possible values
responses?: boolean, // interesting to see what other values were requested
requestsFailed?: boolean, // will probably also be replicated into console errors, but helpful to have if imports werent found
}
export interface BrowserTestInput extends BrowserTestOptions{
log?: LogCallback;
/**
* Optionally specify what to filter from the output
*/
filterOutput?: OutputFilterOptions;
}
export interface BrowserTestOutput extends PuppeteerTestOutput{
code: TestOutput[];
}
export async function runBrowserTest(
build: RollupOptions,
test?: BrowserTestInput | false,
output?: OutputOptions
) : Promise<Partial<BrowserTestOutput>>{
const resolvedPlugins = await Promise.resolve(build.plugins||null);
let pluginsArray : InputPluginOption[] = [];
if(resolvedPlugins && resolvedPlugins instanceof Array){
pluginsArray = resolvedPlugins
}else if(resolvedPlugins){
pluginsArray = [resolvedPlugins];
}
let testOutput: Partial<BrowserTestOutput> = {};
const bundle = await rollup({
...build,
plugins: [
...pluginsArray,
// TODO check if browser output is requested (either for snapshot or for testing)
...(test? [serveTest({
// TODO: intercept output from the serveTest? (and include as one bit in output options below, for snapshotting)
...test,
log: test.log ?? console.log,
onResult: (output)=>{
testOutput = {...testOutput, ...output};
}
})]: [])
]
});
// TODO make configurable?
if(output){
testOutput.code = await getCode(bundle);
}else{
const generated = await bundle.generate(defaultOutput);
}
await bundle.close();
return testOutput
}

View File

@@ -1,4 +1,5 @@
import type {RollupBuild, OutputOptions, OutputAsset, OutputChunk, SourceMap} from "rollup"; import type {RollupBuild, OutputOptions, OutputAsset, OutputChunk, SourceMap} from "rollup";
import {defaultOutput} from "./default-output.ts";
export interface TestOutput{ export interface TestOutput{
code: string, code: string,
@@ -7,7 +8,7 @@ export interface TestOutput{
map: any map: any
} }
export const getCode = async (bundle: RollupBuild, outputOptions: OutputOptions): Promise<TestOutput[]> => { export const getCode = async (bundle: RollupBuild, outputOptions: OutputOptions = defaultOutput): Promise<TestOutput[]> => {
const { output } = await bundle.generate(outputOptions || { format: 'cjs', exports: 'auto' }); const { output } = await bundle.generate(outputOptions || { format: 'cjs', exports: 'auto' });
return output.sort((a,b)=> { return output.sort((a,b)=> {

View File

@@ -0,0 +1,11 @@
import type {OutputOptions} from "rollup";
export const defaultOutput : OutputOptions = {
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
// Prevent hashes from being added (and screw up the snapshots)
chunkFileNames: '[name].js',
entryFileNames: '[name].js',
assetFileNames: '[name].[extname]',
};

View File

@@ -1,6 +1,8 @@
// TODO: this should be the main module used, other should be imported manually if exceptions are needed?
export * from "./browser-test.ts";
export * from "./code-output.ts"; export * from "./code-output.ts";
export * from "./print-code-output.ts"; export * from "./print-code-output.ts";
export * from "./test-server.ts"; export * from "./serve-test.ts";
// export * from './misc.js';
export * from './misc.js';

View File

@@ -1,3 +1,5 @@
// This is still from the old rollup plugin we forked from. For now not used.
import path from "node:path"; import path from "node:path";
import process from "node:process"; import process from "node:process";

View File

@@ -10,44 +10,29 @@ import {isInDebugMode} from "./debug-mode.ts";
export type PageTestCallback = (page: Page)=>Promise<void>; export type PageTestCallback = (page: Page)=>Promise<void>;
export interface TestFilterOptions{
html?: boolean
console?: ('log'|'error'|'warn')[] | true
errors?: boolean, // again don't know possible values
responses?: boolean, // interesting to see what other values were requested
requestsFailed?: boolean, // will probably also be replicated into console errors, but helpful to have if imports werent found
}
export interface TestOptions { export interface TestOptions {
page: string path: string
cb: PageTestCallback cb: PageTestCallback
filterOutput: TestFilterOptions
replaceHost: boolean replaceHost: boolean
replaceHostWith?: string replaceHostWith?: string
} }
const defaultOptions: Partial<TestOptions> = { const defaultOptions: Partial<TestOptions> = {
page: 'index.html', path: 'index.html',
cb: async (page: Page)=>{ cb: async (page: Page)=>{
await page.waitForNetworkIdle({}); await page.waitForNetworkIdle({});
}, },
replaceHost: true, replaceHost: true,
replaceHostWith: `http://localhost`, replaceHostWith: `http://localhost`,
filterOutput:{
html: true,
console: ['log','error','warn'],// TODO: or warning? need to check what possible values are
errors: true, // again don't know possible values
responses: true, // interesting to see what other values were requested
requestsFailed: true, // will probably also be replicated into console errors, but helpful to have if imports werent found
}
} }
export interface TestOutput{ export interface TestOutput{
html?: string, html: string,
console?: string[], console: string[],
errors?: string[], errors: string[],
responses?: string[], responses: string[],
requestsFailed?: string[], requestsFailed: string[],
} }
/** /**
* Opens a page in a puppeteer browser and return the resulting HTML and logmessages produced. * Opens a page in a puppeteer browser and return the resulting HTML and logmessages produced.
* Optionally a callback can be provided to simulate user interactions on the page before returning the HTML * Optionally a callback can be provided to simulate user interactions on the page before returning the HTML
@@ -56,21 +41,16 @@ export interface TestOutput{
* @param opts * @param opts
* @param hostUrl * @param hostUrl
*/ */
export async function runTest(opts: Partial<TestOptions>, hostUrl: string){ export async function puppeteerRunTest(opts: Partial<TestOptions>, hostUrl: string){
const options : TestOptions = (<TestOptions>{ const options : TestOptions = (<TestOptions>{
...defaultOptions, ...defaultOptions,
...opts, ...opts,
filterOutput: {
...defaultOptions.filterOutput,
...(opts?.filterOutput),
},
}); });
const { const {
page: path, path,
cb, cb,
replaceHost, replaceHost,
replaceHostWith, replaceHostWith,
filterOutput
} = options; } = options;
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
@@ -79,64 +59,64 @@ export async function runTest(opts: Partial<TestOptions>, hostUrl: string){
const page = await browser.newPage(); const page = await browser.newPage();
let output : TestOutput = { let output : TestOutput = {
html: '',
console: [], console: [],
errors: [], errors: [],
responses: [], responses: [],
requestsFailed: [] requestsFailed: []
}; };
try{ let errored = false;
try {
// Track requests, errors and console // Track requests, errors and console
page.on('console', message => { page.on('console', message => {
let [type, text] = [message.type(), message.text()]; let [type, text] = [message.type(), message.text()];
if(replaceHost){ if (replaceHost) {
text = text.replaceAll(hostUrl, replaceHostWith!); text = text.replaceAll(hostUrl, replaceHostWith!);
} }
if((<any>filterOutput.console)?.includes?.(<any>type) ?? (filterOutput.console === true)){// TODO: add callback option output.console?.push(`[${type}] ${text}`);
output.console?.push(`[${type}] ${text}`); }).on('pageerror', ({message}) => {
}
}).on('pageerror', ({ message }) => {
let text = message; let text = message;
if(replaceHost){ if (replaceHost) {
text = text.replaceAll(hostUrl, replaceHostWith!); text = text.replaceAll(hostUrl, replaceHostWith!);
} }
if(filterOutput.errors === true) {// TODO add callback option output.errors?.push(text);
output.errors?.push(text)
}
}).on('response', response => { }).on('response', response => {
let [status, url] = [response.status(), response.url()] let [status, url] = [response.status(), response.url()]
if(replaceHost){ if (replaceHost) {
url = url.replaceAll(hostUrl, replaceHostWith!); url = url.replaceAll(hostUrl, replaceHostWith!);
} }
if(filterOutput.responses === true) {// TODO add callback option output.responses?.push(`${status} ${url}`);
output.responses?.push(`${status} ${url}`)
}
}).on('requestfailed', request => { }).on('requestfailed', request => {
let [failure, url] = [request.failure()?.errorText, request.url()]; let [failure, url] = [request.failure()?.errorText, request.url()];
if(replaceHost){ if (replaceHost) {
failure = failure?.replaceAll(hostUrl, replaceHostWith!); failure = failure?.replaceAll(hostUrl, replaceHostWith!);
url = url.replaceAll(hostUrl, replaceHostWith!); url = url.replaceAll(hostUrl, replaceHostWith!);
} }
if(filterOutput.requestsFailed === true) {// TODO add callback option output.requestsFailed?.push(`${failure} ${url}`);
output.requestsFailed?.push(`${failure} ${url}`)
}
}); });
const url = new URL(`${hostUrl}/${path??''}`); const url = new URL(path??'', hostUrl);
await page.goto(url.href); await page.goto(url.href);
if(!cb) { if (!cb) {
await page.waitForNetworkIdle({}); await page.waitForNetworkIdle({});
}else{ } else {
await cb(page); await cb(page);
} }
const htmlHandle = await page.$('html'); const htmlHandle = await page.$('html');
const html = await page.evaluate(html => html?.outerHTML??html?.innerHTML, htmlHandle); const html = await page.evaluate(html => html?.outerHTML ?? html?.innerHTML, htmlHandle);
// Add the final html // Add the final html
output.html = html; output.html = html || '';
return output;
}catch(err){
errored = true;
throw err;
}finally{ }finally{
if(isInDebugMode()){ if(isInDebugMode() && !errored){
console.log(`DEBUG MODE ENABLED, Close the puppeteer browsertab to continue!\n${import.meta.url}:144`); console.log(`DEBUG MODE ENABLED, Close the puppeteer browsertab to continue!\n${import.meta.url}:144`);
await new Promise((resolve)=>{ await new Promise((resolve)=>{
page.on('close', ()=>{ page.on('close', ()=>{
@@ -147,9 +127,7 @@ export async function runTest(opts: Partial<TestOptions>, hostUrl: string){
}else{ }else{
await page.close(); await page.close();
} }
await browser.close(); await browser.close();
} }
return output;
} }

View File

@@ -4,10 +4,12 @@
*/ */
import {runTest, TestFilterOptions, PageTestCallback} from "./run-browser-test.ts"; import {puppeteerRunTest, PageTestCallback, TestOutput} from "./puppeteer-run-test.ts";
import {isInDebugMode} from "./debug-mode.ts"; import {isInDebugMode} from "./debug-mode.ts";
import {resolve, posix} from "node:path"; import {resolve, posix} from "node:path";
import fs from "node:fs/promises";
import type {Stats} from "node:fs";
import { createServer as createHttpsServer } from 'https' import { createServer as createHttpsServer } from 'https'
import { createServer} from 'http' import { createServer} from 'http'
@@ -32,27 +34,27 @@ type TypeMap = {
}; };
type ErrorCodeException = Error & {code: string}; type ErrorCodeException = Error & {code: string};
export type TestResultCallback = (output: TestOutput)=>void;
export type LogCallback = (...args: string[])=>void;
export interface RollupServeTestOptions {
export interface ServeTestOptions {
/** /**
* Change the path to be opened when the test is started * Change the path to be opened when the test is started
* Remember to start with a slash, e.g. `'/different/page'` * Remember to start with a slash, e.g. `'/different/page'`
*/ */
path?: string path?: string
/** /**
* Optionally specify what to filter from the output * Fallback to serving from a specified srcDir, this allows setting breakpoints on sourcecode and test the sourcemaps
*/ */
filterOutput?: TestFilterOptions; srcDir?: string|boolean;
/** /**
* A callback to manually take control of the page and simulate user interactions * A callback to manually take control of the page and simulate user interactions
*/ */
cb?: PageTestCallback cb?: PageTestCallback;
/**
* The AVA context used to test (ie t.snapshot(..) )
*/
t: any
/** /**
* Set to `true` to return index.html (200) instead of error page (404) * Set to `true` to return index.html (200) instead of error page (404)
@@ -95,8 +97,23 @@ export interface RollupServeTestOptions {
* Execute function after server has begun listening * Execute function after server has begun listening
*/ */
onListening?: (server: Server) => void onListening?: (server: Server) => void
} }
export interface RollupServeTestOptions extends ServeTestOptions{
/**
* A callback to run when a test has been run
*/
onResult?: TestResultCallback;
/**
* Callback to log messages
*/
log?: LogCallback;
}
/** /**
* Serve your rolled up bundle like webpack-dev-server * Serve your rolled up bundle like webpack-dev-server
* @param {import('..').RollupServeOptions} options * @param {import('..').RollupServeOptions} options
@@ -107,6 +124,7 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin {
port: 0, port: 0,
headers: {}, headers: {},
historyApiFallback: true, historyApiFallback: true,
srcDir: '', // Serve source dir as fallback (for sourcemaps / debugging)
onListening: function noop (){}, onListening: function noop (){},
...options||{}, ...options||{},
https: options.https??false, https: options.https??false,
@@ -116,7 +134,19 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin {
let server : Server; let server : Server;
let bundle : OutputBundle = {}; let bundle : OutputBundle = {};
const requestListener = (request: IncomingMessage, response: ServerResponse) => { const logTest = (msg: string, mode: 'info'|'warn' = 'info')=>{
if(isInDebugMode()){
console.log(msg);
}
const modeColor = {
green: 32,
info: 34,
warn: 33,
}[mode];
testOptions.log?.(`\u001b[${modeColor}m${msg}\u001b[0m`);
}
const requestListener = async (request: IncomingMessage, response: ServerResponse) => {
// Remove querystring // Remove querystring
const unsafePath = decodeURI(request.url!.split('?')[0]) const unsafePath = decodeURI(request.url!.split('?')[0])
@@ -130,22 +160,56 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin {
function urlToFilePath(url:string){ function urlToFilePath(url:string){
return url[0]==='/'?url.slice(1):url; return url[0]==='/'?url.slice(1):url;
} }
let filePath = urlToFilePath(urlPath); // Todo check if we need to strip '/' let filePath = urlToFilePath(urlPath);
let file: OutputChunk|OutputAsset; let absPath: string | undefined = undefined;
if(!bundle[filePath] && testOptions.historyApiFallback) { let stats: Stats | undefined = undefined;
const fallbackPath = typeof testOptions.historyApiFallback === 'string'
if(!bundle[filePath]){
if(testOptions.srcDir || testOptions.srcDir===''){
try{
absPath = resolve(<string>testOptions.srcDir||'',filePath);
stats = await fs.stat(absPath);
}catch(err){
// File not found
}
}
if(!(stats?.isFile()) && testOptions.historyApiFallback) {
const fallbackPath = typeof testOptions.historyApiFallback === 'string'
? testOptions.historyApiFallback ? testOptions.historyApiFallback
: '/index.html'; : '/index.html';
if(bundle[urlToFilePath(fallbackPath)]){ if(bundle[urlToFilePath(fallbackPath)]){
filePath = urlToFilePath(fallbackPath); filePath = urlToFilePath(fallbackPath);
}
} }
} }
file = bundle[filePath];
if(!file){ const mimeType = mime.getType(filePath!);
return notFound(response, filePath); if(bundle[filePath]) {
}else{ let file: OutputChunk | OutputAsset = bundle[filePath];
const content = (<OutputChunk>file).code || (<OutputAsset>file).source; // Todo might need to read a source file; const content = (<OutputChunk>file).code || (<OutputAsset>file).source; // Todo might need to read a source file;
return found(response, mime.getType(filePath!), content); response.writeHead(200, {'Content-Type': mimeType || 'text/plain'});
response.end(content, 'utf-8');
logTest(`[200] ${request.url}`);
return;
}else if(stats?.isFile()){
response.writeHead(200, {
'Content-Type': mimeType || 'text/plain',
'Content-Length': stats.size,
'Last-Modified': stats.mtime.toUTCString()
});
const content = await fs.readFile(absPath!);
response.end(content);
response.end();
logTest(`[200] ${request.url} (src)`);
}else{
response.writeHead(404)
response.end(
'404 Not Found' + '\n\n' + filePath,
'utf-8'
)
logTest(`[404] ${request.url}`, "warn");
return;
} }
} }
@@ -207,12 +271,11 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin {
if (first) { if (first) {
first = false first = false
const testOutput = await runTest({ const testOutput = await puppeteerRunTest({
page: testOptions.path!, ...testOptions
cb: testOptions.cb, }, url);
filterOutput: testOptions.filterOutput,
}, url) testOptions.onResult?.(testOutput);
testOptions.t?.snapshot?.(testOutput);
} }
} }
}, },
@@ -221,21 +284,3 @@ export default function serveTest (options: RollupServeTestOptions ): Plugin {
} }
} }
} }
function notFound (response: ServerResponse, filePath: string) {
response.writeHead(404)
response.end(
'404 Not Found' + '\n\n' + filePath,
'utf-8'
)
}
function found (response: ServerResponse, mimeType: string|null, content: any) {
response.writeHead(200, { 'Content-Type': mimeType || 'text/plain' })
response.end(content, 'utf-8')
}
function green (text: string) {
return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m'
}

View File

@@ -0,0 +1,47 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`watch 1`] = `
[
{
"code": undefined,
"fileName": "index.html",
"map": undefined,
"source": "<html><head>
</head>
<body>
<script src="watched-file.js" type="module"></script>
</body></html>",
},
{
"code": "const a = 2; // If i show up as a changed file, then the watch test has gone wrong!
export { a };
//# sourceMappingURL=watched-file.js.map
",
"fileName": "watched-file.js",
"map": SourceMap {
"file": "watched-file.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.js.map",
"map": undefined,
"source": "{"version":3,"file":"watched-file.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;;;;"}",
},
]
`;

View File

@@ -1,53 +0,0 @@
# 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: undefined,
fileName: 'index.html',
map: undefined,
source: `<html><head>␊
</head>␊
<body>␊
<script src="watched-file-8c4729c5.js" type="module"></script>␊
</body></html>`,
},
{
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;;;;"}',
},
]

Binary file not shown.

View File

@@ -1,6 +1,6 @@
import {join, dirname} from "node:path"; import {join, dirname} from "node:path";
import {test, expect} from "@jest/globals";
import test from "ava";
import * as rollup from "rollup"; import * as rollup from "rollup";
import {debugPrintOutput, getCode} from "../util/index.ts"; import {debugPrintOutput, getCode} from "../util/index.ts";
import {resolve} from "node:path"; import {resolve} from "node:path";
@@ -8,19 +8,15 @@ import {writeFile} from "node:fs/promises";
import html from "../../src/index.ts"; 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 {fileURLToPath} from "node:url";
import {pathToFileURL} from "url"; import {pathToFileURL} from "url";
import {defaultOutput} from "../util/default-output.ts";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
process.chdir(join(__dirname, 'fixtures')); process.chdir(join(__dirname, 'fixtures'));
test.serial('watch', async (t) => { test('watch', async () => {
const origContent = ` const origContent = `
export const a = 1; // DO NOT CHANGE ME HERE, but in ../test.js export const a = 1; // DO NOT CHANGE ME HERE, but in ../test.js
`; `;
@@ -31,9 +27,10 @@ test.serial('watch', async (t) => {
const path = resolve(__dirname, 'fixtures/watched-file.js'); const path = resolve(__dirname, 'fixtures/watched-file.js');
await writeFile(path, origContent, {encoding: 'utf-8'}); await writeFile(path, origContent, {encoding: 'utf-8'});
const output = defaultOutput;
const watcher = rollup.watch({ const watcher = rollup.watch({
input: 'index.html', input: 'index.html',
output, output: output,
plugins: [ plugins: [
html({ html({
}), }),
@@ -49,32 +46,33 @@ test.serial('watch', async (t) => {
// Just wait on the watch mode to pick up on the changes // Just wait on the watch mode to pick up on the changes
}, },
async (bundle)=>{ async (bundle)=>{
const code = await getCode(bundle, output); const code = await getCode(bundle);
debugPrintOutput('watch',code); debugPrintOutput('watch',code);
// Reset the source file // Reset the source file
await writeFile(path, origContent, {encoding: 'utf-8'}); await writeFile(path, origContent, {encoding: 'utf-8'});
// Assert the output is what we exapect; // Assert the output is what we exapect;
t.snapshot(code); expect(code).toMatchSnapshot();
watcher watcher
}, },
]; ];
const log = console.log;
await new Promise((resolve, reject)=>{ await new Promise((resolve, reject)=>{
watcher.on('event', async (event) => { watcher.on('event', async (event) => {
const {result} = event; const {result} = event;
switch (event.code) { switch (event.code) {
case "START": case "START":
t.log(`WATCH STARTED`); log(`WATCH STARTED`);
break; break;
case "BUNDLE_START": case "BUNDLE_START":
t.log(`REBUILDING...`); log(`REBUILDING...`);
break; break;
case "BUNDLE_END": case "BUNDLE_END":
t.log(`Rebuilt...`); log(`Rebuilt...`);
const cb = steps.shift(); const cb = steps.shift();
const generated = await result.generate(output); const generated = await result.generate(output);
@@ -94,4 +92,6 @@ test.serial('watch', async (t) => {
} }
}); });
}); });
await watcher.close();
}); });