Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dev-server-legacy] Only transform modules to system js #743

Merged
merged 3 commits into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/short-months-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@web/test-runner': patch
---

run user plugins after builtin plugins
5 changes: 5 additions & 0 deletions .changeset/smart-spiders-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@web/dev-server-legacy': patch
---

only transform modules to systemjs
6 changes: 6 additions & 0 deletions .changeset/sweet-starfishes-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@web/dev-server-core': patch
'@web/dev-server': patch
---

ensure user plugins are run after builtin plugins
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ export async function transformImports(

if (dynamicImportIndex === -1) {
// static import

const importSpecifier = code.substring(start, end);
const lines = code.slice(0, end).split('\n');
const line = lines.length;
Expand Down Expand Up @@ -258,6 +257,7 @@ export function transformModuleImportsPlugin(plugins: Plugin[], rootDir: string)
predicates.NOT(predicates.hasAttr('src')),
),
);
let transformed = false;

for (const node of inlineModuleNodes) {
const code = getTextContent(node);
Expand All @@ -267,10 +267,15 @@ export function transformModuleImportsPlugin(plugins: Plugin[], rootDir: string)
rootDir,
importPlugins,
);
setTextContent(node, resolvedCode);
if (code !== resolvedCode) {
setTextContent(node, resolvedCode);
transformed = true;
}
}

return { body: serializeHtml(documentAst) };
if (transformed) {
return { body: serializeHtml(documentAst) };
}
}
},
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { DevServerCoreConfig } from '../DevServerCoreConfig';
import { Plugin } from '../Plugin';
import { transformModuleImportsPlugin } from '../plugins/transformModuleImportsPlugin';
import { webSocketsPlugin } from '../web-sockets/webSocketsPlugin';
import { mimeTypesPlugin } from '../plugins/mimeTypesPlugin';

export function createPlugins(config: DevServerCoreConfig) {
const plugins: Plugin[] = [];

if (config.mimeTypes && Object.keys(config.mimeTypes).length > 0) {
plugins.push(mimeTypesPlugin(config.mimeTypes));
export function addPlugins(config: DevServerCoreConfig) {
if (!config.plugins) {
config.plugins = [];
}

if (config.plugins?.some(pl => 'resolveImport' in pl || 'transformImport' in pl)) {
plugins.push(transformModuleImportsPlugin(config.plugins, config.rootDir));
if (config.mimeTypes && Object.keys(config.mimeTypes).length > 0) {
config.plugins.unshift(mimeTypesPlugin(config.mimeTypes));
}

if (config.injectWebSocket && config.plugins?.some(pl => pl.injectWebSocket)) {
plugins.push(webSocketsPlugin());
config.plugins.unshift(webSocketsPlugin());
}

return plugins;
if (config.plugins?.some(pl => 'resolveImport' in pl || 'transformImport' in pl)) {
// transform module imports must happen after all other plugins did their regular transforms
config.plugins.push(transformModuleImportsPlugin(config.plugins, config.rootDir));
}
}
18 changes: 7 additions & 11 deletions packages/dev-server-core/src/server/createServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import net, { Server, Socket, ListenOptions } from 'net';
import { DevServerCoreConfig } from '../DevServerCoreConfig';
import { createMiddleware } from './createMiddleware';
import { Logger } from '../logger/Logger';
import { createPlugins } from './createPlugins';
import { addPlugins } from './addPlugins';

/**
* A request handler that returns a 301 HTTP Redirect to the same location as the original
Expand All @@ -28,22 +28,18 @@ function httpsRedirect(req: IncomingMessage, res: ServerResponse) {
export function createServer(cfg: DevServerCoreConfig, logger: Logger, fileWatcher: FSWatcher) {
const app = new Koa();

const plugins = createPlugins(cfg);
if (!cfg.plugins) {
cfg.plugins = [];
}
cfg.plugins.push(...plugins);
addPlugins(cfg);

// special case the legacy plugin, if it is given make sure the resolve module imports plugin
// runs before the legacy plugin because it compiles away module syntax. ideally we have a
// generic API for this, but we need to design that a bit more first
const indexOfLegacy = cfg.plugins.findIndex(p => p.name === 'legacy');
let indexOfResolve = cfg.plugins.findIndex(p => p.name === 'resolve-module-imports');
const indexOfLegacy = cfg.plugins!.findIndex(p => p.name === 'legacy');
let indexOfResolve = cfg.plugins!.findIndex(p => p.name === 'resolve-module-imports');
if (indexOfLegacy !== -1 && indexOfResolve !== -1) {
const legacy = cfg.plugins.splice(indexOfLegacy, 1)[0];
const legacy = cfg.plugins!.splice(indexOfLegacy, 1)[0];
// recompute after splicing
indexOfResolve = cfg.plugins.findIndex(p => p.name === 'resolve-module-imports');
cfg.plugins.splice(indexOfResolve, 1, cfg.plugins[indexOfResolve], legacy);
indexOfResolve = cfg.plugins!.findIndex(p => p.name === 'resolve-module-imports');
cfg.plugins!.splice(indexOfResolve, 1, cfg.plugins![indexOfResolve], legacy);
}

const middleware = createMiddleware(cfg, logger, fileWatcher);
Expand Down
2 changes: 1 addition & 1 deletion packages/dev-server-import-maps/test/resolving.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ describe('resolving imports', () => {
});

const text = await fetchText(`${host}/index.html`);
expectIncludes(text, '<html><head></head><body><script src="./app.js"></script></body></html>');
expectIncludes(text, '<html><body><script src="./app.js"></script></body></html>');

server.stop();
});
Expand Down
1 change: 1 addition & 0 deletions packages/dev-server-legacy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@babel/core": "^7.10.5",
"@babel/plugin-proposal-dynamic-import": "^7.10.4",
"@babel/plugin-syntax-class-properties": "^7.10.4",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/plugin-syntax-numeric-separator": "^7.10.4",
"@babel/plugin-transform-modules-systemjs": "^7.10.5",
Expand Down
12 changes: 10 additions & 2 deletions packages/dev-server-legacy/src/babelTransform.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { transformAsync, TransformOptions } from '@babel/core';

export const config: TransformOptions = {
export const es5Config: TransformOptions = {
caller: {
name: '@web/dev-server-legacy',
supportsStaticESM: true,
Expand Down Expand Up @@ -28,6 +28,14 @@ export const config: TransformOptions = {
require.resolve('@babel/plugin-syntax-import-meta'),
require.resolve('@babel/plugin-syntax-class-properties'),
require.resolve('@babel/plugin-syntax-numeric-separator'),
require.resolve('@babel/plugin-syntax-dynamic-import'),
],
};

export const systemJsConfig: TransformOptions = {
...es5Config,
plugins: [
...(es5Config.plugins ?? []),
require.resolve('@babel/plugin-proposal-dynamic-import'),
require.resolve('@babel/plugin-transform-modules-systemjs'),
// systemjs adds template literals, we do systemjs after (potential)
Expand All @@ -36,7 +44,7 @@ export const config: TransformOptions = {
],
};

export async function babelTransform(filename: string, source: string) {
export async function babelTransform(filename: string, source: string, config: TransformOptions) {
const largeFile = source.length > 100000;
const result = await transformAsync(source, {
filename,
Expand Down
1 change: 1 addition & 0 deletions packages/dev-server-legacy/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const PARAM_TRANSFORM_SYSTEMJS = 'systemjs';
7 changes: 6 additions & 1 deletion packages/dev-server-legacy/src/injectPolyfillsLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
GeneratedFile,
File,
} from 'polyfills-loader';
import { PARAM_TRANSFORM_SYSTEMJS } from './constants';
import { findJsScripts } from './findJsScripts';

function findScripts(indexUrl: string, documentAst: DocumentAst) {
Expand All @@ -22,13 +23,17 @@ function findScripts(indexUrl: string, documentAst: DocumentAst) {
let src = getAttribute(scriptNode, 'src');

if (!src) {
src = `inline-script-${i}.js?source=${encodeURIComponent(indexUrl)}`;
const suffix = type === 'module' ? `&${PARAM_TRANSFORM_SYSTEMJS}=true` : '';
src = `inline-script-${i}.js?source=${encodeURIComponent(indexUrl)}${suffix}`;
inlineScripts.push({
path: src,
type,
content: getTextContent(scriptNode),
});
inlineScriptNodes.push(scriptNode);
} else if (type === 'module') {
const separator = src.includes('?') ? '&' : '?';
src = `${src}${separator}${PARAM_TRANSFORM_SYSTEMJS}=true`;
}

files.push({
Expand Down
18 changes: 16 additions & 2 deletions packages/dev-server-legacy/src/legacyPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Plugin, Logger, getRequestFilePath, isInlineScriptRequest } from '@web/
import { GeneratedFile, PolyfillsConfig } from 'polyfills-loader';
import path from 'path';
import { isLegacyBrowser } from './isLegacyBrowser';
import { babelTransform } from './babelTransform';
import { babelTransform, es5Config, systemJsConfig } from './babelTransform';
import { injectPolyfillsLoader } from './injectPolyfillsLoader';
import { PARAM_TRANSFORM_SYSTEMJS } from './constants';

interface inlineScripts {
lastModified: string;
Expand Down Expand Up @@ -103,8 +104,12 @@ export function legacyPlugin(options: LegacyPluginOptions = {}): Plugin {
if (context.path.includes('/polyfills/')) {
return;
}
const config =
context.URL.searchParams.get(PARAM_TRANSFORM_SYSTEMJS) === 'true'
? systemJsConfig
: es5Config;
const filePath = getRequestFilePath(context, rootDir);
const transformed = await babelTransform(filePath, context.body);
const transformed = await babelTransform(filePath, context.body, config);
context.body = transformed;
return;
}
Expand All @@ -129,6 +134,15 @@ export function legacyPlugin(options: LegacyPluginOptions = {}): Plugin {
});
}
},

transformImport({ source, context }) {
if (!isLegacyBrowser(context, logger)) {
return;
}

const prefix = source.includes('?') ? '&' : '?';
return `${source}${prefix}${PARAM_TRANSFORM_SYSTEMJS}=true`;
},
};
}

Expand Down
45 changes: 37 additions & 8 deletions packages/dev-server-legacy/test/transform-html.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { modernUserAgents, legacyUserAgents } from './userAgents';
const htmlBody = `
<html>
<body>
<script type="module" src="./foo.js"></scrip>
<script type="module" src="./foo.js"></script>
<script src="./bar.js"></script>
</body>
</html>`;

Expand All @@ -20,10 +21,11 @@ const inlineScriptHtmlBody = `

}
</script>
<script>console.log("x");</script>
</body>
</html>`;

describe('legacyPlugin()', function () {
describe('legacyPlugin - transform html', function () {
this.timeout(10000);

it(`does not do any work on a modern browser`, async () => {
Expand All @@ -45,6 +47,7 @@ describe('legacyPlugin()', function () {
const text = await fetchText(`${host}/index.html`, {
headers: { 'user-agent': modernUserAgents['Chrome 78'] },
});

expect(text.trim()).to.equal(htmlBody.trim());
server.stop();
});
Expand All @@ -71,11 +74,34 @@ describe('legacyPlugin()', function () {
expectIncludes(text, 'function polyfillsLoader() {');
expectIncludes(text, "loadScript('./polyfills/regenerator-runtime.");
expectIncludes(text, "loadScript('./polyfills/fetch.");
expectIncludes(text, "System.import('./foo.js');");
expectIncludes(text, "loadScript('./polyfills/systemjs.");
server.stop();
});

it(`injects systemjs param to inline modules`, async () => {
const { server, host } = await createTestServer({
rootDir: __dirname,
plugins: [
{
name: 'test',
serve(context) {
if (context.path === '/index.html') {
return htmlBody;
}
},
},
legacyPlugin(),
],
});

const text = await fetchText(`${host}/index.html`, {
headers: { 'user-agent': legacyUserAgents['IE 11'] },
});
expectIncludes(text, "loadScript('./bar.js');");
expectIncludes(text, "System.import('./foo.js?systemjs=true');");
server.stop();
});

it(`handles inline scripts`, async () => {
const { server, host } = await createTestServer({
rootDir: __dirname,
Expand All @@ -95,7 +121,11 @@ describe('legacyPlugin()', function () {
const text = await fetchText(`${host}/index.html`, {
headers: { 'user-agent': legacyUserAgents['IE 11'] },
});
expectIncludes(text, "System.import('./inline-script-0.js?source=%2Findex.html');");
expectIncludes(text, "loadScript('./inline-script-0.js?source=%2Findex.html');");
expectIncludes(
text,
"System.import('./inline-script-1.js?source=%2Findex.html&systemjs=true');",
);
server.stop();
});

Expand All @@ -118,12 +148,11 @@ describe('legacyPlugin()', function () {
await fetchText(`${host}/index.html`, {
headers: { 'user-agent': legacyUserAgents['IE 11'] },
});
const text = await fetchText(`${host}/inline-script-0.js?source=%2Findex.html`, {
const text = await fetchText(`${host}/inline-script-1.js?source=%2Findex.html`, {
headers: { 'user-agent': legacyUserAgents['IE 11'] },
});
expectIncludes(text, 'System.register');
expectIncludes(text, 'var InlineClass;');
expectIncludes(text, 'function _classCallCheck(instance');
expectIncludes(text, 'var InlineClass =');
expectIncludes(text, '_classCallCheck(this, InlineClass);');
server.stop();
});

Expand Down
Loading