diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bf7a80..19245e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,90 +1,2 @@ -# Remove me: -TODO: This started as a fork of, but is now something different entirely. Changelog is no longer relevant (neither is the [README.md](README.md)) -rollup-plugin-css was used in the initial tests, but it hasnt been update in **7** years. Remove this - -# @rollup/plugin-html ChangeLog - -## v1.0.2 - -_2023-01-20_ - -### Bugfixes - -- fix: types should come first in exports [#1403](https://github.com/rollup/plugins/pull/1403) - -## v1.0.1 - -_2022-10-21_ - -### Updates - -- chore: update rollup dependencies ([3038271](https://github.com/rollup/plugins/commit/303827191ede6b2e4eade96c6968ed16a587683f)) - -## v1.0.0 - -_2022-10-09_ - -### Breaking Changes - -- fix: prepare for Rollup 3 [#1294](https://github.com/rollup/plugins/pull/1294) - -### Bugfixes - -- fix: function signature of html updated [#975](https://github.com/rollup/plugins/pull/975) - -## v0.2.3 - -_2021-02-14_ - -### Bugfixes - -- fix: package.json files (#802) - -## v0.2.2 - -_2021-01-29_ - -### Updates - -- chore: run build before publish (ce65c12) -- chore: upgrade TypeScript (#713) -- refactor: refactor to typescript (#634) -- chore: update dependencies (6c8614c) - -## v0.2.1 - -_2021-01-29_ - -### Updates - -- chore: run build before publish (ce65c12) -- chore: upgrade TypeScript (#713) -- refactor: refactor to typescript (#634) -- chore: update dependencies (6c8614c) - -## v0.2.0 - -_2020-05-02_ - -### Features - -- feat: support custom meta element creation (#308) - -### Updates - -- test: update snapshots for rollup v2 (c09509f) - -## v0.1.1 - -_2020-01-04_ - -### Updates - -- docs: fix
tag (#89) -- test: change tests to serial to avoid weird snapshot conflicts (a492ce7) - -## 0.1.0 - -_2019-11-29_ - -- First Release +# 0.0.1 +Initial private release diff --git a/README.md b/README.md index 7ad3daa..4fc2035 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,41 @@ -# Work-in-progress changelog - - - - -[npm]: https://img.shields.io/npm/v/@rollup/plugin-html -[npm-url]: https://www.npmjs.com/package/@rollup/plugin-html -[size]: https://packagephobia.now.sh/badge?p=@rollup/plugin-html -[size-url]: https://packagephobia.now.sh/result?p=@rollup/plugin-html +[npm]: https://img.shields.io/npm/v/rollup-plugin-html-entry2 +[npm-url]: https://www.npmjs.com/package/rollup-plugin-html-entry2 +[size]: https://packagephobia.now.sh/badge?p=rollup-plugin-html-entry2 +[size-url]: https://packagephobia.now.sh/result?p=rollup-plugin-html-entry2 +[handlebars]: https://www.npmjs.com/package/handlebars + [![npm][npm]][npm-url] [![size][size]][size-url] [![libera manifesto](https://img.shields.io/badge/libera-manifesto-lightgrey.svg)](https://liberamanifesto.com) -# @rollup/plugin-html +# rollup-plugin-html-entry2 +| :warning: WARNING | +|:-------------------------------------------------------------------| +| **Experimental-stage** plugin. Expect bugs and missing features... | -🍣 A Rollup plugin which creates HTML files to serve Rollup bundles. -Please see [Supported Output Formats](#supported-output-formats) for information about using this plugin with output formats other than `esm` (`es`), `iife`, and `umd`. +A(nother) rollup plugin that tries to teach Rollup to start from an HTML entry, and the use of (multiple) HTML files in general. +The goal is to include assets referenced by the HTML file into the build-process as to copy/inline where appropriate and +optionally optimize them. Without having to seperatly copy them to the output directory. + +When building web-applications a HTML-file is simply the logical entry point into your application. \ +Inspired (and forked) by the original [@rollup/plugin-html](https://www.npmjs.com/package/@rollup/plugin-html), +this plugin will also allow you to transform the source files by any HTML-templating engine such as [handlebars]. + + +Please see [Supported Output Formats](#supported-output-formats) for information about using this plugin with output formats other than `esm` (`es`). ## Requirements -This plugin requires an [LTS](https://github.com/nodejs/Release) Node version (v14.0.0+) and Rollup v1.20.0+. +This plugin requires an [LTS](https://github.com/nodejs/Release) Node version (v18.0.0+) and Rollup v3.?.?+. ## Install Using npm: ```console -npm install @rollup/plugin-html --save-dev +npm install rollup-plugin-html-entry2 --save-dev ``` ## Usage @@ -35,131 +43,85 @@ npm install @rollup/plugin-html --save-dev Create a `rollup.config.js` [configuration file](https://www.rollupjs.org/guide/en/#configuration-files) and import the plugin: ```js -const html = require('@rollup/plugin-html'); +import html from 'rollup-plugin-html-entry2'; -module.exports = { - input: 'src/index.js', +export default { + input: 'src/index.html', output: { dir: 'output', - format: 'cjs' }, plugins: [html()] }; ``` +!! To use 'import x from y' syntax you might need to set `"type": "module"` in your `package.json`. +[Javascript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) are the _preferred_ way of writing modern Javascript. +Due to the early stage development of this plugin, old-style CommonJS modules are completely ignored for now. + Then call `rollup` either via the [CLI](https://www.rollupjs.org/guide/en/#command-line-reference) or the [API](https://www.rollupjs.org/guide/en/#javascript-api). -Once run successfully, an HTML file should be written to the bundle output destination. - ## Options -### `attributes` - -Type: `Object`
-Default: `{ html: { lang: 'en' }, link: null, script: null }` - -Specifies additional attributes for `html`, `link`, and `script` elements. For each property, provide an object with key-value pairs that represent an HTML element attribute name and value. By default, the `html` element is rendered with an attribute of `lang="en"`. - -_Note: If using the `es` / `esm` output format, `{ type: 'module'}` is automatically added to `attributes.script`._ - -### `fileName` - -Type: `String`
-Default: `'index.html'` - -### `meta` - -Type: `Array[...object]`
-Default: `[{ charset: 'utf-8' }]` - -Specifies attributes used to create `` elements. For each array item, provide an object with key-value pairs that represent `` element attribute names and values. - -Specifies the name of the HTML to emit. - -### `publicPath` - -Type: `String`
-Default: `''` - -Specifies a path to prepend to all bundle assets (files) in the HTML output. - ### `template` Type: `Function`
-Default: `internal function` +Default: `undefined`\ Returns: `String` -Specifies a function that provides the rendered source for the HTML output. The function should be in the form of: +Specifies a transform to be applied before parsing the HTML, this allows you to transform the sourcefile with a templating engine such as [handlebars] first. -```js -const template = ({ attributes, bundle, files, publicPath, title }) => { ... } -``` +```javascript +import {rollup} from "rollup"; +import handlebars from "handlebars"; +import html from "rollup-plugin-html-entry2"; -- `attributes`: Corresponds to the `attributes` option passed to the plugin -- `bundle`: An `Object` containing key-value pairs of [`AssetInfo` or `ChunkInfo`](https://rollupjs.org/guide/en/#generatebundle) -- `files`: An `Array` of `AssetInfo` or `ChunkInfo` containing any entry (`isEntry: true`) files, and any asset (`isAsset: true`) files in the bundle that will be emitted -- `publicPath`: Corresponds to the `publicPath` option passed to the plugin -- `title`: Corresponds to the `title` option passed to the plugin - -By default this is handled internally and produces HTML in the following format: - -```html - - - - ${metas} - ${title} - ${links} - - - ${scripts} - - -``` - -Where `${links}` represents all ` -Default: `'Rollup Bundle'` - -Specifies the HTML document title. - -## Exports - -### `makeHtmlAttributes(attributes)` - -Parameters: `attributes`, Type: `Object`
-Returns: `String` - -Consumes an object with key-value pairs that represent an HTML element attribute name and value. The function returns all pairs as a space-separated string of valid HTML element attributes. e.g. - -```js -const { makeHtmlAttributes } = require('@rollup/plugin-html'); - -makeHtmlAttributes({ lang: 'en', 'data-batcave': 'secret' }); -// -> 'lang="en" data-batcave="secret"' +async function build() { + await rollup({ + input: 'index.hbs', + plugins: [ + html({ + transform(src) { + return handlebars.compile(src)({a: 'a'}) + } + }) + ] + }); +} ``` ## Supported Output Formats -By default, this plugin supports the `esm` (`es`), `iife`, and `umd` [output formats](https://rollupjs.org/guide/en/#outputformat), as those are most commonly used as browser bundles. Other formats can be used, but will require using the [`template`](#template) option to specify a custom template function which renders the unique requirements of other formats. +By default, this plugin supports the `esm` (`es`). Any other format is currently untested as this plugin is in an early state, see [#status](#status) -### `amd` +## Status -Will likely require use of RequireJS semantics, which allows only for a single entry ``. -## Attribution +### Not (yet) supported +- Inline scripts (i.e ``) +- Plugins importing CSS files +- CommonJS (cjs) and IIFI output formats. (Is UMD actually ever used?) +- Overriding which tags to ignore/include +- Other (various) plugins such as those for HMR etc +- ... -This plugin was inspired by and is based upon [mini-html-webpack-plugin](https://github.com/styleguidist/mini-html-webpack-plugin) by Juho VepsÀlÀinen and Artem Sapegin, with permission. +# Contibuting -## Meta +You can be helpful by testing, proving helpful feedback, expanding the documentation, responding to issues/questions being reported, resolving the many ToDo`s in the code, implementating features...\ +[Get in touch](mailto:rollup-plugin-html-entry2@cerxes.net) or just dive into [the code](https://git.cerxes.net/rollup-apps/plugin-html) or [issues](https://git.cerxes.net/rollup-apps/plugin-html/issues) -[CONTRIBUTING](/.github/CONTRIBUTING.md) - -[LICENSE (MIT)](/LICENSE) +# Notes +## git.cerxes.net +Once publicly released, the intent is to move the GIT-repository to github. Until that day though, it exists privately on this gitea server and corresponding npm-registry [npm.cerxes.net](https://npm.cerxes.net).\ +TODO: change the links once this happens +## Prior work + - [Vite](https://vitejs.dev) seems to have already [done work])(https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/html.ts) to handle HTML in rollup. + - [rollup-plugin-html-entry](https://www.npmjs.com/package/rollup-plugin-html-entry) seems to be **dead**. Last version from 2020, there have been many changes to rollup`s plugin capabilities since then + - [@rollup/plugin-html](https://www.npmjs.com/package/@rollup/plugin-html) is where this project was originally forked from. Its main focus was to generate an HTML to serve the resulting bundle. Which is different from supporting HTML as entry point since it did not resolve assets used in the HTML. Besides the project setup, not much of the original has been kept... + - [@web/rollup-plugin-html](https://www.npmjs.com/package/@web/rollup-plugin-html) a plugin with similar intentions as this one (in active development anno 2023). diff --git a/package.json b/package.json index 82c93f7..f6c9247 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { - "name": "@rollup-apps/plugin-html", + "name": "rollup-plugin-html-entry2", "version": "0.0.1", - "description": "Creates HTML files to serve Rollup bundles", + "description": "Teaches rollup how to deal with HTML, allows to use HTML-files as entry-points.", "license": "MIT", "repository": { - "url": "rollup/plugins", - "directory": "packages/html" + "type": "git", + "url": "https://git.cerxes.net/rollup-apps/plugin-html.git" }, - "author": "Andrew Powell ", - "homepage": "https://github.com/rollup/plugins/tree/master/packages/html#readme", - "bugs": "https://github.com/rollup/plugins/issues", + "author": "Miel Truyen ", + "homepage": "https://git.cerxes.net/rollup-apps/plugin-html", + "bugs": "https://git.cerxes.net/rollup-apps/plugin-html/issues", "type": "module", "engines": { "node": ">=18" @@ -27,11 +27,11 @@ "scripts": { "build": "rollup -c", "prerelease": "pnpm build", - "test": "ava", "ci:coverage": "nyc pnpm test && nyc report --reporter=text-lcov > coverage.lcov", "ci:lint": "pnpm build && pnpm lint-staged", "ci:test": "pnpm test -- --verbose", - "dev-test": "ava --match='handlebars*' --update-snapshots" + "run-test": "ava", + "save-test": "ava --update-snapshots" }, "files": [ "dist", @@ -77,7 +77,10 @@ "@babel/preset-typescript": "^7.21.4", "nyc": "^15.1.0", "lint-staged": "^13.2.1", - "handlebars": "^4.7.7" + "handlebars": "^4.7.7", + "@rollup/plugin-url": "^8.0.1", + "chalk": "^5.2.0", + "rollup-plugin-livereload": "^2.0.5" }, "types": "./types/index.d.ts", "ava": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 16e0d24..24b5f54 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,12 +27,18 @@ devDependencies: '@rollup/plugin-typescript': specifier: ^11.1.0 version: 11.1.0(rollup@3.20.3)(tslib@2.5.0)(typescript@5.0.4) + '@rollup/plugin-url': + specifier: ^8.0.1 + version: 8.0.1(rollup@3.20.3) '@types/node': specifier: ^18.15.11 version: 18.15.11 ava: specifier: ^5.2.0 version: 5.2.0 + chalk: + specifier: ^5.2.0 + version: 5.2.0 del-cli: specifier: ^5.0.0 version: 5.0.0 @@ -54,6 +60,9 @@ devDependencies: rollup-plugin-delete: specifier: ^2.0.0 version: 2.0.0 + rollup-plugin-livereload: + specifier: ^2.0.5 + version: 2.0.5 rollup-plugin-postcss: specifier: ^4.0.2 version: 4.0.2(postcss@8.4.22)(ts-node@10.9.1) @@ -560,6 +569,21 @@ packages: typescript: 5.0.4 dev: true + /@rollup/plugin-url@8.0.1(rollup@3.20.3): + resolution: {integrity: sha512-8ajztphXb5e19dk3Iwjtm2eSYJR8jFQubZ8pJ1GG2MBMM7/qUedLnZAN+Vt4jqbcT/m27jfjIBocvrzV0giNRw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.0.2(rollup@3.20.3) + make-dir: 3.1.0 + mime: 3.0.0 + rollup: 3.20.3 + dev: true + /@rollup/pluginutils@5.0.2(rollup@3.20.3): resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} engines: {node: '>=14.0.0'} @@ -2023,6 +2047,24 @@ packages: wrap-ansi: 7.0.0 dev: true + /livereload-js@3.4.1: + resolution: {integrity: sha512-5MP0uUeVCec89ZbNOT/i97Mc+q3SxXmiUGhRFOTmhrGPn//uWVQdCvcLJDy64MSBR5MidFdOR7B9viumoavy6g==} + dev: true + + /livereload@0.9.3: + resolution: {integrity: sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==} + engines: {node: '>=8.0.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + livereload-js: 3.4.1 + opts: 2.0.2 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: true + /load-json-file@7.0.1: resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2186,6 +2228,12 @@ packages: picomatch: 2.3.1 dev: true + /mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + dev: true + /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -2347,6 +2395,10 @@ packages: mimic-fn: 4.0.0 dev: true + /opts@2.0.2: + resolution: {integrity: sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==} + dev: true + /p-defer@1.0.0: resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} engines: {node: '>=4'} @@ -3066,6 +3118,16 @@ packages: del: 5.1.0 dev: true + /rollup-plugin-livereload@2.0.5: + resolution: {integrity: sha512-vqQZ/UQowTW7VoiKEM5ouNW90wE5/GZLfdWuR0ELxyKOJUIaj+uismPZZaICU4DnWPVjnpCDDxEqwU7pcKY/PA==} + engines: {node: '>=8.3'} + dependencies: + livereload: 0.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: true + /rollup-plugin-postcss@4.0.2(postcss@8.4.22)(ts-node@10.9.1): resolution: {integrity: sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w==} engines: {node: '>=10'} @@ -3577,6 +3639,19 @@ packages: signal-exit: 3.0.7 dev: true + /ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} dev: true diff --git a/rollup.config.mjs b/rollup.config.mjs index 4da599d..634d11c 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -30,13 +30,14 @@ export function createConfig({ pkg, external = [] }) { }, strictDeprecations: true, output: [ - { - format: 'cjs', - file: pkg.main, - exports: 'named', - footer: 'module.exports = Object.assign(exports.default, exports);', - sourcemap: true - }, + // TODO: cjs output not supported for now + // { + // format: 'cjs', + // file: pkg.main, + // exports: 'named', + // footer: 'module.exports = Object.assign(exports.default, exports);', + // sourcemap: true + // }, { format: 'es', file: pkg.module, @@ -57,7 +58,6 @@ export function createConfig({ pkg, external = [] }) { ...commonOpts, babelHelpers: "bundled", }), - // typescript({ sourceMap: true })] ] }; } diff --git a/src/index.ts b/src/index.ts index 1586014..2be9aa1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,7 @@ import type { } from '../types/index.d.ts'; import {createFilter} from '@rollup/pluginutils'; import {parse as parseHtml, serialize as serializeHtml, DefaultTreeAdapterMap} from "parse5"; -// import {Script, SourceTextModule, createContext} from "node:vm"; +import {readFile} from "node:fs/promises" const getFiles = (bundle: OutputBundle): Record => { const result = {} as ReturnType; @@ -80,20 +80,26 @@ const defaults: RollupHtmlOptions = { // Internal type type HtmlImport = { - id: string, - rollupResolved: ResolvedId|null, - node: DefaultTreeAdapterMap['element'], - reference: LoadReference, - referenceId: string|null, - index: number, + id: string; + rollupResolved: ResolvedId|null; + node: DefaultTreeAdapterMap['element']; + reference: LoadReference; + referenceId: string|null; + index: number; } type HtmlModule = { // TODO might want to impose an own unique id, in case this changes after multiple builds - id: string, + id: string; + name: string; + importers: Set, resolved: HtmlImport[]; - document: DefaultTreeAdapterMap['document'], + assetId?: string|null; + document?: DefaultTreeAdapterMap['document']; } +const modulePrefix = `// `; +const moduleSuffix = `// `; + export default function html(opts: RollupHtmlOptions = {}): Plugin { const { publicPath, @@ -111,22 +117,167 @@ export default function html(opts: RollupHtmlOptions = {}): Plugin { if(publicPath){ throw new Error("TODO, do something with the public path or throw it out of the options. this is just to stop typescript complaining")} let filter = createFilter(include, exclude, {}); - let handledHtmls = new Map();// todo clean this per new build? + let htmlModules = new Map();// todo clean this per new build? return { name: 'html2',// TODO: Need a better name, original plugin was just named `html` and might still make sense to use in conjunction with this one + resolveId: { + async handler(specifier: string, + importer: string | undefined, + options: { assertions: Record }){ + if(!filter(specifier)) return; + + // Let it be resolved like others (node_modules, project aliases, ..) + const resolved = await this.resolve(specifier, importer, { + skipSelf: true, + ...options, + }); + + if(resolved){ + const moduleId = resolved.id; + const moduleExt = extname(resolved.id); + const moduleName = specifier.replace(new RegExp(`${moduleExt}\$`),''); // strip extension of the name if any + const htmlModule : HtmlModule = htmlModules.get(moduleId) ?? { + id: resolved.id, + name: moduleName, + resolved: [], + assetId: null, + importers: new Set(), + }; + htmlModule.importers.add(importer); + + htmlModules.set(htmlModule.id, htmlModule); + // TODO: trigger special handling when imported from a JS file (in which case we want might want to export a module returning the HTML, instead of HTML directly) + } + } + }, load: { async handler(id: string) { if(!filter(id)) return; - // We'll be transforming this, but it appears there is no need for us to load it. Rollup will do this + + // Load + const htmlModule = htmlModules.get(id); + if(htmlModule) { + const contents = await readFile(id, {encoding: "utf-8"}); + + const htmlSrc = transform ? await transform(contents, { + id, + }) : contents; + + // Parse document and store it (TODO: check for watch mode, we should check if it needs reparsing or not) + const document = htmlModule.document ?? parseHtml(htmlSrc); + if(!htmlModule.document){ + htmlModule.document = document; + } + + // Figure out which references to load from this HTML by iterating all nodes (looking for src or href attributes) + let loadResults: { reference: LoadReference, node: DefaultTreeAdapterMap['element'] }[] = []; + if (document.childNodes) { + let nodeQueue = document.childNodes; + do { + const nextQueue: DefaultTreeAdapterMap['childNode'][][] = []; + await Promise.all(nodeQueue.map(async (node) => { + const el = (node); + let toLoad: LoadResult | undefined = undefined; + if (el.attrs) { + toLoad = load ? await load({ + node: el, + sourceId: id + }) : []; + } + + if (toLoad) { + const loadIds: LoadReference[] = (toLoad instanceof Array) ? toLoad : [toLoad]; + for (const loadId of loadIds) { + loadResults.push({ + reference: loadId, + node: el, + }) + } + } + + if (toLoad !== false) { + let asParent = (node); + if (asParent.childNodes) { + nextQueue.push(asParent.childNodes); + } + } + })); + nodeQueue = nextQueue.flat(); + } while (nodeQueue.length > 0); + } + + // Figure out what to resolve (todo, an id can actually be loaded in multiple times, something we might want to keep in mind) + await Promise.all(loadResults.map(async ({reference, node}, index) => { + const refId = reference.get(); + const selfResolvedId = resolve ? resolve(refId, { + sourceId: id, + node, + }) : refId; + const resolvedId: string = selfResolvedId === true ? refId : (selfResolvedId); + if (resolvedId) { + const isEntry = !!/.*\.(js|jsx|ts|tsx)$/i.exec(resolvedId); // TODO: for scripts (via src-tag, not those inlined) entry=true. But it should not check via the id (rather how it is imported from html) + const rollupResolved = await this.resolve(resolvedId, id, { + skipSelf: true, + isEntry: isEntry, + }); + + // TODO: should we test/check if this is refused for resolving here. i.e. external? + const htmlImport: HtmlImport = { + id: resolvedId, + rollupResolved, + node, + reference, + referenceId: + // This was triggering resources being marked as entry, and thus their injected loader modules to be outputed to their own files (ie icon.js to load icon.svg) + // Should be able to resolve the final HTML from the exported module instead (which though would ideally mean interpreting it as a browser would... ) + // TODO: however, probably need to uncomment this for + + diff --git a/test/basic/fixtures/joker.js b/test/basic/fixtures/joker.js deleted file mode 100644 index deb774e..0000000 --- a/test/basic/fixtures/joker.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line -import style from './joker.css'; diff --git a/test/basic/fixtures/robin.js b/test/basic/fixtures/robin.js deleted file mode 100644 index d101643..0000000 --- a/test/basic/fixtures/robin.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line -import * as batman from './batman.js'; diff --git a/test/basic/snapshots/test.js.md b/test/basic/snapshots/test.js.md index 7694ad9..19e1b38 100644 --- a/test/basic/snapshots/test.js.md +++ b/test/basic/snapshots/test.js.md @@ -1,357 +1,58 @@ -# Snapshot report for `test/test.js` +# Snapshot report for `test/basic/test.js` The actual snapshot is saved in `test.js.snap`. Generated by [AVA](https://avajs.dev). -## default options +## simple > Snapshot 1 [ { - code: `(function (factory) {␊ - typeof define === 'function' && define.amd ? define(factory) :␊ - factory();␊ - })((function () { 'use strict';␊ + code: `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-9dbe0e1d.js.map␊ `, - fileName: 'batman.js', - map: null, + fileName: 'batman-9dbe0e1d.js', + map: SourceMap { + file: 'batman-9dbe0e1d.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-9dbe0e1d.js.map', + map: undefined, + source: '{"version":3,"file":"batman-9dbe0e1d.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: `␊ - ␊ - ␊ - ␊ - ␊ - Rollup Bundle␊ + source: `␊ + ␊ + ␊ + ␊ ␊ - ␊ - ␊ - ␊ - ␊ - `, - }, - ] - -## options - -> Snapshot 1 - - [ - { - code: `(function (factory) {␊ - typeof define === 'function' && define.amd ? define(factory) :␊ - factory();␊ - })((function () { 'use strict';␊ - ␊ - ␊ - ␊ - }));␊ - `, - fileName: 'batman.js', - map: null, - source: undefined, - }, - { - code: undefined, - fileName: 'batman.html', - map: undefined, - source: `␊ - ␊ - ␊ - ␊ - ␊ - ␊ - Batcave␊ - ␊ - ␊ - ␊ - ␊ - ␊ - `, - }, - ] - -## iife - -> Snapshot 1 - - [ - { - code: `(function () {␊ - 'use strict';␊ - ␊ - ␊ - ␊ - })();␊ - `, - fileName: 'batman.js', - map: null, - source: undefined, - }, - { - code: undefined, - fileName: 'index.html', - map: undefined, - source: `␊ - ␊ - ␊ - ␊ - ␊ - Rollup Bundle␊ - ␊ - ␊ - ␊ - ␊ - ␊ - `, - }, - ] - -## esm - -> Snapshot 1 - - [ - { - code: `␊ - `, - fileName: 'batman.js', - map: null, - source: undefined, - }, - { - code: undefined, - fileName: 'index.html', - map: undefined, - source: `␊ - ␊ - ␊ - ␊ - ␊ - Rollup Bundle␊ - ␊ - ␊ - ␊ - ␊ - ␊ - `, - }, - ] - -## unsupported output format - -> Snapshot 1 - - [ - { - code: `'use strict';␊ - ␊ - `, - fileName: 'batman.js', - map: null, - source: undefined, - }, - { - code: undefined, - fileName: 'index.html', - map: undefined, - source: `␊ - ␊ - ␊ - ␊ - ␊ - Rollup Bundle␊ - ␊ - ␊ - ␊ - ␊ - ␊ - `, - }, - ] - -> Snapshot 2 - - [ - { - code: 'EMPTY_BUNDLE', - message: 'Generated an empty chunk: "batman".', - names: [ - 'batman', - ], - toString: Function {}, - }, - { - code: 'PLUGIN_WARNING', - message: 'plugin-html: The output format \'cjs\' is not directly supported. A custom `template` is probably required. Supported formats include: es, esm, iife, umd', - plugin: 'html', - toString: Function {}, - }, - ] - -## css - -> Snapshot 1 - - [ - { - code: `(function (factory) {␊ - typeof define === 'function' && define.amd ? define(factory) :␊ - factory();␊ - })((function () { 'use strict';␊ - ␊ - ␊ - ␊ - }));␊ - `, - fileName: 'joker.js', - map: null, - source: undefined, - }, - { - code: undefined, - fileName: 'joker.css', - map: undefined, - source: Buffer @Uint8Array [ - 2a207b20 77696474 683a2031 3030253b 207d0a - ], - }, - { - code: undefined, - fileName: 'index.html', - map: undefined, - source: `␊ - ␊ - ␊ - ␊ - ␊ - Rollup Bundle␊ - ␊ - ␊ - ␊ - ␊ - ␊ - `, - }, - ] - -## attributes - -> Snapshot 1 - - [ - { - code: `(function (factory) {␊ - typeof define === 'function' && define.amd ? define(factory) :␊ - factory();␊ - })((function () { 'use strict';␊ - ␊ - ␊ - ␊ - }));␊ - `, - fileName: 'joker.js', - map: null, - source: undefined, - }, - { - code: undefined, - fileName: 'joker.css', - map: undefined, - source: Buffer @Uint8Array [ - 2a207b20 77696474 683a2031 3030253b 207d0a - ], - }, - { - code: undefined, - fileName: 'index.html', - map: undefined, - source: `␊ - ␊ - ␊ - ␊ - ␊ - Rollup Bundle␊ - ␊ - ␊ - ␊ - ␊ - ␊ - `, - }, - ] - -## imports - -> Snapshot 1 - - [ - { - code: `(function (factory) {␊ - typeof define === 'function' && define.amd ? define(factory) :␊ - factory();␊ - })((function () { 'use strict';␊ - ␊ - ␊ - ␊ - }));␊ - `, - fileName: 'robin.js', - map: null, - source: undefined, - }, - { - code: undefined, - fileName: 'index.html', - map: undefined, - source: `␊ - ␊ - ␊ - ␊ - ␊ - Rollup Bundle␊ - ␊ - ␊ - ␊ - ␊ - ␊ - `, - }, - ] - -## template - -> Snapshot 1 - - [ - { - code: `(function (factory) {␊ - typeof define === 'function' && define.amd ? define(factory) :␊ - factory();␊ - })((function () { 'use strict';␊ - ␊ - ␊ - ␊ - }));␊ - `, - fileName: 'batman.js', - map: null, - source: undefined, - }, - { - code: undefined, - fileName: 'index.html', - map: undefined, - source: '
', + ␊ + `, }, ] diff --git a/test/basic/snapshots/test.js.snap b/test/basic/snapshots/test.js.snap index 1fdf4d3..e3c19c5 100644 Binary files a/test/basic/snapshots/test.js.snap and b/test/basic/snapshots/test.js.snap differ diff --git a/test/basic/test.js b/test/basic/test.js index bf085aa..5609aee 100644 --- a/test/basic/test.js +++ b/test/basic/test.js @@ -2,123 +2,36 @@ import {join, dirname} from "node:path"; import test from "ava"; import { rollup } from "rollup"; -import css from "rollup-plugin-postcss"; - -import { getCode } from "../util/test.js"; +import {debugPrintOutput, getCode} from "../util/test.js"; import html from "../../src/index.ts"; -// const read = (file = 'index.html') => readFileSync(join('output/', file), 'utf-8'); - -const output = { dir: 'output', format: 'umd' }; +const output = { + dir: 'output', // Output all files + format: 'es', // iifi and cjs should be added to tests + sourcemap: true,// Test if #sourcemapUrl is not accidentally included in the html-output +}; import {fileURLToPath} from "node:url"; const __dirname = dirname(fileURLToPath(import.meta.url)); process.chdir(join(__dirname, 'fixtures')); -test.serial('default options', async (t) => { - const bundle = await rollup({ - input: 'batman.js', - plugins: [html()] - }); - const code = await getCode(bundle, output, true); - t.snapshot(code); -}); -test.serial('options', async (t) => { +test.serial('simple', async (t) => { const bundle = await rollup({ - input: 'batman.js', + input: 'index.html', plugins: [ html({ - fileName: 'batman.html', - publicPath: 'batcave/', - title: 'Batcave', - meta: [ - { charset: 'utf-8' }, - { name: 'viewport', content: 'minimum-scale=1, initial-scale=1, width=device-width' } - ] - }) + }), ] }); const code = await getCode(bundle, output, true); + debugPrintOutput('simple',code); t.snapshot(code); }); -test.serial('iife', async (t) => { - const bundle = await rollup({ - input: 'batman.js', - plugins: [html()] - }); - const code = await getCode(bundle, { dir: 'output', format: 'iife' }, true); - t.snapshot(code); -}); - -test.serial('esm', async (t) => { - const bundle = await rollup({ - input: 'batman.js', - plugins: [html()] - }); - const code = await getCode(bundle, { dir: 'output', format: 'es' }, true); - t.snapshot(code); -}); - -test.serial('unsupported output format', async (t) => { - const warnings = []; - const bundle = await rollup({ - input: 'batman.js', - onwarn: (warning) => warnings.push(warning), - plugins: [html()] - }); - const code = await getCode(bundle, { dir: 'output', format: 'cjs' }, true); - t.snapshot(code); - t.snapshot(warnings); -}); - -test.serial('css', async (t) => { - const bundle = await rollup({ - input: 'joker.js', - plugins: [css({ extract: true }), html()] - }); - const code = await getCode(bundle, output, true); - t.snapshot(code); -}); - -test.serial('attributes', async (t) => { - const bundle = await rollup({ - input: 'joker.js', - plugins: [ - css({ extract: true }), - html({ - attributes: { - html: { batsignal: 'on', lang: 'bat' }, - link: { 'data-vilian': 'joker' }, - script: { defer: true } - } - }) - ] - }); - const code = await getCode(bundle, output, true); - t.snapshot(code); -}); - -test.serial('imports', async (t) => { - const bundle = await rollup({ - input: 'robin.js', - plugins: [html()] - }); - const code = await getCode(bundle, output, true); - t.snapshot(code); -}); - -test.serial('template', async (t) => { - const bundle = await rollup({ - input: 'batman.js', - plugins: [ - html({ - transform: () => '
' - }) - ] - }); - const code = await getCode(bundle, output, true); - t.snapshot(code); -}); +// TODO various parameters +// - format: cjs, iifi, ... +// - sourcemap: inline, false, (and the various exotic sourcemap options) +// Watch mode tests would be its own dir +// ... diff --git a/test/hbs/fixtures/batman.js b/test/hbs/fixtures/batman.js deleted file mode 100644 index 15c5e86..0000000 --- a/test/hbs/fixtures/batman.js +++ /dev/null @@ -1,4 +0,0 @@ -export const notSoIifi = ()=>{ - return `I'm "annoying" ${"in case we need to test \`string\` escaping.''"}`; -} -console.log(notSoIifi()); diff --git a/test/hbs/snapshots/test.js.md b/test/hbs/snapshots/test.js.md deleted file mode 100644 index 3344211..0000000 --- a/test/hbs/snapshots/test.js.md +++ /dev/null @@ -1,74 +0,0 @@ -# Snapshot report for `test/hbs/test.js` - -The actual snapshot is saved in `test.js.snap`. - -Generated by [AVA](https://avajs.dev). - -## handlebars - -> Snapshot 1 - - [ - { - code: `␊ - ␊ - ␊ - ␊ - ␊ - ␊ - ␊ - ␊ - //# sourceMappingURL=index.html.map␊ - `, - fileName: 'index.html', - map: SourceMap { - file: 'index.html', - mappings: '', - names: [], - sources: [], - sourcesContent: [], - version: 3, - }, - source: undefined, - }, - { - code: `const notSoIifi = ()=>{␊ - return \`I'm "annoying" ${"in case we need to test \\\`string\\\` escaping.''"}\`;␊ - };␊ - console.log(notSoIifi());␊ - ␊ - export { notSoIifi };␊ - //# sourceMappingURL=batman-f8ac73ff.js.map␊ - `, - fileName: 'batman-f8ac73ff.js', - map: SourceMap { - file: 'batman-f8ac73ff.js', - mappings: 'AAAY,MAAC,SAAS,GAAG,IAAI;AAC7B,IAAI,OAAO,CAAC,eAAe,EAAE,gDAAgD,CAAC,CAAC,CAAC;AAChF,EAAC;AACD,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;;;;', - names: [], - sources: [ - '../batman.js', - ], - sourcesContent: [ - `export const notSoIifi = ()=>{␊ - return \`I'm "annoying" ${"in case we need to test \\\`string\\\` escaping.''"}\`;␊ - }␊ - console.log(notSoIifi());␊ - `, - ], - version: 3, - }, - source: undefined, - }, - { - code: undefined, - fileName: 'batman-f8ac73ff.js.map', - map: undefined, - source: '{"version":3,"file":"batman-f8ac73ff.js","sources":["../batman.js"],"sourcesContent":["export const notSoIifi = ()=>{\\n return `I\'m \\"annoying\\" ${\\"in case we need to test \\\\`string\\\\` escaping.\'\'\\"}`;\\n}\\nconsole.log(notSoIifi());\\n"],"names":[],"mappings":"AAAY,MAAC,SAAS,GAAG,IAAI;AAC7B,IAAI,OAAO,CAAC,eAAe,EAAE,gDAAgD,CAAC,CAAC,CAAC;AAChF,EAAC;AACD,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;;;;"}', - }, - { - code: undefined, - fileName: 'index.html.map', - map: undefined, - source: '{"version":3,"file":"index.html","sources":[],"sourcesContent":[],"names":[],"mappings":""}', - }, - ] diff --git a/test/hbs/snapshots/test.js.snap b/test/hbs/snapshots/test.js.snap deleted file mode 100644 index 342d38e..0000000 Binary files a/test/hbs/snapshots/test.js.snap and /dev/null differ diff --git a/test/live-reload/fixtures/batman.js b/test/live-reload/fixtures/batman.js new file mode 100644 index 0000000..ee16ff1 --- /dev/null +++ b/test/live-reload/fixtures/batman.js @@ -0,0 +1,4 @@ +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()); diff --git a/test/live-reload/fixtures/index.html b/test/live-reload/fixtures/index.html new file mode 100644 index 0000000..79a7a8e --- /dev/null +++ b/test/live-reload/fixtures/index.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/live-reload/snapshots/test.js.md b/test/live-reload/snapshots/test.js.md new file mode 100644 index 0000000..58396a0 --- /dev/null +++ b/test/live-reload/snapshots/test.js.md @@ -0,0 +1,60 @@ +# 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: `␊ + ␊ + ␊ + ␊ + ␊ + ␊ + `, + }, + ] diff --git a/test/live-reload/snapshots/test.js.snap b/test/live-reload/snapshots/test.js.snap new file mode 100644 index 0000000..1ef818f Binary files /dev/null and b/test/live-reload/snapshots/test.js.snap differ diff --git a/test/live-reload/test.js b/test/live-reload/test.js new file mode 100644 index 0000000..4842cca --- /dev/null +++ b/test/live-reload/test.js @@ -0,0 +1,42 @@ +import {join, dirname} from "node:path"; + +import test from "ava"; +import {rollup} from "rollup"; +import liveReload from "rollup-plugin-livereload"; +import {debugPrintOutput, getCode} from "../util/test.js"; + +import html from "../../src/index.ts"; + +const output = { + dir: 'output', // Output all files + format: 'es', // iifi and cjs should be added to tests + sourcemap: true,// Test if #sourcemapUrl is not accidentally included in the html-output +}; + +import {fileURLToPath} from "node:url"; +const __dirname = dirname(fileURLToPath(import.meta.url)); +process.chdir(join(__dirname, 'fixtures')); + + +test.serial('live-reload', async (t) => { + const bundle = await rollup({ + input: 'index.html', + plugins: [ + html({ + }), + liveReload({ + verbose: false// this oddly enough prevents it from actually starting the liveserver, which would've left the test to wait indefinatly to close + }) + ] + }); + const code = await getCode(bundle, output, true); + await bundle.close();// Make sure live-reload closes itself + debugPrintOutput('live-reload',code); + t.snapshot(code); +}); + +// TODO various parameters +// - format: cjs, iifi, ... +// - sourcemap: inline, false, (and the various exotic sourcemap options) +// Watch mode tests would be its own dir +// ... diff --git a/test/templating/fixtures/batman.js b/test/templating/fixtures/batman.js new file mode 100644 index 0000000..413d5d3 --- /dev/null +++ b/test/templating/fixtures/batman.js @@ -0,0 +1,2 @@ +export const b = ()=>'batman'; +console.log(b()); diff --git a/test/templating/fixtures/icon.svg b/test/templating/fixtures/icon.svg new file mode 100644 index 0000000..bd53f96 --- /dev/null +++ b/test/templating/fixtures/icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/test/hbs/fixtures/index.hbs b/test/templating/fixtures/index.hbs similarity index 100% rename from test/hbs/fixtures/index.hbs rename to test/templating/fixtures/index.hbs diff --git a/test/templating/fixtures/index.html b/test/templating/fixtures/index.html new file mode 100644 index 0000000..7d3f5dd --- /dev/null +++ b/test/templating/fixtures/index.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/basic/fixtures/joker.css b/test/templating/fixtures/joker.css similarity index 100% rename from test/basic/fixtures/joker.css rename to test/templating/fixtures/joker.css diff --git a/test/templating/snapshots/test.js.md b/test/templating/snapshots/test.js.md new file mode 100644 index 0000000..8c8a7f9 --- /dev/null +++ b/test/templating/snapshots/test.js.md @@ -0,0 +1,55 @@ +# 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: `␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + `, + }, + ] diff --git a/test/templating/snapshots/test.js.snap b/test/templating/snapshots/test.js.snap new file mode 100644 index 0000000..107f938 Binary files /dev/null and b/test/templating/snapshots/test.js.snap differ diff --git a/test/hbs/test.js b/test/templating/test.js similarity index 68% rename from test/hbs/test.js rename to test/templating/test.js index 553e862..243b1b7 100644 --- a/test/hbs/test.js +++ b/test/templating/test.js @@ -3,7 +3,7 @@ import {join, dirname} from "node:path"; import test from "ava"; import { rollup } from "rollup"; -import { getCode } from "../util/test.js"; +import {debugPrintOutput, getCode} from "../util/test.js"; import html from "../../src/index.ts"; import handlebars from "handlebars"; @@ -14,24 +14,30 @@ const output = { sourcemap: true,// Test if #sourcemapUrl is not accidentally included in the html-output }; -import {readFile} from "node:fs/promises"; import {fileURLToPath} from "node:url"; const __dirname = dirname(fileURLToPath(import.meta.url)); process.chdir(join(__dirname, 'fixtures')); + test.serial('handlebars', async (t) => { - const template = await readFile('index.hbs', {encoding: "utf-8"}); const bundle = await rollup({ input: 'index.hbs', plugins: [ html({ - // Should we define an output template here?! - transform(ctx){ - return handlebars.compile(template)({a:'a'}) + transform(src){ + return handlebars.compile(src)({a:'a'}) } }) ] }); const code = await getCode(bundle, output, true); + debugPrintOutput('handlebars',code); t.snapshot(code); }); + + +// TODO various parameters +// - format: cjs, iifi, ... +// - sourcemap: inline, false, (and the various exotic sourcemap options) +// Watch mode tests would be its own dir +// ... diff --git a/test/url-plugin/fixtures/batman.js b/test/url-plugin/fixtures/batman.js new file mode 100644 index 0000000..413d5d3 --- /dev/null +++ b/test/url-plugin/fixtures/batman.js @@ -0,0 +1,2 @@ +export const b = ()=>'batman'; +console.log(b()); diff --git a/test/url-plugin/fixtures/icon.svg b/test/url-plugin/fixtures/icon.svg new file mode 100644 index 0000000..bd53f96 --- /dev/null +++ b/test/url-plugin/fixtures/icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/test/url-plugin/fixtures/index.html b/test/url-plugin/fixtures/index.html new file mode 100644 index 0000000..7d3f5dd --- /dev/null +++ b/test/url-plugin/fixtures/index.html @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/url-plugin/snapshots/test.js.md b/test/url-plugin/snapshots/test.js.md new file mode 100644 index 0000000..3a39828 --- /dev/null +++ b/test/url-plugin/snapshots/test.js.md @@ -0,0 +1,105 @@ +# 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: `␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + `, + }, + ] + +## 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: `␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + `, + }, + ] diff --git a/test/url-plugin/snapshots/test.js.snap b/test/url-plugin/snapshots/test.js.snap new file mode 100644 index 0000000..679d822 Binary files /dev/null and b/test/url-plugin/snapshots/test.js.snap differ diff --git a/test/url-plugin/test.js b/test/url-plugin/test.js new file mode 100644 index 0000000..dbdd35d --- /dev/null +++ b/test/url-plugin/test.js @@ -0,0 +1,67 @@ +import {join, dirname} from "node:path"; + +import test from "ava"; +import { rollup } from "rollup"; +import urlPlugin from "@rollup/plugin-url"; + +import {debugPrintOutput, getCode} from "../util/test.js"; + +import html from "../../src/index.ts"; + +const output = { + dir: 'output', // Output all files + format: 'es', // iifi and cjs should be added to tests + sourcemap: true,// Test if #sourcemapUrl is not accidentally included in the html-output +}; + +import {fileURLToPath} from "node:url"; +const __dirname = dirname(fileURLToPath(import.meta.url)); +process.chdir(join(__dirname, 'fixtures')); + + +const defaultAssetInclude = [ + '**/*.(png|jpg|jpeg|gif|ico|svg)',// images, svg + '**/*.(woff|woff2|eot|ttf|otf)',// fonts + '**/*.(webm|mp4)',// video +]; + +test.serial('copied-assets', async (t) => { + const bundle = await rollup({ + input: 'index.html', + plugins: [ + html({ + }), + urlPlugin({ + include: defaultAssetInclude, + limit: 0,// Never inline something + }), + ], + }); + const code = await getCode(bundle, output, true); + debugPrintOutput('copied-assets',code); + t.snapshot(code); +}); + + +test.serial('inlined-assets', async (t) => { + const bundle = await rollup({ + input: 'index.html', + plugins: [ + html({ + }), + urlPlugin({ + include: defaultAssetInclude, + limit: Number.MAX_SAFE_INTEGER,// Always inline things + }), + ] + }); + const code = await getCode(bundle, output, true); + debugPrintOutput('inlined-assets',code); + t.snapshot(code); +}); + +// TODO various parameters +// - format: cjs, iifi, ... +// - sourcemap: inline, false, (and the various exotic sourcemap options) +// Watch mode tests would be its own dir +// ... diff --git a/test/util/test.js b/test/util/test.js index ca9f139..ef3e693 100644 --- a/test/util/test.js +++ b/test/util/test.js @@ -1,5 +1,6 @@ import path from "node:path"; import process from "node:process"; +import chalk from "chalk"; /** * @param {import('rollup').RollupBuild} bundle @@ -22,6 +23,35 @@ export const getCode = async (bundle, outputOptions, allFiles = false) => { return code; }; +export const debugPrintOutput = async (header, files) => { + const out = []; + + const headFn = chalk.bgCyan; + const headPadding = header.split('').map(x=>'#').join(''); + out.push(...[ + headFn(`##${headPadding}##`), + headFn(`# ${header} #`), + headFn(`##${headPadding}##`), + ]); + + const fileHeadFn = chalk.blue; + const fileContentFn = chalk.blackBright; + out.push(...(files.map(file=>{ + return [ + fileHeadFn(`${file.fileName}:`), + fileContentFn(`${file.code??file.source}`), + '', + ] + }).flat())); + + out.push(...[ + headFn(`##${headPadding}##`), + ]); + + process.env.DEBUG? console.log(out.join('\n')) : null; +}; + + /** * @param {import('rollup').RollupBuild} bundle * @param {import('rollup').OutputOptions} [outputOptions]