Skip to content

Commit

Permalink
feat(ssr): add SSR compilation mode (#4685)
Browse files Browse the repository at this point in the history
* feat(ssr): add SSR compilation mode

* chore: avoid inadvertently transforming component-author code

* chore: add comment

Co-authored-by: Nolan Lawson <nlawson@salesforce.com>

* chore: add comment

Co-authored-by: Nolan Lawson <nlawson@salesforce.com>

* chore: remove commented code

* chore: use more specific regex to detect generateMarkup fns

Co-authored-by: Nolan Lawson <nlawson@salesforce.com>

* chore: remove unnecessary scope traveral option

* chore: split targetSSR and ssrMode config options

---------

Co-authored-by: Nolan Lawson <nlawson@salesforce.com>
  • Loading branch information
divmain and nolanlawson authored Oct 24, 2024
1 parent 3ee2b6d commit 1f4dd3d
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 27 deletions.
7 changes: 5 additions & 2 deletions packages/@lwc/compiler/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
import { InstrumentationObject, CompilerValidationErrors, invariant } from '@lwc/errors';
import { isUndefined, isBoolean, getAPIVersionFromNumber } from '@lwc/shared';
import { CompilationMode } from '@lwc/ssr-compiler';
import type { CustomRendererConfig } from '@lwc/template-compiler';

/**
Expand All @@ -31,7 +32,9 @@ const DEFAULT_OPTIONS = {
experimentalComplexExpressions: false,
disableSyntheticShadowSupport: false,
enableLightningWebSecurityTransforms: false,
};
targetSSR: false,
ssrMode: 'sync',
} as const;

const DEFAULT_DYNAMIC_IMPORT_CONFIG: Required<DynamicImportConfig> = {
loader: '',
Expand Down Expand Up @@ -129,6 +132,7 @@ export interface TransformOptions {
/** API version to associate with the compiled module. Values correspond to Salesforce platform releases. */
apiVersion?: number;
targetSSR?: boolean;
ssrMode?: CompilationMode;
}

type OptionalTransformKeys =
Expand Down Expand Up @@ -237,6 +241,5 @@ function normalizeOptions(options: TransformOptions): NormalizedTransformOptions
outputConfig,
experimentalDynamicComponent,
apiVersion,
targetSSR: !!options.targetSSR,
};
}
19 changes: 9 additions & 10 deletions packages/@lwc/compiler/src/transformers/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,32 +92,31 @@ function transformFile(
filename: string,
options: NormalizedTransformOptions
): TransformResult {
let transformer;

switch (path.extname(filename)) {
case '.html':
transformer = options.targetSSR ? compileTemplateForSSR : templateTransformer;
break;
if (options.targetSSR) {
return compileTemplateForSSR(src, filename, options, options.ssrMode);
}
return templateTransformer(src, filename, options);

case '.css':
transformer = styleTransform;
break;
return styleTransform(src, filename, options);

case '.tsx':
case '.jsx':
case '.ts':
case '.js':
case '.mts':
case '.mjs':
transformer = options.targetSSR ? compileComponentForSSR : scriptTransformer;
break;
if (options.targetSSR) {
return compileComponentForSSR(src, filename, options, options.ssrMode);
}
return scriptTransformer(src, filename, options);

default:
throw generateCompilerError(TransformerErrors.NO_AVAILABLE_TRANSFORMER, {
messageArgs: [filename],
origin: { filename },
});
}

return transformer(src, filename, options);
}
3 changes: 3 additions & 0 deletions packages/@lwc/rollup-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ import { transformSync, StylesheetConfig, DynamicImportConfig } from '@lwc/compi
import { resolveModule, ModuleRecord, RegistryType } from '@lwc/module-resolver';
import { APIVersion, getAPIVersionFromNumber } from '@lwc/shared';
import type { CompilerDiagnostic } from '@lwc/errors';
import type { CompilationMode } from '@lwc/ssr-compiler';

export interface RollupLwcOptions {
/** A boolean indicating whether to compile for SSR runtime target. */
targetSSR?: boolean;
/** The variety of SSR code that should be generated, one of 'sync', 'async', or 'asyncYield' */
ssrMode?: CompilationMode;
/** A [minimatch pattern](https://github.com/isaacs/minimatch), or array of patterns, which specifies the files in the build the plugin should transform on. By default all files are targeted. */
include?: FilterPattern;
/** A [minimatch pattern](https://github.com/isaacs/minimatch), or array of patterns, which specifies the files in the build the plugin should not transform. By default no files are ignored. */
Expand Down
7 changes: 6 additions & 1 deletion packages/@lwc/ssr-compiler/src/__tests__/fixtures.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import lwcRollupPlugin from '@lwc/rollup-plugin';
import { FeatureFlagName } from '@lwc/features/dist/types';
import { testFixtureDir, formatHTML } from '@lwc/test-utils-lwc-internals';
import { serverSideRenderComponent } from '@lwc/ssr-runtime';
import type { CompilationMode } from '../index';

interface FixtureModule {
tagName: string;
Expand All @@ -23,6 +24,8 @@ interface FixtureModule {

vi.setConfig({ testTimeout: 10_000 /* 10 seconds */ });

const SSR_MODE: CompilationMode = 'sync';

async function compileFixture({ input, dirname }: { input: string; dirname: string }) {
const modulesDir = path.resolve(dirname, './modules');
const outputFile = path.resolve(dirname, './dist/compiled-experimental-ssr.js');
Expand All @@ -35,6 +38,7 @@ async function compileFixture({ input, dirname }: { input: string; dirname: stri
plugins: [
lwcRollupPlugin({
targetSSR: true,
ssrMode: SSR_MODE,
enableDynamicComponents: true,
// TODO [#3331]: remove usage of lwc:dynamic in 246
experimentalDynamicDirective: true,
Expand Down Expand Up @@ -85,7 +89,8 @@ function testFixtures() {
result = await serverSideRenderComponent(
module!.tagName,
module!.generateMarkup,
config?.props ?? {}
config?.props ?? {},
SSR_MODE
);
} catch (err: any) {
return {
Expand Down
10 changes: 8 additions & 2 deletions packages/@lwc/ssr-compiler/src/compile-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import { traverse, builders as b, is } from 'estree-toolkit';
import { parseModule } from 'meriyah';
import { AriaPropNameToAttrNameMap } from '@lwc/shared';

import { transmogrify } from '../transmogrify';
import { replaceLwcImport } from './lwc-import';
import { catalogTmplImport } from './catalog-tmpls';
import { catalogStaticStylesheets, catalogStyleImport } from './stylesheets';
import { addGenerateMarkupExport } from './generate-markup';

import type { Identifier as EsIdentifier, Program as EsProgram } from 'estree';
import type { Visitors, ComponentMetaState } from './types';
import type { CompilationMode } from '../shared';

const visitors: Visitors = {
$: { scope: true },
Expand Down Expand Up @@ -112,8 +114,8 @@ const visitors: Visitors = {
},
};

export default function compileJS(src: string, filename: string) {
const ast = parseModule(src, {
export default function compileJS(src: string, filename: string, compilationMode: CompilationMode) {
let ast = parseModule(src, {
module: true,
next: true,
}) as EsProgram;
Expand Down Expand Up @@ -155,6 +157,10 @@ export default function compileJS(src: string, filename: string) {

addGenerateMarkupExport(ast, state, filename);

if (compilationMode === 'async' || compilationMode === 'sync') {
ast = transmogrify(ast, compilationMode);
}

return {
code: generate(ast, {}),
};
Expand Down
11 changes: 9 additions & 2 deletions packages/@lwc/ssr-compiler/src/compile-template/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ import { DiagnosticLevel } from '@lwc/errors';
import { esTemplate } from '../estemplate';
import { getStylesheetImports } from '../compile-js/stylesheets';
import { addScopeTokenDeclarations } from '../compile-js/stylesheet-scope-token';
import { transmogrify } from '../transmogrify';
import { optimizeAdjacentYieldStmts } from './shared';
import { templateIrToEsTree } from './ir-to-es';
import type {
ExportDefaultDeclaration as EsExportDefaultDeclaration,
ImportDeclaration as EsImportDeclaration,
} from 'estree';
import type { CompilationMode } from '../shared';

const bStyleValidationImport = esTemplate`
import { validateStyleTextContents } from '@lwc/ssr-runtime';
Expand Down Expand Up @@ -62,7 +64,8 @@ const bExportTemplate = esTemplate`
export default function compileTemplate(
src: string,
filename: string,
options: TemplateCompilerConfig
options: TemplateCompilerConfig,
compilationMode: CompilationMode
) {
const { root, warnings } = parse(src, {
// `options` is from @lwc/compiler, and may have flags that @lwc/template-compiler doesn't
Expand Down Expand Up @@ -110,13 +113,17 @@ export default function compileTemplate(
bStyleValidationImport(),
bExportTemplate(optimizeAdjacentYieldStmts(statements)),
];
const program = b.program(moduleBody, 'module');
let program = b.program(moduleBody, 'module');

addScopeTokenDeclarations(program, filename, options.namespace, options.name);

const stylesheetImports = getStylesheetImports(filename);
program.body.unshift(...stylesheetImports);

if (compilationMode === 'async' || compilationMode === 'sync') {
program = transmogrify(program, compilationMode);
}

return {
code: generate(program, {}),
};
Expand Down
14 changes: 9 additions & 5 deletions packages/@lwc/ssr-compiler/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,31 @@

import compileJS from './compile-js';
import compileTemplate from './compile-template';
import { TransformOptions } from './shared';
import type { CompilationMode, TransformOptions } from './shared';

export interface CompilationResult {
code: string;
map: unknown;
}

export type { CompilationMode };

export function compileComponentForSSR(
src: string,
filename: string,
_options: TransformOptions
_options: TransformOptions,
mode: CompilationMode = 'asyncYield'
): CompilationResult {
const { code } = compileJS(src, filename);
const { code } = compileJS(src, filename, mode);
return { code, map: undefined };
}

export function compileTemplateForSSR(
src: string,
filename: string,
options: TransformOptions
options: TransformOptions,
mode: CompilationMode = 'asyncYield'
): CompilationResult {
const { code } = compileTemplate(src, filename, options);
const { code } = compileTemplate(src, filename, options, mode);
return { code, map: undefined };
}
3 changes: 3 additions & 0 deletions packages/@lwc/ssr-compiler/src/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,6 @@ export interface IHoistInstantiation {
}

export type TransformOptions = Pick<TemplateCompilerConfig, 'name' | 'namespace'>;

/* SSR compilation mode. `async` refers to async functions, `sync` to sync functions, and `asyncYield` to async generator functions. */
export type CompilationMode = 'asyncYield' | 'async' | 'sync';
Loading

0 comments on commit 1f4dd3d

Please sign in to comment.