Skip to content

Commit 945df46

Browse files
fix(build): do not copy polyfills to the dist OT unless building es5 (#5725)
Prior to this change Stencil will copy polyfills to the `dist` output target whether or not the user has indicated they'll be necessary. The polyfills comprise two things: copying the polyfills themselves into the 'loader' path, and adding code to the lazy-loader entry points which loads those polyfills. Instead of just assuming that the user wants this, we now gate this behavior on whether `buildEs5` is set on the Stencil configuration. fixes #5416 STENCIL-1288
1 parent 43454bb commit 945df46

File tree

3 files changed

+122
-16
lines changed

3 files changed

+122
-16
lines changed

src/compiler/output-targets/dist-lazy/generate-esm.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,25 @@ export const generateEsm = async (
5858
'',
5959
);
6060

61-
await copyPolyfills(config, compilerCtx, esmOutputs);
61+
if (config.buildEs5) {
62+
await copyPolyfills(config, compilerCtx, esmOutputs);
63+
}
6264
await generateShortcuts(config, compilerCtx, outputTargets, output);
6365
}
6466
}
6567

6668
return { name: 'esm', buildCtx };
6769
};
6870

71+
/**
72+
* Copy polyfills from `$INSTALL_DIR/internal/client/polyfills` to the lazy
73+
* loader output directory where $INSTALL_DIR is the directory in which the
74+
* `@stencil/core` package is installed.
75+
*
76+
* @param config a validated Stencil configuration
77+
* @param compilerCtx the current compiler context
78+
* @param outputTargets dist-lazy output targets
79+
*/
6980
const copyPolyfills = async (
7081
config: d.ValidatedConfig,
7182
compilerCtx: d.CompilerCtx,

src/compiler/output-targets/output-lazy-loader.ts

+37-15
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,33 @@ const generateLoader = async (
4444
2,
4545
);
4646

47+
const polyfillsEntryPoint = join(es2017Dir, 'polyfills/index.js');
48+
const polyfillsExport = `export * from '${relative(loaderPath, polyfillsEntryPoint)}';`;
49+
4750
const es5EntryPoint = join(es5Dir, 'loader.js');
51+
const indexContent = filterAndJoin([
52+
generatePreamble(config),
53+
es5HtmlElement,
54+
config.buildEs5 ? polyfillsExport : null,
55+
`export * from '${relative(loaderPath, es5EntryPoint)}';`,
56+
]);
57+
4858
const es2017EntryPoint = join(es2017Dir, 'loader.js');
49-
const polyfillsEntryPoint = join(es2017Dir, 'polyfills/index.js');
59+
const indexES2017Content = filterAndJoin([
60+
generatePreamble(config),
61+
config.buildEs5 ? polyfillsExport : null,
62+
`export * from '${relative(loaderPath, es2017EntryPoint)}';`,
63+
]);
64+
5065
const cjsEntryPoint = join(cjsDir, 'loader.cjs.js');
51-
const polyfillsExport = `export * from '${relative(loaderPath, polyfillsEntryPoint)}';`;
52-
const indexContent = `${generatePreamble(config)}
53-
${es5HtmlElement}
54-
${polyfillsExport}
55-
export * from '${relative(loaderPath, es5EntryPoint)}';
56-
`;
57-
const indexES2017Content = `${generatePreamble(config)}
58-
${polyfillsExport}
59-
export * from '${relative(loaderPath, es2017EntryPoint)}';
60-
`;
61-
const indexCjsContent = `${generatePreamble(config)}
62-
module.exports = require('${relative(loaderPath, cjsEntryPoint)}');
63-
module.exports.applyPolyfills = function() { return Promise.resolve() };
64-
`;
66+
const indexCjsContent = filterAndJoin([
67+
generatePreamble(config),
68+
`module.exports = require('${relative(loaderPath, cjsEntryPoint)}');`,
69+
config.buildEs5 ? `module.exports.applyPolyfills = function() { return Promise.resolve() };` : null,
70+
]);
6571

6672
const indexDtsPath = join(loaderPath, 'index.d.ts');
73+
6774
await Promise.all([
6875
compilerCtx.fs.writeFile(join(loaderPath, 'package.json'), packageJsonContent),
6976
compilerCtx.fs.writeFile(join(loaderPath, 'index.d.ts'), generateIndexDts(indexDtsPath, outputTarget.componentDts)),
@@ -98,3 +105,18 @@ export declare function applyPolyfills(): Promise<void>;
98105
export declare function setNonce(nonce: string): void;
99106
`;
100107
};
108+
109+
/**
110+
* Given an array of 'parts' which can be assembled into a string 1) filter
111+
* out any parts that are `null` and 2) join the remaining strings into a single
112+
* output string
113+
*
114+
* @param parts an array of parts to filter and join
115+
* @returns the joined string
116+
*/
117+
function filterAndJoin(parts: (string | null)[]): string {
118+
return parts
119+
.filter((part) => part !== null)
120+
.join('\n')
121+
.trim();
122+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type * as d from '@stencil/core/declarations';
2+
import { mockBuildCtx, mockCompilerCtx, mockCompilerSystem, mockValidatedConfig } from '@stencil/core/testing';
3+
import { DIST, resolve } from '@utils';
4+
5+
import { validateDist } from '../../config/outputs/validate-dist';
6+
import { outputLazyLoader } from '../output-lazy-loader';
7+
8+
function setup(configOverrides: Partial<d.ValidatedConfig> = {}) {
9+
const sys = mockCompilerSystem();
10+
const config: d.ValidatedConfig = mockValidatedConfig({
11+
...configOverrides,
12+
configPath: '/testing-path',
13+
buildAppCore: true,
14+
namespace: 'TestApp',
15+
outputTargets: [
16+
{
17+
type: DIST,
18+
dir: 'my-test-dir',
19+
},
20+
],
21+
srcDir: '/src',
22+
sys,
23+
});
24+
25+
config.outputTargets = validateDist(config, config.outputTargets);
26+
27+
const compilerCtx = mockCompilerCtx(config);
28+
const writeFileSpy = jest.spyOn(compilerCtx.fs, 'writeFile');
29+
const buildCtx = mockBuildCtx(config, compilerCtx);
30+
31+
return { config, compilerCtx, buildCtx, writeFileSpy };
32+
}
33+
34+
describe('Lazy Loader Output Target', () => {
35+
let config: d.ValidatedConfig;
36+
let compilerCtx: d.CompilerCtx;
37+
let writeFileSpy: jest.SpyInstance;
38+
39+
afterEach(() => {
40+
writeFileSpy.mockRestore();
41+
});
42+
43+
it('should write code for initializing polyfills when buildEs5=true', async () => {
44+
({ config, compilerCtx, writeFileSpy } = setup({ buildEs5: true }));
45+
await outputLazyLoader(config, compilerCtx);
46+
47+
const expectedIndexOutput = `export * from '../esm/polyfills/index.js';
48+
export * from '../esm-es5/loader.js';`;
49+
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.js'), expectedIndexOutput);
50+
51+
const expectedCjsIndexOutput = `module.exports = require('../cjs/loader.cjs.js');
52+
module.exports.applyPolyfills = function() { return Promise.resolve() };`;
53+
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.cjs.js'), expectedCjsIndexOutput);
54+
55+
const expectedES2017Output = `export * from '../esm/polyfills/index.js';
56+
export * from '../esm/loader.js';`;
57+
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.es2017.js'), expectedES2017Output);
58+
});
59+
60+
it('should exclude polyfill code when buildEs5=false', async () => {
61+
({ config, compilerCtx, writeFileSpy } = setup({ buildEs5: false }));
62+
await outputLazyLoader(config, compilerCtx);
63+
64+
const expectedIndexOutput = `export * from '../esm/loader.js';`;
65+
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.js'), expectedIndexOutput);
66+
67+
const expectedCjsIndexOutput = `module.exports = require('../cjs/loader.cjs.js');`;
68+
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.cjs.js'), expectedCjsIndexOutput);
69+
70+
const expectedES2017Output = `export * from '../esm/loader.js';`;
71+
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.es2017.js'), expectedES2017Output);
72+
});
73+
});

0 commit comments

Comments
 (0)