feat(rollup-plugin-polyfills-loader): first release

This commit is contained in:
Lars den Bakker
2020-03-06 09:38:30 +01:00
parent 73a69d661a
commit 39cc2db792
42 changed files with 1220 additions and 73 deletions

View File

@@ -1,42 +0,0 @@
const html = require('../../rollup-plugin-html');
const htmlPlugin = html({
name: 'index.html',
inject: false,
});
function polyfillsLoader(options) {
return {
name: 'polyfills-loader',
buildStart(inputOptions) {
const { htmlFileName } = options;
const htmlPlugin = inputOptions.plugins.find(pl => {
return pl.name === 'rollup-plugin-html' && pl.getHtmlFileName() === htmlFileName;
});
console.log(htmlPlugin);
return inputOptions;
},
};
}
module.exports = {
input: './demo/spa/src/my-app.js',
output: [
{
format: 'system',
dir: './demo/dist/legacy',
plugins: [htmlPlugin.addOutput()],
},
{
format: 'es',
dir: './demo/dist',
plugins: [htmlPlugin.addOutput()],
},
],
plugins: [
//
htmlPlugin,
polyfillsLoader({ htmlFileName: 'index.html' }),
],
};

View File

@@ -22,7 +22,6 @@
"demo:spa:manual-inject": "rm -rf demo/dist && rollup -c demo/spa/manual-inject.rollup.config.js --watch & yarn serve-demo",
"demo:spa:multi-output": "rm -rf demo/dist && rollup -c demo/spa/multi-output.rollup.config.js --watch & yarn serve-demo",
"demo:spa:template": "rm -rf demo/dist && rollup -c demo/spa/template.rollup.config.js --watch & yarn serve-demo",
"demo:spa:polyfills-loader": "rm -rf demo/dist && rollup -c demo/spa/polyfills-loader.rollup.config.js --watch & yarn serve-demo",
"serve-demo": "es-dev-server --watch --root-dir demo/dist --app-index index.html --compatibility none --open",
"test": "npm run test:node",
"test:node": "mocha test/**/*.test.js test/*.test.js",

View File

@@ -11,6 +11,8 @@
/** @typedef {import('./src/types').GeneratedBundle} GeneratedBundle */
/** @typedef {import('./src/types').TransformFunction} TransformFunction */
/** @typedef {import('./src/types').RollupPluginHtml} RollupPluginHtml */
/** @typedef {import('./src/types').EntrypointBundle} EntrypointBundle */
/** @typedef {import('./src/types').TransformArgs} TransformArgs */
const { getInputHtmlData } = require('./src/getInputHtmlData');
const { getEntrypointBundles } = require('./src/getEntrypointBundles');

View File

@@ -25,13 +25,15 @@ async function getOutputHtml({
const { template, inject, minify } = pluginOptions;
let outputHtml;
const { default: defaultBundle, ...multiBundles } = entrypointBundles;
if (typeof template === 'string') {
outputHtml = template;
} else if (typeof template === 'function') {
outputHtml = await template({
inputHtml,
bundle: entrypointBundles.default,
bundles: entrypointBundles,
bundle: defaultBundle,
bundles: multiBundles,
});
} else if (inputHtml) {
outputHtml = inputHtml;
@@ -55,8 +57,8 @@ async function getOutputHtml({
}
for (const transform of transforms) {
outputHtml = await transform(outputHtml, {
bundle: entrypointBundles.default,
bundles: entrypointBundles,
bundle: defaultBundle,
bundles: multiBundles,
});
}

View File

@@ -0,0 +1,27 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.1.2](https://github.com/open-wc/open-wc/compare/@open-wc/rollup-plugin-html@0.1.1...@open-wc/rollup-plugin-html@0.1.2) (2020-03-02)
**Note:** Version bump only for package @open-wc/rollup-plugin-html
## [0.1.1](https://github.com/open-wc/open-wc/compare/@open-wc/rollup-plugin-html@0.1.0...@open-wc/rollup-plugin-html@0.1.1) (2020-02-29)
**Note:** Version bump only for package @open-wc/rollup-plugin-html
# 0.1.0 (2020-02-29)
### Features
* **rollup-plugin-html:** first release ([9acb29a](https://github.com/open-wc/open-wc/commit/9acb29ac84b0ef7e2b06c57043c9d2c76d5a29c0))

View File

@@ -0,0 +1,172 @@
# Rollup Plugin Polyfills Loader
Inject [Polyfills Loader](https://github.com/open-wc/open-wc/tree/master/packages/polyfills-loader) into a HTML file generated by [@open-wc/rollup-plugin-html](https://github.com/open-wc/open-wc/tree/master/packages/rollup-plugin-html).
## Under construction
Documentation is still under construction.
## Types
```ts
import { PolyfillsConfig } from 'polyfills-loader';
export interface LegacyBuildConfig {
name: string;
test: string;
}
export interface PluginOptions {
htmlFileName?: string;
modernOutput?: string;
legacyOutput?: LegacyBuildConfig | LegacyBuildConfig[];
polyfills?: PolyfillsConfig;
}
```
## Examples
### Basic rollup build
```js
import html from '@open-wc/rollup-plugin-html';
import polyfillsLoader from '@open-wc/rollup-plugin-polyfills-loader';
export default {
output: {
dir: 'dist',
},
plugins: [
html({
inputPath: 'index.html',
inject: false,
}),
polyfillsLoader({
htmlFileName: 'index.html',
polyfills: {
coreJs: true,
fetch: true,
webcomponents: true,
},
}),
],
};
```
### Multiple rollup build outputs
```js
import html from '@open-wc/rollup-plugin-html';
import polyfillsLoader from '@open-wc/rollup-plugin-polyfills-loader';
const htmlPlugin = html({
inputPath: 'demo/single-build/index.html',
inject: false,
});
export default {
output: [
{
format: 'system',
dir: './demo/dist/legacy',
plugins: [htmlPlugin.addOutput('legacy')],
},
{
format: 'es',
dir: './demo/dist',
plugins: [htmlPlugin.addOutput('modern')],
},
],
plugins: [
htmlPlugin,
polyfillsLoader({
htmlFileName: 'index.html',
modernOutput: 'modern',
legacyOutput: { name: 'legacy', test: "!('noModule' in HTMLScriptElement.prototype)" },
polyfills: {
coreJs: true,
fetch: true,
webcomponents: true,
},
}),
],
};
```
### Multi page build
```js
import html from '@open-wc/rollup-plugin-html';
import polyfillsLoader from '@open-wc/rollup-plugin-polyfills-loader';
export default {
output: {
dir: './demo/dist',
},
plugins: [
html({
inputPath: './demo/multi-page/index.html',
}),
polyfillsLoader({
htmlFileName: 'index.html',
polyfills: { coreJs: true, fetch: true },
}),
html({
inputPath: './demo/multi-page/pages/page-a.html',
name: 'pages/page-a.html',
}),
polyfillsLoader({
htmlFileName: 'pages/page-a.html',
polyfills: { coreJs: true, fetch: true },
}),
html({
inputPath: './demo/multi-page/pages/page-b.html',
name: 'pages/page-b.html',
}),
polyfillsLoader({
htmlFileName: 'pages/page-b.html',
polyfills: { coreJs: true, fetch: true },
}),
html({
inputPath: './demo/multi-page/pages/page-c.html',
name: 'pages/page-c.html',
}),
polyfillsLoader({
htmlFileName: 'pages/page-c.html',
polyfills: { coreJs: true, fetch: true },
}),
],
};
```
You can make this shorter with a helper function:
```js
import html from '@open-wc/rollup-plugin-html';
import polyfillsLoader from '@open-wc/rollup-plugin-polyfills-loader';
function createPage(inputPath, name) {
return [
html({ inputPath, name }),
polyfillsLoader({
htmlFileName: name,
polyfills: { coreJs: true, fetch: true },
}),
];
}
export default {
output: {
dir: './demo/dist',
},
plugins: [
...createPage('./demo/multi-page/index.html', 'index.html'),
...createPage('./demo/multi-page/pages/page-a.html', 'pages/page-a.html'),
...createPage('./demo/multi-page/pages/page-b.html', 'pages/page-b.html'),
...createPage('./demo/multi-page/pages/page-c.html', 'pages/page-c.html'),
],
};
```

View File

@@ -0,0 +1 @@
<script type="module" src="./src/my-app.js"></script>

View File

@@ -0,0 +1,35 @@
import html from '@open-wc/rollup-plugin-html';
import polyfillsLoader from '@open-wc/rollup-plugin-polyfills-loader';
const htmlPlugin = html({
inputPath: 'demo/single-build/index.html',
inject: false,
});
export default {
output: [
{
format: 'system',
dir: './demo/dist/legacy',
plugins: [htmlPlugin.addOutput('legacy')],
},
{
format: 'es',
dir: './demo/dist',
plugins: [htmlPlugin.addOutput('modern')],
},
],
plugins: [
htmlPlugin,
polyfillsLoader({
htmlFileName: 'index.html',
modernOutput: 'modern',
legacyOutput: { name: 'legacy', test: "!('noModule' in HTMLScriptElement.prototype)" },
polyfills: {
coreJs: true,
fetch: true,
webcomponents: true,
},
}),
],
};

View File

@@ -0,0 +1 @@
console.log('lazy-1.js');

View File

@@ -0,0 +1 @@
console.log('lazy-2.js');

View File

@@ -0,0 +1,4 @@
console.log('my-app.js');
setTimeout(() => import('./lazy-1.js'), 100);
setTimeout(() => import('./lazy-2.js'), 1000);

View File

@@ -0,0 +1,18 @@
<h1>Index</h1>
<ul>
<li>
<a href="/">Index</a>
</li>
<li>
<a href="/pages/page-a.html">A</a>
</li>
<li>
<a href="/pages/page-B.html">B</a>
</li>
<li>
<a href="/pages/page-C.html">C</a>
</li>
</ul>

View File

@@ -0,0 +1,20 @@
<h1>Page A</h1>
<ul>
<li>
<a href="/">Index</a>
</li>
<li>
<a href="/pages/page-a.html">A</a>
</li>
<li>
<a href="/pages/page-B.html">B</a>
</li>
<li>
<a href="/pages/page-C.html">C</a>
</li>
</ul>
<script type="module" src="./page-a.js"></script>

View File

@@ -0,0 +1,3 @@
import './shared.js';
console.log('page-a.js');

View File

@@ -0,0 +1,20 @@
<h1>Page B</h1>
<ul>
<li>
<a href="/">Index</a>
</li>
<li>
<a href="/pages/page-a.html">A</a>
</li>
<li>
<a href="/pages/page-B.html">B</a>
</li>
<li>
<a href="/pages/page-C.html">C</a>
</li>
</ul>
<script type="module" src="./page-b.js"></script>

View File

@@ -0,0 +1,3 @@
import './shared.js';
console.log('page-c.js');

View File

@@ -0,0 +1,20 @@
<h1>Page B</h1>
<ul>
<li>
<a href="/">Index</a>
</li>
<li>
<a href="/pages/page-a.html">A</a>
</li>
<li>
<a href="/pages/page-B.html">B</a>
</li>
<li>
<a href="/pages/page-C.html">C</a>
</li>
</ul>
<script type="module" src="./page-c.js"></script>

View File

@@ -0,0 +1,3 @@
import './shared.js';
console.log('page-c.js');

View File

@@ -0,0 +1 @@
console.log('shared.js');

View File

@@ -0,0 +1,24 @@
import html from '@open-wc/rollup-plugin-html';
import polyfillsLoader from '@open-wc/rollup-plugin-polyfills-loader';
function createPage(inputPath, name) {
return [
html({ inputPath, name }),
polyfillsLoader({
htmlFileName: name,
polyfills: { coreJs: true, fetch: true },
}),
];
}
export default {
output: {
dir: './demo/dist',
},
plugins: [
...createPage('./demo/multi-page/index.html', 'index.html'),
...createPage('./demo/multi-page/pages/page-a.html', 'pages/page-a.html'),
...createPage('./demo/multi-page/pages/page-b.html', 'pages/page-b.html'),
...createPage('./demo/multi-page/pages/page-c.html', 'pages/page-c.html'),
],
};

View File

@@ -0,0 +1 @@
<script type="module" src="./src/my-app.js"></script>

View File

@@ -0,0 +1,22 @@
import html from '@open-wc/rollup-plugin-html';
import polyfillsLoader from '@open-wc/rollup-plugin-polyfills-loader';
export default {
output: {
dir: './demo/dist',
},
plugins: [
html({
inputPath: 'demo/single-build/index.html',
inject: false,
}),
polyfillsLoader({
htmlFileName: 'index.html',
polyfills: {
coreJs: true,
fetch: true,
webcomponents: true,
},
}),
],
};

View File

@@ -0,0 +1 @@
console.log('lazy-1.js');

View File

@@ -0,0 +1 @@
console.log('lazy-2.js');

View File

@@ -0,0 +1,4 @@
console.log('my-app.js');
setTimeout(() => import('./lazy-1.js'), 100);
setTimeout(() => import('./lazy-2.js'), 1000);

View File

@@ -0,0 +1,48 @@
{
"name": "@open-wc/rollup-plugin-polyfills-loader",
"version": "0.0.0",
"publishConfig": {
"access": "public"
},
"description": "Plugin for generating an html file with rollup",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/open-wc/open-wc.git",
"directory": "packages/rollup-plugin-polyfills-loader"
},
"author": "open-wc",
"homepage": "https://github.com/open-wc/open-wc/",
"main": "rollup-plugin-polyfills-loader.js",
"scripts": {
"demo:single-build": "rm -rf demo/dist && rollup -c demo/single-build/rollup.config.js --watch & yarn serve-demo",
"demo:multi-build": "rm -rf demo/dist && rollup -c demo/multi-build/rollup.config.js --watch & yarn serve-demo",
"demo:multi-page": "rm -rf demo/dist && rollup -c demo/multi-page/rollup.config.js --watch & yarn serve-demo",
"serve-demo": "es-dev-server --watch --root-dir demo/dist --app-index index.html --compatibility none --open",
"test": "npm run test:node",
"test:node": "mocha test/**/*.test.js test/*.test.js",
"test:update-snapshots": "mocha test/**/*.test.js test/*.test.js --update-snapshots",
"test:watch": "npm run test:node -- --watch"
},
"files": [
"*.js",
"src"
],
"keywords": [
"rollup-plugin",
"minify",
"html",
"polyfill"
],
"devDependencies": {
"chai": "^4.2.0",
"es-dev-server": "^1.42.1",
"lit-element": "^2.2.1",
"rimraf": "^3.0.0",
"rollup": "^1.31.1"
},
"dependencies": {
"@open-wc/rollup-plugin-html": "^0.1.3",
"polyfills-loader": "^1.3.0"
}
}

View File

@@ -0,0 +1,83 @@
/* eslint-disable no-param-reassign */
/** @typedef {import ('@open-wc/rollup-plugin-html').RollupPluginHtml} RollupPluginHtml */
/** @typedef {import ('@open-wc/rollup-plugin-html').EntrypointBundle} EntrypointBundle */
/** @typedef {import('rollup').EmittedFile} EmittedFile */
/** @typedef {import('rollup').Plugin} Plugin */
/** @typedef {import('polyfills-loader').FileType} FileType */
/** @typedef {import('polyfills-loader').GeneratedFile} GeneratedFile */
/** @typedef {import('./src/types').PluginOptions} PluginOptions */
const { injectPolyfillsLoader } = require('polyfills-loader');
const { createError } = require('./src/utils');
const { createPolyfillsLoaderConfig } = require('./src/createPolyfillsLoaderConfig');
/**
* @param {PluginOptions} pluginOptions
* @returns {Plugin}
*/
function rollupPluginHtml(pluginOptions) {
pluginOptions = {
htmlFileName: 'index.html',
...(pluginOptions || {}),
};
/** @type {GeneratedFile[] | undefined} */
let generatedFiles;
return {
name: '@open-wc/rollup-plugin-polyfills-loader',
buildStart(options) {
generatedFiles = undefined;
if (!options.plugins) throw new Error('no plugins');
const htmlPlugins = /** @type {RollupPluginHtml[]} */ (options.plugins.filter(
p => p.name === '@open-wc/rollup-plugin-html',
));
if (htmlPlugins.length === 0) {
throw createError(
'Could not find any instance of @open-wc/rollup-plugin-html in rollup build.',
);
}
const htmlPlugin = htmlPlugins.find(
pl => pl.getHtmlFileName() === pluginOptions.htmlFileName,
);
if (!htmlPlugin) {
throw createError(
`Could not find any instance of @open-wc/rollup-plugin-html that creates a file called ${pluginOptions.htmlFileName}.` +
`Found filenames: ${htmlPlugins.map(p => p.getHtmlFileName()).join(', ')}`,
);
}
htmlPlugin.addHtmlTransformer((html, { bundle, bundles }) => {
const config = createPolyfillsLoaderConfig(pluginOptions, bundle, bundles);
const { htmlString, polyfillFiles } = injectPolyfillsLoader(html, config);
generatedFiles = polyfillFiles;
return htmlString;
});
},
generateBundle(_, bundle) {
if (generatedFiles) {
for (const file of generatedFiles) {
// if the polyfills loader is used multiple times, this polyfill might already be output
// so we guard against that. polyfills are already hashed, so there is no need to worry
// about clashing
if (!(file.path in bundle)) {
this.emitFile({
type: 'asset',
name: file.path,
fileName: file.path,
source: file.content,
});
}
}
}
},
};
}
module.exports = rollupPluginHtml;

View File

@@ -0,0 +1,99 @@
/** @typedef {import ('@open-wc/rollup-plugin-html').EntrypointBundle} EntrypointBundle */
/** @typedef {import('polyfills-loader').PolyfillsLoaderConfig} PolyfillsLoaderConfig */
/** @typedef {import('polyfills-loader').LegacyEntrypoint} LegacyEntrypoint */
/** @typedef {import('rollup').ModuleFormat} ModuleFormat */
/** @typedef {import('./types').PluginOptions} PluginOptions */
const { fileTypes } = require('polyfills-loader');
const { createError } = require('./utils');
/** @param {ModuleFormat} [format] */
function formatToFilyType(format) {
switch (format) {
case 'es':
case 'esm':
case 'module':
return fileTypes.MODULE;
case 'system':
return fileTypes.SYSTEMJS;
default:
return fileTypes.SCRIPT;
}
}
/** @param {string} name */
function bundleNotFoundError(name) {
return createError(`Could not find any @open-wc/rollup-plugin-html output named ${name}.`);
}
/** @param {EntrypointBundle} bundle */
function createEntrypoints(bundle) {
const type = formatToFilyType(bundle.options.format);
const files = bundle.entrypoints.map(e => ({ type, path: e.importPath }));
return { files };
}
/**
* @param {EntrypointBundle} bundle
* @param {string} test
*/
function createLegacyEntrypoints(bundle, test) {
return { ...createEntrypoints(bundle), test };
}
/**
* @param {PluginOptions} pluginOptions
* @param {EntrypointBundle} [bundle]
* @param {Record<string, EntrypointBundle>} [bundles]
* @returns {PolyfillsLoaderConfig}
*/
function createPolyfillsLoaderConfig(pluginOptions, bundle, bundles) {
const { modernOutput, legacyOutput, polyfills } = pluginOptions;
let modern;
let legacy;
// @open-wc/rollup-plugin-html outputs `bundle` when there is a single output,
// otherwise it outputs `bundles`
if (bundle) {
if (modernOutput || legacyOutput) {
throw createError(
'Options modernOutput or legacyOutput was set, but @open-wc/rollup-plugin-html' +
` did not output multiple builds. Make sure you use html.addOutput('my-output') for each rollup output.`,
);
}
modern = createEntrypoints(bundle);
} else {
if (!bundles || Object.keys(bundles).length === 0) {
throw createError(
'@open-wc/rollup-plugin-html did not output any bundles to ' +
`be injected in the HTML file ${pluginOptions.htmlFileName}`,
);
}
if (!modernOutput || !legacyOutput) {
throw createError(
'Rollup is configured to output multiple builds, set the modernOutput and legacyOutput options' +
' to configure how they should be loaded by the polyfills loader.',
);
}
if (!bundles[modernOutput]) throw bundleNotFoundError(modernOutput);
modern = createEntrypoints(bundles[modernOutput]);
/** @type {LegacyEntrypoint[]} */
legacy = [];
const legacyOutputIterator = Array.isArray(legacyOutput) ? legacyOutput : [legacyOutput];
for (const output of legacyOutputIterator) {
if (!bundles[output.name]) throw bundleNotFoundError(output.name);
const entrypoint = createLegacyEntrypoints(bundles[output.name], output.test);
legacy.push(entrypoint);
}
}
return { modern, legacy, polyfills };
}
module.exports = { createPolyfillsLoaderConfig };

View File

@@ -0,0 +1,13 @@
import { PolyfillsConfig } from 'polyfills-loader';
export interface LegacyBuildConfig {
name: string;
test: string;
}
export interface PluginOptions {
htmlFileName?: string;
modernOutput?: string;
legacyOutput?: LegacyBuildConfig | LegacyBuildConfig[];
polyfills?: PolyfillsConfig;
}

View File

@@ -0,0 +1,15 @@
/** @typedef {import('rollup').InputOptions} InputOptions */
/** @typedef {import('./types').PluginOptions} PluginOptions */
const PLUGIN = '[rollup-plugin-polyfills-loader]';
/**
* @param {string} msg
*/
function createError(msg) {
return new Error(`${PLUGIN} ${msg}`);
}
module.exports = {
createError,
};

View File

@@ -0,0 +1 @@
console.log('entrypoint-a.js');

View File

@@ -0,0 +1 @@
console.log('entrypoint-b.js');

View File

@@ -0,0 +1,202 @@
/* eslint-disable no-await-in-loop */
/** @typedef {import('rollup').OutputChunk} OutputChunk */
/** @typedef {import('rollup').OutputAsset} OutputAsset */
/** @typedef {import('rollup').RollupOptions} RollupOptions */
/** @typedef {import('rollup').OutputOptions} OutputOptions */
/** @typedef {(OutputChunk | OutputAsset)[]} Output */
const rollup = require('rollup');
const { expect } = require('chai');
const fs = require('fs');
const path = require('path');
// @ts-ignore
const html = require('@open-wc/rollup-plugin-html');
const polyfillsLoader = require('../rollup-plugin-polyfills-loader');
const updateSnapshots = process.argv.includes('--update-snapshots');
/**
* @param {Output} output
* @param {string} name
* @returns {OutputAsset & { source: string }}
*/
function getAsset(output, name) {
return /** @type {OutputAsset & { source: string }} */ (output.find(
o => o.fileName === name && o.type === 'asset',
));
}
/**
* @param {object} args
* @param {string} args.name
* @param {string} args.fileName
* @param {RollupOptions} args.inputOptions
* @param {OutputOptions[]} args.outputOptions
*/
async function testSnapshot({ name, fileName, inputOptions, outputOptions }) {
const snapshotPath = path.join(__dirname, 'snapshots', `${name}.html`);
const bundle = await rollup.rollup(inputOptions);
let output;
for (const outputConfig of outputOptions) {
({ output } = await bundle.generate(outputConfig));
}
if (!output) throw new Error('');
const file = getAsset(output, fileName);
if (!file) throw new Error(`Build did not output ${fileName}`);
if (updateSnapshots) {
fs.writeFileSync(snapshotPath, file.source, 'utf-8');
} else {
const snapshot = fs.readFileSync(snapshotPath, 'utf-8');
expect(file.source.replace(/\s/g, '')).to.equal(snapshot.replace(/\s/g, ''));
}
return output;
}
/** @type {OutputOptions[]} */
const defaultOutputOptions = [
{
format: 'es',
dir: 'dist',
},
];
describe('rollup-plugin-polyfills-loader', () => {
it('can inject a polyfills loader with a single output', async () => {
const inputOptions = {
plugins: [
html({
inputHtml: '<script type="module" src="test/fixtures/entrypoint-a.js"></script>',
minify: false,
}),
polyfillsLoader({
htmlFileName: 'index.html',
}),
],
};
await testSnapshot({
name: 'single-output',
fileName: 'index.html',
inputOptions,
outputOptions: defaultOutputOptions,
});
});
it('can set the html file name', async () => {
const inputOptions = {
plugins: [
html({
name: 'foo.html',
inputHtml: '<script type="module" src="test/fixtures/entrypoint-a.js"></script>',
minify: false,
}),
polyfillsLoader({
htmlFileName: 'foo.html',
}),
],
};
await testSnapshot({
name: 'html-filename',
fileName: 'foo.html',
inputOptions,
outputOptions: defaultOutputOptions,
});
});
it('can set polyfills to load', async () => {
const inputOptions = {
plugins: [
html({
name: 'index.html',
inputHtml: '<script type="module" src="test/fixtures/entrypoint-a.js"></script>',
minify: false,
}),
polyfillsLoader({
htmlFileName: 'index.html',
polyfills: {
webcomponents: true,
fetch: true,
},
}),
],
};
const output = await testSnapshot({
name: 'polyfills',
fileName: 'index.html',
inputOptions,
outputOptions: defaultOutputOptions,
});
expect(output.find(o => o.fileName.startsWith('polyfills/webcomponents'))).to.exist;
expect(output.find(o => o.fileName.startsWith('polyfills/fetch'))).to.exist;
});
it('can inject with multiple build outputs', async () => {
const htmlPlugin = html({
name: 'index.html',
inputHtml: '<script type="module" src="test/fixtures/entrypoint-a.js"></script>',
minify: false,
});
const inputOptions = {
plugins: [
htmlPlugin,
polyfillsLoader({
htmlFileName: 'index.html',
modernOutput: 'modern',
legacyOutput: [{ name: 'legacy', test: "!('noModule' in HTMLScriptElement.prototype)" }],
polyfills: {
webcomponents: true,
fetch: true,
},
}),
],
};
/** @type {OutputOptions[]} */
const outputOptions = [
{
format: 'system',
dir: 'dist/legacy',
plugins: [htmlPlugin.addOutput('legacy')],
},
{
format: 'es',
dir: 'dist',
plugins: [htmlPlugin.addOutput('modern')],
},
];
await testSnapshot({
name: 'multiple-outputs',
fileName: 'index.html',
inputOptions,
outputOptions,
});
});
it('polyfills loader can be minified by html plugin', async () => {
const inputOptions = {
plugins: [
html({
inputHtml: '<script type="module" src="test/fixtures/entrypoint-a.js"></script>',
}),
polyfillsLoader({
htmlFileName: 'index.html',
}),
],
};
await testSnapshot({
name: 'minified',
fileName: 'index.html',
inputOptions,
outputOptions: defaultOutputOptions,
});
});
});

View File

@@ -0,0 +1,25 @@
<html><head></head><body><script type="module" src="./entrypoint-a.js"></script><script>(function () {
function loadScript(src, type) {
return new Promise(function (resolve) {
var script = document.createElement('script');
function onLoaded() {
document.head.removeChild(script);
resolve();
}
script.src = src;
script.onload = onLoaded;
script.onerror = function () {
console.error('[polyfills-loader] failed to load: ' + src + ' check the network tab for HTTP status.');
onLoaded();
};
if (type) script.type = type;
document.head.appendChild(script);
});
}
loadScript('./entrypoint-a.js', 'module');
})();</script></body></html>

View File

@@ -0,0 +1 @@
<html><head></head><body><script type="module" src="./entrypoint-a.js"></script><script>!function(){var e,o;e="./entrypoint-a.js",o="module",new Promise((function(n){var t=document.createElement("script");function r(){document.head.removeChild(t),n()}t.src=e,t.onload=r,t.onerror=function(){console.error("[polyfills-loader] failed to load: "+e+" check the network tab for HTTP status."),r()},o&&(t.type=o),document.head.appendChild(t)}))}();</script></body></html>

View File

@@ -0,0 +1,55 @@
<html><head></head><body><script>System.import("./legacy/entrypoint-a.js");</script><script type="module" src="./entrypoint-a.js"></script><script>(function () {
function loadScript(src, type) {
return new Promise(function (resolve) {
var script = document.createElement('script');
function onLoaded() {
document.head.removeChild(script);
resolve();
}
script.src = src;
script.onload = onLoaded;
script.onerror = function () {
console.error('[polyfills-loader] failed to load: ' + src + ' check the network tab for HTTP status.');
onLoaded();
};
if (type) script.type = type;
document.head.appendChild(script);
});
}
var polyfills = [];
if (!('fetch' in window)) {
polyfills.push(loadScript('./polyfills/fetch.8c78815e37189a88a5ccc668ab31698f.js'));
}
if (!('noModule' in HTMLScriptElement.prototype)) {
polyfills.push(loadScript('./polyfills/systemjs.6dfbfd8f2c3e558918ed74d133a6757a.js'));
}
if (!('attachShadow' in Element.prototype) || !('getRootNode' in Element.prototype)) {
polyfills.push(loadScript('./polyfills/webcomponents.dae9f79d9d6992b6582e204c3dd953d3.js'));
}
if (!('noModule' in HTMLScriptElement.prototype) && 'getRootNode' in Element.prototype) {
polyfills.push(loadScript('./polyfills/custom-elements-es5-adapter.0ec040d16c6fd1b9220084b0b925cbe0.js'));
}
function loadFiles() {
if (!('noModule' in HTMLScriptElement.prototype)) {
System.import('./legacy/entrypoint-a.js');
} else {
loadScript('./entrypoint-a.js', 'module');
}
}
if (polyfills.length) {
Promise.all(polyfills).then(loadFiles);
} else {
loadFiles();
}
})();</script></body></html>

View File

@@ -0,0 +1,47 @@
<html><head></head><body><script type="module" src="./entrypoint-a.js"></script><script>(function () {
function loadScript(src, type) {
return new Promise(function (resolve) {
var script = document.createElement('script');
function onLoaded() {
document.head.removeChild(script);
resolve();
}
script.src = src;
script.onload = onLoaded;
script.onerror = function () {
console.error('[polyfills-loader] failed to load: ' + src + ' check the network tab for HTTP status.');
onLoaded();
};
if (type) script.type = type;
document.head.appendChild(script);
});
}
var polyfills = [];
if (!('fetch' in window)) {
polyfills.push(loadScript('./polyfills/fetch.8c78815e37189a88a5ccc668ab31698f.js'));
}
if (!('attachShadow' in Element.prototype) || !('getRootNode' in Element.prototype)) {
polyfills.push(loadScript('./polyfills/webcomponents.dae9f79d9d6992b6582e204c3dd953d3.js'));
}
if (!('noModule' in HTMLScriptElement.prototype) && 'getRootNode' in Element.prototype) {
polyfills.push(loadScript('./polyfills/custom-elements-es5-adapter.0ec040d16c6fd1b9220084b0b925cbe0.js'));
}
function loadFiles() {
loadScript('./entrypoint-a.js', 'module');
}
if (polyfills.length) {
Promise.all(polyfills).then(loadFiles);
} else {
loadFiles();
}
})();</script></body></html>

View File

@@ -0,0 +1,25 @@
<html><head></head><body><script type="module" src="./entrypoint-a.js"></script><script>(function () {
function loadScript(src, type) {
return new Promise(function (resolve) {
var script = document.createElement('script');
function onLoaded() {
document.head.removeChild(script);
resolve();
}
script.src = src;
script.onload = onLoaded;
script.onerror = function () {
console.error('[polyfills-loader] failed to load: ' + src + ' check the network tab for HTTP status.');
onLoaded();
};
if (type) script.type = type;
document.head.appendChild(script);
});
}
loadScript('./entrypoint-a.js', 'module');
})();</script></body></html>

View File

@@ -0,0 +1,208 @@
const { expect } = require('chai');
const { createPolyfillsLoaderConfig } = require('../../src/createPolyfillsLoaderConfig');
describe('createPolyfillsLoaderConfig()', () => {
it('creates a config for a single module build', () => {
const pluginConfig = {};
const bundle = {
options: { format: 'es' },
entrypoints: [{ importPath: 'app.js' }],
};
// @ts-ignore
const config = createPolyfillsLoaderConfig(pluginConfig, bundle);
expect(config).to.eql({
legacy: undefined,
modern: { files: [{ path: 'app.js', type: 'module' }] },
polyfills: undefined,
});
});
it('creates a config for multiple entrypoints', () => {
const pluginConfig = {};
const bundle = {
options: { format: 'es' },
entrypoints: [{ importPath: 'app-1.js' }, { importPath: 'app-2.js' }],
};
// @ts-ignore
const config = createPolyfillsLoaderConfig(pluginConfig, bundle);
expect(config).to.eql({
legacy: undefined,
modern: {
files: [
{ path: 'app-1.js', type: 'module' },
{ path: 'app-2.js', type: 'module' },
],
},
polyfills: undefined,
});
});
it('creates a config for a single systemjs build', () => {
const pluginConfig = {};
const bundle = {
options: { format: 'system' },
entrypoints: [
// @ts-ignore
{ importPath: 'app.js' },
],
};
// @ts-ignore
const config = createPolyfillsLoaderConfig(pluginConfig, bundle);
expect(config).to.eql({
legacy: undefined,
modern: { files: [{ path: 'app.js', type: 'systemjs' }] },
polyfills: undefined,
});
});
it('creates a config for 2 build outputs', () => {
const pluginConfig = {
modernOutput: 'modern',
legacyOutput: { name: 'legacy', test: "!('noModule' in HTMScriptElement.prototype)" },
};
const bundles = {
modern: {
options: { format: 'es' },
entrypoints: [{ importPath: 'app.js' }],
},
legacy: {
options: { format: 'system' },
entrypoints: [{ importPath: 'legacy/app.js' }],
},
};
// @ts-ignore
const config = createPolyfillsLoaderConfig(pluginConfig, undefined, bundles);
expect(config).to.eql({
modern: { files: [{ path: 'app.js', type: 'module' }] },
legacy: [
{
files: [{ path: 'legacy/app.js', type: 'systemjs' }],
test: "!('noModule' in HTMScriptElement.prototype)",
},
],
polyfills: undefined,
});
});
it('creates a config for 3 build outputs', () => {
const pluginConfig = {
modernOutput: 'modern',
legacyOutput: [
{ name: 'super-legacy', test: 'window.bar' },
{ name: 'legacy', test: 'window.foo' },
],
};
const bundles = {
modern: {
options: { format: 'es' },
entrypoints: [{ importPath: 'app.js' }],
},
legacy: {
options: { format: 'system' },
entrypoints: [{ importPath: 'legacy/app.js' }],
},
'super-legacy': {
options: { format: 'system' },
entrypoints: [{ importPath: 'super-legacy/app.js' }],
},
};
// @ts-ignore
const config = createPolyfillsLoaderConfig(pluginConfig, undefined, bundles);
expect(config).to.eql({
modern: { files: [{ path: 'app.js', type: 'module' }] },
legacy: [
{
files: [{ path: 'super-legacy/app.js', type: 'systemjs' }],
test: 'window.bar',
},
{
files: [{ path: 'legacy/app.js', type: 'systemjs' }],
test: 'window.foo',
},
],
polyfills: undefined,
});
});
it('can set polyfills to load', () => {
const pluginConfig = {
polyfills: { fetch: true, webcomponents: true },
};
const bundle = {
options: { format: 'es' },
entrypoints: [{ importPath: 'app.js' }],
};
// @ts-ignore
const config = createPolyfillsLoaderConfig(pluginConfig, bundle);
expect(config).to.eql({
legacy: undefined,
modern: { files: [{ path: 'app.js', type: 'module' }] },
polyfills: { fetch: true, webcomponents: true },
});
});
it('throws when a single build is output while multiple builds are configured', () => {
const pluginConfig = {
modernOutput: 'modern',
};
const bundle = {
options: { format: 'es' },
entrypoints: [{ importPath: 'app.js' }],
};
// @ts-ignore
const action = () => createPolyfillsLoaderConfig(pluginConfig, bundle);
expect(action).to.throw();
});
it('throws when a multiple builds are output while no builds are configured', () => {
const pluginConfig = {};
const bundles = {
modern: {
options: { format: 'es' },
entrypoints: [{ importPath: 'app.js' }],
},
legacy: {
options: { format: 'system' },
entrypoints: [{ importPath: 'legacy/app.js' }],
},
};
// @ts-ignore
const action = () => createPolyfillsLoaderConfig(pluginConfig, undefined, bundles);
expect(action).to.throw();
});
it('throws when the modern build could not be found', () => {
const pluginConfig = {
modernOutput: 'not-modern',
legacyOutput: { name: 'legacy', test: 'window.foo' },
};
const bundles = {
modern: {
options: { format: 'es' },
entrypoints: [{ importPath: 'app.js' }],
},
legacy: {
options: { format: 'system' },
entrypoints: [{ importPath: 'legacy/app.js' }],
},
};
// @ts-ignore
const action = () => createPolyfillsLoaderConfig(pluginConfig, undefined, bundles);
expect(action).to.throw();
});
});

View File

@@ -0,0 +1,6 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"strict": true
}
}

View File

@@ -14,7 +14,7 @@
"esModuleInterop": true
},
"files": ["browser.d.ts"],
"include": ["packages"],
"include": ["packages/**/*"],
"exclude": [
"node_modules",
"**/node_modules/*",

View File

@@ -3092,31 +3092,6 @@
resolved "https://registry.yarnpkg.com/@open-wc/semantic-dom-diff/-/semantic-dom-diff-0.13.21.tgz#718b9ec5f9a98935fc775e577ad094ae8d8b7dea"
integrity sha512-BONpjHcGX2zFa9mfnwBCLEmlDsOHzT+j6Qt1yfK3MzFXFtAykfzFjAgaxPetu0YbBlCfXuMlfxI4vlRGCGMvFg==
<<<<<<< HEAD
"@open-wc/testing-karma-bs@file:./packages/testing-karma-bs":
version "1.3.45"
dependencies:
"@open-wc/testing-karma" "^3.3.1"
"@types/node" "^11.13.0"
karma-browserstack-launcher "^1.0.0"
"@open-wc/testing-karma@file:./packages/testing-karma":
version "3.3.1"
dependencies:
"@open-wc/karma-esm" "^2.13.12"
axe-core "^3.3.1"
karma "^4.1.0"
karma-chrome-launcher "^3.1.0"
karma-coverage-istanbul-reporter "^2.0.0"
karma-mocha "^1.0.0"
karma-mocha-reporter "^2.0.0"
karma-mocha-snapshot "^0.2.1"
karma-snapshot "^0.6.0"
karma-source-map-support "^1.3.0"
mocha "^6.2.2"
=======
>>>>>>> feat(rollup-plugin-html): other plugins can inject transform functions
"@reach/router@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.2.1.tgz#34ae3541a5ac44fa7796e5506a5d7274a162be4e"