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(hydrate): respect HydratedFlag configuration in hydrate script #5741

Merged
merged 1 commit into from
May 15, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/compiler/app-core/app-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ export const updateBuildConditionals = (config: ValidatedConfig, b: BuildConditi
if (config.hydratedFlag) {
b.hydratedAttribute = config.hydratedFlag.selector === 'attribute';
b.hydratedClass = config.hydratedFlag.selector === 'class';
b.hydratedSelectorName = config.hydratedFlag.name;
} else {
b.hydratedAttribute = false;
b.hydratedClass = false;
Expand Down
18 changes: 11 additions & 7 deletions src/compiler/bundle/app-data-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import { APP_DATA_CONDITIONAL, STENCIL_APP_DATA_ID, STENCIL_APP_GLOBALS_ID } fro
* @param config the Stencil configuration for a particular project
* @param compilerCtx the current compiler context
* @param buildCtx the current build context
* @param build the set build conditionals for the build
* @param buildConditionals the set build conditionals for the build
* @param platform the platform that is being built
* @returns a Rollup plugin which carries out the necessary work
*/
export const appDataPlugin = (
config: d.ValidatedConfig,
compilerCtx: d.CompilerCtx,
buildCtx: d.BuildCtx,
build: d.BuildConditionals,
buildConditionals: d.BuildConditionals,
platform: 'client' | 'hydrate' | 'worker',
): Plugin => {
if (!platform) {
Expand Down Expand Up @@ -68,7 +68,7 @@ export const appDataPlugin = (
// build custom app-data based off of component metadata
const s = new MagicString(``);
appendNamespace(config, s);
appendBuildConditionals(config, build, s);
appendBuildConditionals(config, buildConditionals, s);
appendEnv(config, s);
return s.toString();
}
Expand Down Expand Up @@ -200,13 +200,17 @@ const appendGlobalScripts = (globalScripts: GlobalScript[], s: MagicString) => {
* **This function mutates the provided {@link MagicString} argument**
*
* @param config the configuration associated with the Stencil project
* @param build the build conditionals to serialize into a JS object
* @param buildConditionals the build conditionals to serialize into a JS object
* @param s a `MagicString` to append the generated constant onto
*/
const appendBuildConditionals = (config: d.ValidatedConfig, build: d.BuildConditionals, s: MagicString): void => {
const buildData = Object.keys(build)
export const appendBuildConditionals = (
config: d.ValidatedConfig,
buildConditionals: d.BuildConditionals,
s: MagicString,
): void => {
const buildData = Object.keys(buildConditionals)
.sort()
.map((key) => key + ': ' + ((build as any)[key] ? 'true' : 'false'))
.map((key) => key + ': ' + JSON.stringify((buildConditionals as any)[key]))
.join(', ');

s.append(`export const BUILD = /* ${config.fsNamespace} */ { ${buildData} };\n`);
Expand Down
46 changes: 46 additions & 0 deletions src/compiler/bundle/test/app-data-plugin.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as d from '@stencil/core/declarations';
import { mockValidatedConfig } from '@stencil/core/testing';
import MagicString from 'magic-string';

import { appendBuildConditionals } from '../app-data-plugin';

function setup() {
const config = mockValidatedConfig();
const magicString = new MagicString('');
return { config, magicString };
}

describe('app data plugin', () => {
it('should include the fsNamespace in the appended BUILD constant', () => {
const { config, magicString } = setup();
appendBuildConditionals(config, {}, magicString);
expect(magicString.toString().includes(`export const BUILD = /* ${config.fsNamespace} */`)).toBe(true);
});

it.each([true, false])('should include hydratedAttribute when %p', (hydratedAttribute) => {
const conditionals: d.BuildConditionals = {
hydratedAttribute,
};
const { config, magicString } = setup();
appendBuildConditionals(config, conditionals, magicString);
expect(magicString.toString().includes(`hydratedAttribute: ${String(hydratedAttribute)}`)).toBe(true);
});

it.each([true, false])('should include hydratedClass when %p', (hydratedClass) => {
const conditionals: d.BuildConditionals = {
hydratedClass,
};
const { config, magicString } = setup();
appendBuildConditionals(config, conditionals, magicString);
expect(magicString.toString().includes(`hydratedClass: ${String(hydratedClass)}`)).toBe(true);
});

it('should append hydratedSelectorName', () => {
const conditionals: d.BuildConditionals = {
hydratedSelectorName: 'boop',
};
const { config, magicString } = setup();
appendBuildConditionals(config, conditionals, magicString);
expect(magicString.toString().includes('hydratedSelectorName: "boop"')).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ import { rewriteAliasedSourceFileImportPaths } from '../../transformers/rewrite-
import { updateStencilCoreImports } from '../../transformers/update-stencil-core-import';
import { getHydrateBuildConditionals } from './hydrate-build-conditionals';

/**
* Marshall some Rollup options for the hydrate factory and then pass it to our
* {@link bundleOutput} helper
*
* @param config a validated Stencil configuration
* @param compilerCtx the current compiler context
* @param buildCtx the current build context
* @param appFactoryEntryCode an entry code for the app factory
* @returns a promise wrapping a rollup build object
*/
export const bundleHydrateFactory = async (
config: d.ValidatedConfig,
compilerCtx: d.CompilerCtx,
Expand All @@ -21,7 +31,7 @@ export const bundleHydrateFactory = async (
const bundleOpts: BundleOptions = {
id: 'hydrate',
platform: 'hydrate',
conditionals: getHydrateBuildConditionals(buildCtx.components),
conditionals: getHydrateBuildConditionals(config, buildCtx.components),
customBeforeTransformers: getCustomBeforeTransformers(config, compilerCtx),
inlineDynamicImports: true,
inputs: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ import { HYDRATE_FACTORY_INTRO, HYDRATE_FACTORY_OUTRO } from './hydrate-factory-
import { updateToHydrateComponents } from './update-to-hydrate-components';
import { writeHydrateOutputs } from './write-hydrate-outputs';

/**
* Generate and build the hydrate app and then write it to disk
*
* @param config a validated Stencil configuration
* @param compilerCtx the current compiler context
* @param buildCtx the current build context
* @param outputTargets the output targets for the current build
*/
export const generateHydrateApp = async (
config: d.ValidatedConfig,
compilerCtx: d.CompilerCtx,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import type * as d from '../../../declarations';
import { getBuildFeatures } from '../../app-core/app-data';
import { getBuildFeatures, updateBuildConditionals } from '../../app-core/app-data';

export const getHydrateBuildConditionals = (cmps: d.ComponentCompilerMeta[]) => {
/**
* Get the `BUILD` conditionals for the hydrate build based on the current
* project
*
* @param config a validated Stencil configuration
* @param cmps component metadata
* @returns a populated build conditional object
*/
export const getHydrateBuildConditionals = (config: d.ValidatedConfig, cmps: d.ComponentCompilerMeta[]) => {
const build = getBuildFeatures(cmps) as d.BuildConditionals;
// we need to make sure that things like the hydratedClass and flag are
// set for the hydrate build
updateBuildConditionals(config, build);

build.slotRelocation = true;
build.lazyLoad = true;
Expand Down Expand Up @@ -32,8 +43,6 @@ export const getHydrateBuildConditionals = (cmps: d.ComponentCompilerMeta[]) =>
build.cssAnnotations = true;
// TODO(STENCIL-854): Remove code related to legacy shadowDomShim field
build.shadowDomShim = true;
build.hydratedAttribute = false;
build.hydratedClass = true;
// TODO(STENCIL-1305): remove this option
build.scriptDataOpts = false;
build.attachStyles = true;
Expand Down
50 changes: 50 additions & 0 deletions src/compiler/output-targets/test/build-conditionals.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { mockConfig, mockLoadConfigInit } from '@stencil/core/testing';
import type * as d from '../../../declarations';
import { validateConfig } from '../../config/validate-config';
import { getCustomElementsBuildConditionals } from '../dist-custom-elements/custom-elements-build-conditionals';
import { getHydrateBuildConditionals } from '../dist-hydrate-script/hydrate-build-conditionals';
import { getLazyBuildConditionals } from '../dist-lazy/lazy-build-conditionals';

describe('build-conditionals', () => {
Expand Down Expand Up @@ -69,6 +70,15 @@ describe('build-conditionals', () => {
const bc = getCustomElementsBuildConditionals(config, cmps);
expect(bc.hydrateClientSide).toBe(true);
});

it('hydratedSelectorName', () => {
userConfig.hydratedFlag = {
name: 'boooop',
};
const { config } = validateConfig(userConfig, mockLoadConfigInit());
const bc = getCustomElementsBuildConditionals(config, cmps);
expect(bc.hydratedSelectorName).toBe('boooop');
});
});

describe('getLazyBuildConditionals', () => {
Expand Down Expand Up @@ -144,5 +154,45 @@ describe('build-conditionals', () => {
const bc = getLazyBuildConditionals(config, cmps);
expect(bc.hydrateClientSide).toBe(true);
});

it('hydratedSelectorName', () => {
userConfig.hydratedFlag = {
name: 'boooop',
};
const { config } = validateConfig(userConfig, mockLoadConfigInit());
const bc = getLazyBuildConditionals(config, cmps);
expect(bc.hydratedSelectorName).toBe('boooop');
});
});

describe('getHydrateBuildConditionals', () => {
it('hydratedSelectorName', () => {
userConfig.hydratedFlag = {
name: 'boooop',
};
const { config } = validateConfig(userConfig, mockLoadConfigInit());
const bc = getHydrateBuildConditionals(config, cmps);
expect(bc.hydratedSelectorName).toBe('boooop');
});

it('should allow setting to use a class for hydration', () => {
userConfig.hydratedFlag = {
selector: 'class',
};
const { config } = validateConfig(userConfig, mockLoadConfigInit());
const bc = getHydrateBuildConditionals(config, cmps);
expect(bc.hydratedClass).toBe(true);
expect(bc.hydratedAttribute).toBe(false);
});

it('should allow setting to use an attr for hydration', () => {
userConfig.hydratedFlag = {
selector: 'attribute',
};
const { config } = validateConfig(userConfig, mockLoadConfigInit());
const bc = getHydrateBuildConditionals(config, cmps);
expect(bc.hydratedClass).toBe(false);
expect(bc.hydratedAttribute).toBe(true);
});
});
});
1 change: 1 addition & 0 deletions src/declarations/stencil-private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ export interface BuildConditionals extends Partial<BuildFeatures> {
cloneNodeFix?: boolean;
hydratedAttribute?: boolean;
hydratedClass?: boolean;
hydratedSelectorName?: string;
initializeNextTick?: boolean;
// TODO(STENCIL-1305): remove this option
scriptDataOpts?: boolean;
Expand Down
10 changes: 8 additions & 2 deletions src/runtime/update-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,11 +456,17 @@ const emitLifecycleEvent = (elm: EventTarget, lifecycleName: string) => {
}
};

/**
* Set the hydrated flag on a DOM element
*
* @param elm a reference to a DOM element
* @returns undefined
*/
const addHydratedFlag = (elm: Element) =>
BUILD.hydratedClass
? elm.classList.add('hydrated')
? elm.classList.add(BUILD.hydratedSelectorName ?? 'hydrated')
: BUILD.hydratedAttribute
? elm.setAttribute('hydrated', '')
? elm.setAttribute(BUILD.hydratedSelectorName ?? 'hydrated', '')
: undefined;

const serverSideConnected = (elm: any) => {
Expand Down