Skip to content

Commit

Permalink
fix(runtime): only generate lazy build CSS when there are component t…
Browse files Browse the repository at this point in the history
…ags (#5305)

* fix(runtime): only generate lazy build CSS when there are component tags

This commit fixes an issue where invalid CSS could be generated and inserted into the DOM if `bootstrapLazy` was called with no component metadata or if no new components are registered in the custom element registry (i.e. it is called multiple times with the same metadata).

STENCIL-632

Closes: #3771

Co-authored-by: Robin Aldenhoven <raldenhoven@users.noreply.github.com>

* remove prehydration tests

This commit removes some "invisible prehydration" tests that no longer work based on changes in 2559917. They no longer work because `bootstrapLazy` is called with the same compiler metadata so styles are not re-inserted after being manually removed by calls to `tearDownStylesScripts` in the respective test files

* chore(karma): remove additional invisilbePrehydration infra

* mark todo

---------

Co-authored-by: Robin Aldenhoven <raldenhoven@users.noreply.github.com>
Co-authored-by: Ryan Waskiewicz <ryanwaskiewicz@gmail.com>
  • Loading branch information
3 people committed Jan 31, 2024
1 parent 9d9fe41 commit a0c1bd0
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 106 deletions.
42 changes: 23 additions & 19 deletions src/runtime/bootstrap-lazy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,29 +196,33 @@ export const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d.
});
});

// Add styles for `slot-fb` elements if any of our components are using slots outside the Shadow DOM
if (hasSlotRelocation) {
dataStyles.innerHTML += SLOT_FB_CSS;
}
// Only bother generating CSS if we have components
// TODO(STENCIL-1118): Add test cases for CSS content based on conditionals
if (cmpTags.length > 0) {
// Add styles for `slot-fb` elements if any of our components are using slots outside the Shadow DOM
if (hasSlotRelocation) {
dataStyles.innerHTML += SLOT_FB_CSS;
}

// Add hydration styles
if (BUILD.invisiblePrehydration && (BUILD.hydratedClass || BUILD.hydratedAttribute)) {
dataStyles.innerHTML += cmpTags + HYDRATED_CSS;
}
// Add hydration styles
if (BUILD.invisiblePrehydration && (BUILD.hydratedClass || BUILD.hydratedAttribute)) {
dataStyles.innerHTML += cmpTags + HYDRATED_CSS;
}

// If we have styles, add them to the DOM
if (dataStyles.innerHTML.length) {
dataStyles.setAttribute('data-styles', '');
// If we have styles, add them to the DOM
if (dataStyles.innerHTML.length) {
dataStyles.setAttribute('data-styles', '');

// Apply CSP nonce to the style tag if it exists
const nonce = plt.$nonce$ ?? queryNonceMetaTagContent(doc);
if (nonce != null) {
dataStyles.setAttribute('nonce', nonce);
}
// Apply CSP nonce to the style tag if it exists
const nonce = plt.$nonce$ ?? queryNonceMetaTagContent(doc);
if (nonce != null) {
dataStyles.setAttribute('nonce', nonce);
}

// Insert the styles into the document head
// NOTE: this _needs_ to happen last so we can ensure the nonce (and other attributes) are applied
head.insertBefore(dataStyles, metaCharset ? metaCharset.nextSibling : head.firstChild);
// Insert the styles into the document head
// NOTE: this _needs_ to happen last so we can ensure the nonce (and other attributes) are applied
head.insertBefore(dataStyles, metaCharset ? metaCharset.nextSibling : head.firstChild);
}
}

// Process deferred connectedCallbacks now all components have been registered
Expand Down
63 changes: 63 additions & 0 deletions src/runtime/test/bootstrap-lazy.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { doc } from '@platform';

import { LazyBundlesRuntimeData } from '../../internal';
import { bootstrapLazy } from '../bootstrap-lazy';

describe('bootstrap lazy', () => {
it('should not inject invalid CSS when no lazy bundles are provided', () => {
const spy = jest.spyOn(doc.head, 'insertBefore');

bootstrapLazy([]);

expect(spy).not.toHaveBeenCalledWith(
expect.objectContaining({
sheet: expect.objectContaining({
cssRules: [
expect.objectContaining({
// This html is not valid since it does not start with a selector for the visibility hidden block
cssText: '{visibility:hidden}.hydrated{visibility:inherit}',
}),
],
}),
}),
null,
);
});

it('should not inject invalid CSS when components are already in custom element registry', () => {
const spy = jest.spyOn(doc.head, 'insertBefore');

const lazyBundles: LazyBundlesRuntimeData = [
['my-component', [[0, 'my-component', { first: [1], middle: [1], last: [1] }]]],
];

bootstrapLazy(lazyBundles);
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
sheet: expect.objectContaining({
cssRules: [
expect.objectContaining({
cssText: 'my-component{visibility:hidden}.hydrated{visibility:inherit}',
}),
],
}),
}),
null,
);

bootstrapLazy(lazyBundles);
expect(spy).not.toHaveBeenCalledWith(
expect.objectContaining({
sheet: expect.objectContaining({
cssRules: [
expect.objectContaining({
// This html is not valid since it does not start with a selector for the visibility hidden block
cssText: '{visibility:hidden}.hydrated{visibility:inherit}',
}),
],
}),
}),
null,
);
});
});
5 changes: 1 addition & 4 deletions test/karma/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@
"scripts": {
"clean": "rm -rf test-output tmp-compiled-tests",
"start": "node ../../bin/stencil build --dev --watch --serve --es5",
"build.all": "npm run clean && npm run build.sibling && npm run build.invisible-prehydration && npm run build.app && npm run build.custom-elements && npm run karma.webpack && npm run build.prerender",
"build.all": "npm run clean && npm run build.sibling && npm run build.invisible-prehydration.false && npm run build.app && npm run build.custom-elements && npm run karma.webpack && npm run build.prerender",
"build.app": "npm run compile.test-app && node ../../bin/stencil build --debug --es5",
"compile.test-app": "node ../../node_modules/typescript/lib/tsc -p tsconfig.json",
"build.custom-elements": "webpack-cli --config test-app/custom-elements-output-webpack/webpack.config.js && webpack-cli --config test-app/custom-elements-output-tag-class-different/webpack.config.js && webpack-cli --config test-app/custom-elements-delegates-focus/webpack.config.js",
"build.invisible-prehydration": "npm run build.invisible-prehydration.default && npm run build.invisible-prehydration.true && npm run build.invisible-prehydration.false",
"build.invisible-prehydration.default": "node ../../bin/stencil build --config test-invisible-prehydration/stencil.config.ts --debug",
"build.invisible-prehydration.true": "node ../../bin/stencil build --config test-invisible-prehydration/stencil.invisiblePrehydrationTrue.config.ts --debug",
"build.invisible-prehydration.false": "node ../../bin/stencil build --config test-invisible-prehydration/stencil.invisiblePrehydrationFalse.config.ts --debug",
"build.prerender": "node ../../bin/stencil build --config test-prerender/stencil.config-prerender.ts --prerender --debug && node test-prerender/no-script-build.js",
"build.sibling": "node ../../bin/stencil build --config test-sibling/stencil.config.ts --debug",
Expand Down
6 changes: 0 additions & 6 deletions test/karma/test-app/invisible-prehydration-default/index.html

This file was deleted.

17 changes: 0 additions & 17 deletions test/karma/test-app/invisible-prehydration-default/karma.spec.ts

This file was deleted.

6 changes: 0 additions & 6 deletions test/karma/test-app/invisible-prehydration-true/index.html

This file was deleted.

17 changes: 0 additions & 17 deletions test/karma/test-app/invisible-prehydration-true/karma.spec.ts

This file was deleted.

4 changes: 0 additions & 4 deletions test/karma/test-app/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,6 @@ export function setupDomTests(document: Document): DomTestUtilities {
document.head.querySelectorAll('style[data-styles]').forEach((e) => e.remove());

[
'/build/testinvisibleprehydration.esm.js',
'/build/testinvisibleprehydration.js',
'/build/testprehydratedtruestyles.esm.js',
'/build/testprehydratedtruestyles.js',
'/build/testprehydratedfalsestyles.esm.js',
'/build/testprehydratedfalsestyles.js',
'/build/testapp.esm.js',
Expand Down
16 changes: 0 additions & 16 deletions test/karma/test-invisible-prehydration/stencil.config.ts

This file was deleted.

This file was deleted.

0 comments on commit a0c1bd0

Please sign in to comment.