Skip to content

Commit

Permalink
fix(hydrate): respect HydratedFlag configuration in hydrate script
Browse files Browse the repository at this point in the history
  • Loading branch information
khanhduy1407 committed Dec 1, 2024
1 parent f941626 commit fff9935
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 14 deletions.
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, RINDO_APP_DATA_ID, RINDO_APP_GLOBALS_ID } from '.
* @param config the Rindo 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 Rindo 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 '@rindo/core/declarations';
import { mockValidatedConfig } from '@rindo/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 { updateRindoCoreImports } from '../../transformers/update-rindo-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 Rindo 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 @@ -10,6 +10,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 Rindo 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 Rindo 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(RINDO-854): Remove code related to legacy shadowDomShim field
build.shadowDomShim = true;
build.hydratedAttribute = false;
build.hydratedClass = true;
// TODO(RINDO-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 '@rindo/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/rindo-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(RINDO-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

0 comments on commit fff9935

Please sign in to comment.