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

fix(build): do not copy polyfills to the dist OT unless building es5 #5725

Merged
merged 1 commit into from
May 7, 2024
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
13 changes: 12 additions & 1 deletion src/compiler/output-targets/dist-lazy/generate-esm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,25 @@ export const generateEsm = async (
'',
);

await copyPolyfills(config, compilerCtx, esmOutputs);
if (config.buildEs5) {
await copyPolyfills(config, compilerCtx, esmOutputs);
}
await generateShortcuts(config, compilerCtx, outputTargets, output);
}
}

return { name: 'esm', buildCtx };
};

/**
* Copy polyfills from `$INSTALL_DIR/internal/client/polyfills` to the lazy
* loader output directory where $INSTALL_DIR is the directory in which the
* `@stencil/core` package is installed.
*
* @param config a validated Stencil configuration
* @param compilerCtx the current compiler context
* @param outputTargets dist-lazy output targets
*/
const copyPolyfills = async (
config: d.ValidatedConfig,
compilerCtx: d.CompilerCtx,
Expand Down
52 changes: 37 additions & 15 deletions src/compiler/output-targets/output-lazy-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,26 +44,33 @@ const generateLoader = async (
2,
);

const polyfillsEntryPoint = join(es2017Dir, 'polyfills/index.js');
const polyfillsExport = `export * from '${relative(loaderPath, polyfillsEntryPoint)}';`;

const es5EntryPoint = join(es5Dir, 'loader.js');
const indexContent = filterAndJoin([
generatePreamble(config),
es5HtmlElement,
config.buildEs5 ? polyfillsExport : null,
`export * from '${relative(loaderPath, es5EntryPoint)}';`,
]);

const es2017EntryPoint = join(es2017Dir, 'loader.js');
const polyfillsEntryPoint = join(es2017Dir, 'polyfills/index.js');
const indexES2017Content = filterAndJoin([
generatePreamble(config),
config.buildEs5 ? polyfillsExport : null,
`export * from '${relative(loaderPath, es2017EntryPoint)}';`,
]);

const cjsEntryPoint = join(cjsDir, 'loader.cjs.js');
const polyfillsExport = `export * from '${relative(loaderPath, polyfillsEntryPoint)}';`;
const indexContent = `${generatePreamble(config)}
${es5HtmlElement}
${polyfillsExport}
export * from '${relative(loaderPath, es5EntryPoint)}';
`;
const indexES2017Content = `${generatePreamble(config)}
${polyfillsExport}
export * from '${relative(loaderPath, es2017EntryPoint)}';
`;
const indexCjsContent = `${generatePreamble(config)}
module.exports = require('${relative(loaderPath, cjsEntryPoint)}');
module.exports.applyPolyfills = function() { return Promise.resolve() };
`;
const indexCjsContent = filterAndJoin([
generatePreamble(config),
`module.exports = require('${relative(loaderPath, cjsEntryPoint)}');`,
config.buildEs5 ? `module.exports.applyPolyfills = function() { return Promise.resolve() };` : null,
]);

const indexDtsPath = join(loaderPath, 'index.d.ts');

await Promise.all([
compilerCtx.fs.writeFile(join(loaderPath, 'package.json'), packageJsonContent),
compilerCtx.fs.writeFile(join(loaderPath, 'index.d.ts'), generateIndexDts(indexDtsPath, outputTarget.componentDts)),
Expand Down Expand Up @@ -98,3 +105,18 @@ export declare function applyPolyfills(): Promise<void>;
export declare function setNonce(nonce: string): void;
`;
};

/**
* Given an array of 'parts' which can be assembled into a string 1) filter
* out any parts that are `null` and 2) join the remaining strings into a single
* output string
*
* @param parts an array of parts to filter and join
* @returns the joined string
*/
function filterAndJoin(parts: (string | null)[]): string {
return parts
.filter((part) => part !== null)
.join('\n')
.trim();
}
73 changes: 73 additions & 0 deletions src/compiler/output-targets/test/output-lazy-loader.spec.ts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a new spec file, we didn't previously have coverage for this file in particular

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type * as d from '@stencil/core/declarations';
import { mockBuildCtx, mockCompilerCtx, mockCompilerSystem, mockValidatedConfig } from '@stencil/core/testing';
import { DIST, resolve } from '@utils';

import { validateDist } from '../../config/outputs/validate-dist';
import { outputLazyLoader } from '../output-lazy-loader';

function setup(configOverrides: Partial<d.ValidatedConfig> = {}) {
const sys = mockCompilerSystem();
const config: d.ValidatedConfig = mockValidatedConfig({
...configOverrides,
configPath: '/testing-path',
buildAppCore: true,
namespace: 'TestApp',
outputTargets: [
{
type: DIST,
dir: 'my-test-dir',
},
],
srcDir: '/src',
sys,
});

config.outputTargets = validateDist(config, config.outputTargets);

const compilerCtx = mockCompilerCtx(config);
const writeFileSpy = jest.spyOn(compilerCtx.fs, 'writeFile');
const buildCtx = mockBuildCtx(config, compilerCtx);

return { config, compilerCtx, buildCtx, writeFileSpy };
}

describe('Lazy Loader Output Target', () => {
let config: d.ValidatedConfig;
let compilerCtx: d.CompilerCtx;
let writeFileSpy: jest.SpyInstance;

afterEach(() => {
writeFileSpy.mockRestore();
});

it('should write code for initializing polyfills when buildEs5=true', async () => {
({ config, compilerCtx, writeFileSpy } = setup({ buildEs5: true }));
await outputLazyLoader(config, compilerCtx);

const expectedIndexOutput = `export * from '../esm/polyfills/index.js';
export * from '../esm-es5/loader.js';`;
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.js'), expectedIndexOutput);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a little funny (the resolve call I mean) but I had to do this to get the tests passing on CI on Windows, you know, sometimes you gotta do what you gotta do


const expectedCjsIndexOutput = `module.exports = require('../cjs/loader.cjs.js');
module.exports.applyPolyfills = function() { return Promise.resolve() };`;
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.cjs.js'), expectedCjsIndexOutput);

const expectedES2017Output = `export * from '../esm/polyfills/index.js';
export * from '../esm/loader.js';`;
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.es2017.js'), expectedES2017Output);
});

it('should exclude polyfill code when buildEs5=false', async () => {
({ config, compilerCtx, writeFileSpy } = setup({ buildEs5: false }));
await outputLazyLoader(config, compilerCtx);

const expectedIndexOutput = `export * from '../esm/loader.js';`;
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.js'), expectedIndexOutput);

const expectedCjsIndexOutput = `module.exports = require('../cjs/loader.cjs.js');`;
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.cjs.js'), expectedCjsIndexOutput);

const expectedES2017Output = `export * from '../esm/loader.js';`;
expect(writeFileSpy).toHaveBeenCalledWith(resolve('/my-test-dir/loader/index.es2017.js'), expectedES2017Output);
});
});