mirror of
https://github.com/marko-js/marko.git
synced 2026-02-01 16:07:13 +00:00
feat: add hydrate option (#1673)
* feat: add hydrate, migrate and source output options Co-authored-by: Michael Rawlings <mirawlings@ebay.com>
This commit is contained in:
parent
4e0235419d
commit
a4e701355e
@ -174,7 +174,7 @@ export function loadFileForTag(tag) {
|
||||
if (sourceFileName) {
|
||||
return file.___getMarkoFile(
|
||||
fs.readFileSync(sourceFileName).toString("utf-8"),
|
||||
{ ...file.opts, sourceFileName, filename: sourceFileName },
|
||||
{ ...file.opts, sourceFileName },
|
||||
file.markoOpts
|
||||
);
|
||||
}
|
||||
@ -192,7 +192,7 @@ export function loadFileForImport(file, request) {
|
||||
);
|
||||
return file.___getMarkoFile(
|
||||
fs.readFileSync(sourceFileName).toString("utf-8"),
|
||||
{ ...file.opts, sourceFileName, filename: sourceFileName },
|
||||
{ ...file.opts, sourceFileName },
|
||||
file.markoOpts
|
||||
);
|
||||
}
|
||||
|
||||
31
packages/compiler/index.d.ts
vendored
31
packages/compiler/index.d.ts
vendored
@ -1,15 +1,32 @@
|
||||
import { SourceMap } from "magic-string";
|
||||
import { TaglibLookup } from "@marko/babel-utils";
|
||||
import { types } from "./src";
|
||||
|
||||
export * as types from "./babel-types";
|
||||
|
||||
type Dep = {
|
||||
type: string;
|
||||
code: string;
|
||||
path: string;
|
||||
startPos?: number;
|
||||
endPos?: number;
|
||||
require?: boolean;
|
||||
virtualPath?: string;
|
||||
[x: string]: unknown;
|
||||
};
|
||||
|
||||
export type Config = {
|
||||
output?: "html" | "dom";
|
||||
output?: "html" | "dom" | "hydrate" | "migrate" | "source";
|
||||
runtimeId?: string;
|
||||
ast?: boolean;
|
||||
code?: boolean;
|
||||
writeVersionComment?: boolean;
|
||||
ignoreUnrecognizedTags?: boolean;
|
||||
sourceMaps?: boolean;
|
||||
translator?: string;
|
||||
fileSystem?: typeof import("fs");
|
||||
modules?: "esm" | "cjs";
|
||||
resolveVirtualDependency?(sourceFileName: string, dep: { virtualPath: string, code: string, map?: SourceMap }): string;
|
||||
optimize?: boolean;
|
||||
cache?: Map<unknown, unknown>;
|
||||
babelConfig?: {
|
||||
@ -30,20 +47,14 @@ export type MarkoMeta = {
|
||||
tags?: string[];
|
||||
deps: Array<
|
||||
| string
|
||||
| {
|
||||
type: string;
|
||||
code: string;
|
||||
path: string;
|
||||
require?: boolean;
|
||||
virtualPath?: string;
|
||||
[x: string]: unknown;
|
||||
}
|
||||
| Dep
|
||||
>;
|
||||
};
|
||||
|
||||
export type CompileResult = {
|
||||
ast: types.File;
|
||||
code: string;
|
||||
map?: unknown;
|
||||
map: SourceMap;
|
||||
meta: MarkoMeta;
|
||||
};
|
||||
|
||||
|
||||
@ -46,6 +46,15 @@ export default (api, markoOpts) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
markoOpts.output === "hydrate" &&
|
||||
typeof markoOpts.resolveVirtualDependency !== "function"
|
||||
) {
|
||||
throw new Error(
|
||||
`@marko/compiler: the "resolveVirtualDependency" option must be supplied when output is "hydrate".`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
name: "marko",
|
||||
parserOverride(code, jsParseOptions) {
|
||||
@ -55,23 +64,25 @@ export default (api, markoOpts) => {
|
||||
return finalAst;
|
||||
},
|
||||
pre(file) {
|
||||
if (markoOpts.output === "source" || markoOpts.output === "migrate") {
|
||||
return file;
|
||||
}
|
||||
|
||||
const { ast, metadata } = file;
|
||||
const sourceFile = SOURCE_FILES.get(ast);
|
||||
metadata.marko = shallowClone(sourceFile.metadata.marko);
|
||||
|
||||
if (markoOpts._translate !== false) {
|
||||
const { buildCodeFrameError } = file;
|
||||
const { buildError } = file.hub;
|
||||
file.buildCodeFrameError = MarkoFile.prototype.buildCodeFrameError;
|
||||
file.hub.buildError = file.buildCodeFrameError.bind(file);
|
||||
file.markoOpts = markoOpts;
|
||||
file.___taglibLookup = sourceFile.___taglibLookup;
|
||||
file.___getMarkoFile = getMarkoFile;
|
||||
traverseAll(file, translator.translate);
|
||||
file.buildCodeFrameError = buildCodeFrameError;
|
||||
file.hub.buildError = buildError;
|
||||
file.markoOpts = file.___taglibLookup = file.___getMarkoFile = undefined;
|
||||
}
|
||||
const { buildCodeFrameError } = file;
|
||||
const { buildError } = file.hub;
|
||||
file.buildCodeFrameError = MarkoFile.prototype.buildCodeFrameError;
|
||||
file.hub.buildError = file.buildCodeFrameError.bind(file);
|
||||
file.markoOpts = markoOpts;
|
||||
file.___taglibLookup = sourceFile.___taglibLookup;
|
||||
file.___getMarkoFile = getMarkoFile;
|
||||
traverseAll(file, translator.translate);
|
||||
file.buildCodeFrameError = buildCodeFrameError;
|
||||
file.hub.buildError = buildError;
|
||||
file.markoOpts = file.___taglibLookup = file.___getMarkoFile = undefined;
|
||||
|
||||
metadata.marko.watchFiles = metadata.marko.watchFiles.filter(unique);
|
||||
}
|
||||
@ -86,15 +97,15 @@ export function getMarkoFile(code, jsParseOptions, markoOpts) {
|
||||
markoOpts.cache.set(translator, (compileCache = new Map()));
|
||||
}
|
||||
|
||||
const filename = jsParseOptions.sourceFileName;
|
||||
const id = getTemplateId(markoOpts.optimize, filename);
|
||||
const contentHash = createHash("MD5").update(code).digest("hex");
|
||||
const cacheKey = createHash("MD5")
|
||||
.update(id)
|
||||
.update(markoOpts.migrate ? "\0migrate" : "")
|
||||
.digest("hex");
|
||||
const { sourceFileName } = jsParseOptions;
|
||||
const isSource = markoOpts.output === "source";
|
||||
const isMigrate = markoOpts.output === "migrate";
|
||||
const canCache = !(isSource || isMigrate);
|
||||
const id = getTemplateId(markoOpts.optimize, sourceFileName);
|
||||
const contentHash = canCache && createHash("MD5").update(code).digest("hex");
|
||||
const cacheKey = canCache && createHash("MD5").update(id).digest("hex");
|
||||
|
||||
let cached = compileCache.get(cacheKey);
|
||||
let cached = canCache && compileCache.get(cacheKey);
|
||||
|
||||
if (cached) {
|
||||
if (cached.contentHash !== contentHash) {
|
||||
@ -121,7 +132,7 @@ export function getMarkoFile(code, jsParseOptions, markoOpts) {
|
||||
return cached.file;
|
||||
}
|
||||
|
||||
const taglibLookup = buildLookup(path.dirname(filename), translator);
|
||||
const taglibLookup = buildLookup(path.dirname(sourceFileName), translator);
|
||||
|
||||
const file = new MarkoFile(jsParseOptions, {
|
||||
code,
|
||||
@ -159,6 +170,11 @@ export function getMarkoFile(code, jsParseOptions, markoOpts) {
|
||||
};
|
||||
|
||||
parseMarko(file);
|
||||
|
||||
if (isSource) {
|
||||
return file;
|
||||
}
|
||||
|
||||
file.path.scope.crawl(); // Initialize bindings.
|
||||
|
||||
for (const id in taglibLookup.taglibsById) {
|
||||
@ -170,13 +186,18 @@ export function getMarkoFile(code, jsParseOptions, markoOpts) {
|
||||
}
|
||||
}
|
||||
|
||||
traverseAll(file, rootMigrators);
|
||||
|
||||
if (isMigrate) {
|
||||
return file;
|
||||
}
|
||||
|
||||
for (const { path: transformerPath } of taglibLookup.merged.transformers) {
|
||||
const mod = markoModules.require(transformerPath);
|
||||
meta.watchFiles.push(transformerPath);
|
||||
rootTransformers.push(mod.default || mod);
|
||||
}
|
||||
|
||||
traverseAll(file, rootMigrators);
|
||||
traverseAll(file, rootTransformers);
|
||||
|
||||
for (const taglibId in taglibLookup.taglibsById) {
|
||||
|
||||
@ -13,6 +13,15 @@ if (globalThis[MARKO_CONFIG_KEY]) {
|
||||
// The default output mode for compiled templates
|
||||
output: "html",
|
||||
|
||||
// Override the runtimeid used when calling `marko/components.init` in the `hydrate` output.
|
||||
runtimeId: undefined,
|
||||
|
||||
// Have Marko provide the final AST in the compile result.
|
||||
ast: false,
|
||||
|
||||
// Set the false to have Marko not generate the final code string, useful if just reading metadata or AST.
|
||||
code: true,
|
||||
|
||||
/**
|
||||
* Whether the version should be written to the template as a comment e.g.
|
||||
* // Compiled using marko@x.x.x - DO NOT EDIT
|
||||
@ -108,6 +117,13 @@ if (globalThis[MARKO_CONFIG_KEY]) {
|
||||
*/
|
||||
optimize: undefined,
|
||||
|
||||
/**
|
||||
* This option should be set if `hydrate` output is specified.
|
||||
* Maps a virtual dependency to a resolved file which can be implemented
|
||||
* for specific bundlers.
|
||||
*/
|
||||
resolveVirtualDependency: undefined,
|
||||
|
||||
/**
|
||||
* Compiling a Marko template may require other (used) Marko templates to compile.
|
||||
* To prevent compiling templates more than once, most of the compilation is cached.
|
||||
|
||||
@ -45,11 +45,13 @@ function loadBabelConfig(filename, config) {
|
||||
const markoConfig = { ...globalConfig, ...config, babelConfig: undefined };
|
||||
const requiredPlugins = [[corePlugin, markoConfig]];
|
||||
const baseBabelConfig = {
|
||||
filename: filename,
|
||||
...(config && config.babelConfig),
|
||||
filename,
|
||||
sourceFileName: filename,
|
||||
sourceType: "module",
|
||||
sourceMaps: markoConfig.sourceMaps,
|
||||
...(config && config.babelConfig)
|
||||
code: markoConfig.code,
|
||||
ast: markoConfig.ast
|
||||
};
|
||||
|
||||
if (markoConfig.modules === "cjs") {
|
||||
@ -68,11 +70,12 @@ function loadBabelConfig(filename, config) {
|
||||
|
||||
function buildResult(babelResult) {
|
||||
const {
|
||||
ast,
|
||||
map,
|
||||
code,
|
||||
metadata: { marko: meta }
|
||||
} = babelResult;
|
||||
return { map, code, meta };
|
||||
return { ast, map, code, meta };
|
||||
}
|
||||
|
||||
let scheduledClear = false;
|
||||
|
||||
@ -20,7 +20,13 @@ fs.readdirSync(path.join(__dirname, "../../"))
|
||||
output: "dom",
|
||||
optimize: true
|
||||
}),
|
||||
generated: runTest({ _translate: false })
|
||||
generated: runTest({ output: "migrate" }),
|
||||
hydrate: runTest({
|
||||
output: "hydrate",
|
||||
resolveVirtualDependency(from, { virtualPath }) {
|
||||
return virtualPath;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
function runTest(config) {
|
||||
|
||||
@ -1,45 +1,48 @@
|
||||
# Compiler
|
||||
|
||||
The Marko compiler tries its best to get out of your way and for the most part you will only see references to it in the various Marko ecosystem plugins for tools like webpack, Rollup, and others.
|
||||
|
||||
The compiler also provides a series of hooks you can tap into to bend the Marko language to your will.
|
||||
|
||||
> **Note:**
|
||||
> It is best to use existing official plugins, and the standard tag library when possible.
|
||||
> The compiler is an advanced API intended for integrating with build tools (webpack, rollup, etc.) and experimenting with new language features in userland. It's best to use existing official plugins and the standard tag library when possible.
|
||||
|
||||
## Compile API
|
||||
|
||||
The compile API is relatively straightforward and always you to take any Marko file and turn it into executable JavaScript.
|
||||
### Compile Functions
|
||||
|
||||
The compile functions take an input Marko template [`CompileOptions`](#options)and produce a `CompileResult` containing the executable JavaScript:
|
||||
|
||||
```ts
|
||||
import * as compiler from "@marko/compiler";
|
||||
|
||||
type CompileOptions = typeof import("@marko/compiler/src/config.js");
|
||||
|
||||
type CompileResult = {
|
||||
meta: Record<string, unknown>; // Meta data gathered while compiling.
|
||||
map?: SourceMap; // A sourcemap.
|
||||
code: string; // The translated code.
|
||||
meta: Record<string, unknown>; // Meta data gathered while compiling
|
||||
map?: SourceMap; // A sourcemap
|
||||
code: string; // The translated code
|
||||
};
|
||||
```
|
||||
|
||||
### `compiler.configure(options: CompileOptions)`
|
||||
#### `compiler.compileFile(filename: string, options?: CompileOptions): Promise<CompileResult>`
|
||||
|
||||
The `configure` API will override the default compiler options. For the list of options (applicable to all `compile*` functions) [see the source code](https://github.com/marko-js/marko/tree/master/packages/compiler/src/config.js).
|
||||
#### `compiler.compileFileSync(filename: string, options?: CompileOptions): CompileResult`
|
||||
|
||||
`compileFile` and `compileFileSync` load the source template at `filename` from disk and translate it into JavaScript.
|
||||
|
||||
```js
|
||||
compiler.configure({ output: "dom" });
|
||||
import * as compiler from "@marko/compiler";
|
||||
|
||||
const asyncResult = await compiler.compileFile("./src/index.marko", {
|
||||
modules: "cjs"
|
||||
});
|
||||
const syncResult = compiler.compileFileSync("./src/index.marko", {
|
||||
modules: "cjs"
|
||||
});
|
||||
```
|
||||
|
||||
### `compiler.compile(src: string, filename: string, options?: CompileOptions): Promise<CompileResult>`
|
||||
#### `compiler.compile(src: string, filename: string, options?: CompileOptions): Promise<CompileResult>`
|
||||
|
||||
### `compiler.compileSync(src: string, filename: string, options?: CompileOptions): CompileResult`
|
||||
#### `compiler.compileSync(src: string, filename: string, options?: CompileOptions): CompileResult`
|
||||
|
||||
Both the `compile` and `compileSync` APIs will translate the provided Marko source code into JavaScript.
|
||||
The only difference between the two (as the names likely suggest) is that `compile` will use async APIs under the hood while `compileSync`
|
||||
will use sync APIs.
|
||||
`compile` and `compileSync` allow passing the source template as a string rather than loading from disk. The `filename` location is used for resolving taglibs and imports, but does not have to actually exist on disk.
|
||||
|
||||
```js
|
||||
import * as compiler from "@marko/compiler";
|
||||
|
||||
const asyncResult = await compiler.compile(
|
||||
"<h1>Hello!</>",
|
||||
"./src/index.marko",
|
||||
@ -50,22 +53,210 @@ const syncResult = compiler.compileSync("<h1>Hello!</>", "./src/index.marko", {
|
||||
});
|
||||
```
|
||||
|
||||
### `compiler.compileFile(filename: string, options?: CompileOptions): Promise<CompileResult>`
|
||||
### Options
|
||||
|
||||
### `compiler.compileFileSync(filename: string, options?: CompileOptions): CompileResult`
|
||||
|
||||
`compileFile` and `compileFileSync` act the same as their counterparts `compile` and `compileSync` with the exception being that you do not
|
||||
need to pass in the source content. Instead, these APIs will load the file from disk for you automatically.
|
||||
Configuration options may be passed when calling the above compile functions or the compiler may be configured globally, overriding the default compiler options:
|
||||
|
||||
```js
|
||||
const asyncResult = await compiler.compileFile("./src/index.marko", {
|
||||
modules: "cjs"
|
||||
});
|
||||
const syncResult = compiler.compileFileSync("./src/index.marko", {
|
||||
modules: "cjs"
|
||||
});
|
||||
import * as compiler from "@marko/compiler";
|
||||
compiler.configure({ output: "dom" });
|
||||
```
|
||||
|
||||
#### `output`
|
||||
|
||||
Type: `string`<br>
|
||||
Default: `"html"`
|
||||
|
||||
- `"html"` - compiles the template to JavaScript that generates HTML strings.
|
||||
- `"dom"` - compiles the template to JavaScript that generates DOM nodes.
|
||||
- `"hydrate"` - similar to DOM, but only includes the assets & components needed in the browser, assuming the page was rendered on the server.
|
||||
- `"migrate"` - only runs migrations (not transforms or translation) and returns the migrated template code.
|
||||
- `"source"` - parses Marko file without running any migrations / transforms. (useful with `ast: true`)
|
||||
|
||||
When using output `dom` or `hydrate`, you should also specify a [`resolveVirtualDependency`](#resolvevirtualdependency) function.
|
||||
|
||||
#### `code`
|
||||
|
||||
Type: `boolean`<br>
|
||||
Default: true
|
||||
|
||||
If set to false, Marko will not generate the compiled source code string.
|
||||
|
||||
#### `ast`
|
||||
|
||||
Type: `boolean`<br>
|
||||
Default: false
|
||||
|
||||
Set to true to have the compiler provide the `ast` in it's output.
|
||||
|
||||
#### `runtimeId`
|
||||
|
||||
Type: `string`<br>
|
||||
Default: undefined
|
||||
|
||||
Optionally use to override the runtime id (used to differentiate multiple copies of Marko on the same page) passed to `marko/components.init(runtimeId)` when compiling in the `hydrate` output.
|
||||
|
||||
#### `writeVersionComment`
|
||||
|
||||
Type: `boolean`<br>
|
||||
Default: `true`
|
||||
|
||||
Whether the version should be written to the template as a comment e.g.
|
||||
|
||||
```js
|
||||
// Compiled using marko@x.x.x - DO NOT EDIT
|
||||
```
|
||||
|
||||
#### `ignoreUnrecognizedTags`
|
||||
|
||||
Type: `boolean`<br>
|
||||
Default: `false`
|
||||
|
||||
Whether unrecognized tags should be silently ignored rather than throwing a compile error. The the ignored tag will be output as a native element. Some test setups use this alongside `@marko/compiler/taglib`'s `excludeDir` and `excludePackage` to simulate "shallow" rendering.
|
||||
|
||||
#### `sourceMaps`
|
||||
|
||||
Type: `boolean` or `string`<br>
|
||||
Default: `false`
|
||||
|
||||
Whether source maps should be output with the compiled templates.
|
||||
|
||||
- When `true` a `map` property will be available on the compile result.
|
||||
- When `"inline"` the sourcemap will be inlined as a comment in the output code.
|
||||
- When `"both"` both of the above will be used.
|
||||
|
||||
#### `meta`
|
||||
|
||||
Type: `boolean`<br>
|
||||
Default: `false,
|
||||
|
||||
_Deprecated_. This option inlines the metadata in the output Javascript code. Metadata should be accessed instead from the `CompileResult`.
|
||||
|
||||
#### `fileSystem`
|
||||
|
||||
Type: typeof [`fs`](https://nodejs.org/api/fs.html) (specifically read APIs)<br>
|
||||
Default: Cached `fs`
|
||||
|
||||
Use a different file system object (eg. webpack's [CachedInputFileSystem](https://github.com/webpack/enhanced-resolve/blob/f08fe3f1a22c90c722eca14b38a9300ad00c62e8/lib/CachedInputFileSystem.js) or [`arc-fs`](https://github.com/eBay/arc/tree/master/packages/arc-fs))
|
||||
|
||||
#### `modules`
|
||||
|
||||
Type: `string` (`"esm"` or `"cjs"`)<br>
|
||||
Default: `"esm"`
|
||||
|
||||
By default Marko outputs ES Modules, you can optionally specify commonjs.
|
||||
|
||||
#### `optimize`
|
||||
|
||||
Type: `boolean`<br>
|
||||
Default: [environment based](https://github.com/marko-js/marko/blob/0f212897d2d3ec30b12c2f18ba950818bccb83b4/packages/compiler/src/babel-plugin/index.js#L277-L284) (`false` in development, `true` in production)
|
||||
|
||||
Enables production mode optimizations
|
||||
|
||||
#### `resolveVirtualDependency`
|
||||
|
||||
Type:
|
||||
|
||||
```ts
|
||||
(
|
||||
sourceFileName: string,
|
||||
dep: {
|
||||
code: string;
|
||||
virtualPath: string;
|
||||
map?: SourceMap;
|
||||
}
|
||||
) => string;
|
||||
```
|
||||
|
||||
Default: `undefined`
|
||||
|
||||
This option should be set when `dom` or `hydrate` output is specified. Since Marko templates can represent multiple output files (eg. JS renderer, CSS styles), we need to be able to treat a single source `.marko` file as multiple virtual files.
|
||||
|
||||
Different build tools have different mechanisms for handling virtual files. You should pass a function that returns a virtual path that can be handled by your build tool.
|
||||
|
||||
##### Example based on `@marko/webpack/loader`:
|
||||
|
||||
```js
|
||||
// lookup is shared between resolveVirtualDependency and markoLoader
|
||||
const virtualSources = new Map();
|
||||
|
||||
function resolveVirtualDependency(sourceFileName, { virtualPath, code, map }) {
|
||||
const virtualSourceFileName = `${sourceFileName}?virtual=${virtualPath}`;
|
||||
|
||||
// Add the virtual source to the lookup
|
||||
// to be later accessed by the loader
|
||||
virtualSources.set(virtualSourceFileName, { code, map });
|
||||
|
||||
// Generate the webpack path, from right to left...
|
||||
// 1. Pass the virtualSourceFileName so webpack can find the real file
|
||||
// located at sourceFilename, but the virtualPath is also present
|
||||
// (eg. "./index.marko?virtual=./index.marko.css")
|
||||
// 2. Use an inline loader to run this file through @marko/webpack/loader
|
||||
// https://webpack.js.org/concepts/loaders/#inline
|
||||
// 3. Use an inline matchResource to redefine this as the virtualPath
|
||||
// which allows the appropriate loaders to match the virtual dependency
|
||||
// https://webpack.js.org/api/loaders/#inline-matchresource
|
||||
return `${virtualPath}!=!@marko/webpack/loader!${virtualSourceFileName}`;
|
||||
}
|
||||
|
||||
export default function markoLoader(source) {
|
||||
let code, map;
|
||||
|
||||
if (virtualSources.has(this.resource)) {
|
||||
// If the resource has a ?virtual query param, we should
|
||||
// find it in the lookup and then return the virtual code
|
||||
// rather than performing the normal compilation
|
||||
{ code, map } = virtualSources.get(this.resource);
|
||||
virtualSources.delete(this.resource);
|
||||
} else {
|
||||
// The default behavior is to compile the template in dom output mode
|
||||
{ code, map } = markoCompiler.compileSync(source, this.resourcePath, {
|
||||
output: "dom",
|
||||
resolveVirtualDependency
|
||||
});
|
||||
}
|
||||
|
||||
return this.callback(null, code, map);
|
||||
}
|
||||
```
|
||||
|
||||
#### `cache`
|
||||
|
||||
Type: typeof [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) (specifically, `get` is required)<br>
|
||||
Default: `new Map()`
|
||||
|
||||
Compiling a Marko template may require other (used) Marko templates to compile.
|
||||
To prevent compiling templates more than once, most of the compilation is cached.
|
||||
|
||||
The default cache strategy is to clear the cache on every macrotask.
|
||||
If the default cache is overwritten it is up to the user to determine when the
|
||||
cache is cleared.
|
||||
|
||||
#### `babelConfig`
|
||||
|
||||
Type: see [babel options](https://babeljs.io/docs/en/options)<br>
|
||||
Default: babel defaults, plus
|
||||
|
||||
```js
|
||||
{
|
||||
filename,
|
||||
sourceFileName: filename,
|
||||
sourceType: "module",
|
||||
sourceMaps: config.sourceMaps
|
||||
}
|
||||
```
|
||||
|
||||
#### `translator`
|
||||
|
||||
Type: `{ analyze: Visitor, transform:Visitor }`<br>
|
||||
Default: [autodiscovers](https://github.com/marko-js/marko/blob/0f212897d2d3ec30b12c2f18ba950818bccb83b4/packages/compiler/src/config.js#L46-L89) a translator package starting with `@marko/translator-` or `marko-translator-`
|
||||
|
||||
The translator is a collection of transforms that translates the Marko AST into a valid JavaScript AST based on the `output` option. There is a default translator that ships with Marko, but this option may be used to switch to experimental translators for alternate runtimes.
|
||||
|
||||
The translator is an object with two [Babel Visitors](https://github.com/jamiebuilds/babel-handbook/blob/master/translations/en/plugin-handbook.md#visitors): `analyze` and `transform`. The result of the analyze visitor is cached and may be requested by other templates. The transform visitor transforms the AST to it's final JavaScript AST.
|
||||
|
||||
See [`@marko/translator-default`](https://github.com/marko-js/marko/blob/11a10f82cdb5389880e6deca5f77d17727acb831/packages/translator-default/src/index.js) for a reference implementation.
|
||||
|
||||
## Hooks
|
||||
|
||||

|
||||
@ -80,8 +271,8 @@ The hook will also receive a `types` object that matches the [@babel/types](http
|
||||
Here is an example hook:
|
||||
|
||||
```js
|
||||
module.exports = (tag, t) => {
|
||||
if (t.isStringLiteral(tag.node.name)) {
|
||||
module.exports = (tag, types) => {
|
||||
if (types.isStringLiteral(tag.node.name)) {
|
||||
console.log(`Found a tag called ${tag.node.name.value}`);
|
||||
tag.remove();
|
||||
}
|
||||
@ -137,6 +328,9 @@ These migrations run automatically in the background and can be written to disk
|
||||
|
||||
To hook into the `migrate` stage you can use the `migrate` option in the `marko.json` file.
|
||||
|
||||
> **Note:**
|
||||
> To make the compiler to stop at this point and output the migrated template rather than continuing on to produce the JavaScript output, pass `"migrate"` as the value for the `output` compilation option.
|
||||
|
||||
### Transform
|
||||
|
||||
The transform stage of the compiler is meant for userland transformations of Marko code, into other Marko code. Think of it like [babel.transform](https://babeljs.io/docs/en/babel-core#transform) for Marko templates.
|
||||
@ -156,5 +350,17 @@ The [`@marko/babel-utils`](https://github.com/marko-js/marko/tree/master/package
|
||||
|
||||
## Marko AST
|
||||
|
||||
You can check out the AST extensions that Marko makes [in the source code](https://github.com/marko-js/marko/tree/master/packages/compiler/src/babel-types/types/definitions.js).
|
||||
For AST creation and assertion utilities you can also import Marko's superset of `@babel/types` through the compiler via `import { types } from "@marko/compiler"`.
|
||||
Marko extends Babel's AST types adding nodes for `MarkoTag`, `MarkoAttribute`, etc.
|
||||
For AST creation and assertion utilities you can import Marko's superset of `@babel/types` through the compiler:
|
||||
|
||||
```js
|
||||
import { types } from "@marko/compiler";
|
||||
```
|
||||
|
||||
The [`@babel/types` documentation](https://babeljs.io/docs/en/babel-types) shows all the utility methods available for the Babel AST nodes. When importing `types` from `@marko/compiler` you get the same types of utilities for the Marko nodes as well (`types.markoTag`, `types.isMarkoTag`, `types.assertMarkoTag`, etc.).
|
||||
|
||||
For a full list of definitions, view the source code for Babel and Marko:
|
||||
|
||||
- [Babel's Core Definitions](https://github.com/babel/babel/blob/master/packages/babel-types/src/definitions/core.js)
|
||||
- [Babel's Extended Definitions](https://github.com/babel/babel/tree/master/packages/babel-types/src/definitions)
|
||||
- [Marko's Definitions](https://github.com/marko-js/marko/blob/master/packages/compiler/src/babel-types/types/definitions.js)
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"@marko/babel-utils": "^5.4.2",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"magic-string": "^0.25.7",
|
||||
"self-closing-tags": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { resolve } from "path";
|
||||
import { types as t } from "@marko/compiler";
|
||||
import {
|
||||
parseExpression,
|
||||
@ -11,7 +12,8 @@ import {
|
||||
isDynamicTag,
|
||||
isAttributeTag,
|
||||
loadFileForTag,
|
||||
findParentTag
|
||||
findParentTag,
|
||||
getTagDef
|
||||
} from "@marko/babel-utils";
|
||||
import { version } from "marko/package.json";
|
||||
import MarkoDocumentType from "./document-type";
|
||||
@ -26,18 +28,87 @@ import MarkoClass from "./class";
|
||||
import { analyzeStaticVDOM } from "./util/optimize-vdom-create";
|
||||
import { optimizeHTMLWrites } from "./util/optimize-html-writes";
|
||||
import getComponentFiles from "./util/get-component-files";
|
||||
import addDependencies from "./util/add-dependencies";
|
||||
|
||||
export { default as taglibs } from "./taglib";
|
||||
|
||||
export const analyze = {
|
||||
Program(program) {
|
||||
// Pre populate metadata for component files.
|
||||
getComponentFiles(program);
|
||||
Program: {
|
||||
enter(program) {
|
||||
// Pre populate metadata for component files.
|
||||
getComponentFiles(program);
|
||||
},
|
||||
exit(program) {
|
||||
const { file } = program.hub;
|
||||
const meta = file.metadata.marko;
|
||||
const {
|
||||
styleFile,
|
||||
packageFile,
|
||||
componentBrowserFile
|
||||
} = getComponentFiles(program);
|
||||
|
||||
if (packageFile) {
|
||||
meta.deps.unshift(`package: ${packageFile}`);
|
||||
}
|
||||
|
||||
if (styleFile) {
|
||||
meta.deps.unshift(styleFile);
|
||||
}
|
||||
|
||||
if (meta.hasComponentBrowser) {
|
||||
meta.component = componentBrowserFile;
|
||||
} else if (meta.hasComponent || meta.hasStatefulTagParams) {
|
||||
meta.component = file.opts.sourceFileName;
|
||||
}
|
||||
|
||||
meta.component =
|
||||
meta.component && resolveRelativePath(file, meta.component);
|
||||
meta.deps = meta.deps.map(filename =>
|
||||
typeof filename === "string"
|
||||
? resolveRelativePath(file, filename)
|
||||
: filename
|
||||
);
|
||||
}
|
||||
},
|
||||
MarkoTag(tag) {
|
||||
const { file } = tag.hub;
|
||||
const tagDef = getTagDef(tag);
|
||||
// Check if tag uses stateful tag params.
|
||||
const meta = tag.hub.file.metadata.marko;
|
||||
|
||||
if (tagDef) {
|
||||
if (tagDef.html && !tagDef.template && !tagDef.renderer) {
|
||||
if (tagDef.htmlType === "custom-element") {
|
||||
if (tagDef.parseOptions && tagDef.parseOptions.import) {
|
||||
// TODO: the taglib should be updated to support this as a top level option.
|
||||
meta.deps.push(
|
||||
resolve(
|
||||
tagDef.dir,
|
||||
resolve(tagDef.dir, tagDef.parseOptions.import)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (tag.get("name").isStringLiteral()) {
|
||||
const relativePath = resolveRelativeTagEntry(file, tagDef);
|
||||
|
||||
if (relativePath) {
|
||||
tag.node.extra = tag.node.extra || {};
|
||||
tag.node.extra.relativePath = relativePath;
|
||||
|
||||
if (!meta.tags.includes(relativePath)) {
|
||||
meta.tags.push(relativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tagDef.codeGeneratorModulePath) {
|
||||
if (!meta.watchFiles.includes(tagDef.codeGeneratorModulePath)) {
|
||||
meta.watchFiles.push(tagDef.codeGeneratorModulePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
meta.hasStatefulTagParams ||
|
||||
isNativeTag(tag) ||
|
||||
@ -63,6 +134,21 @@ export const analyze = {
|
||||
childMeta &&
|
||||
(childMeta.hasStatefulTagParams ||
|
||||
(childMeta.hasComponent && !childMeta.hasComponentBrowser));
|
||||
},
|
||||
ImportDeclaration: {
|
||||
exit(path) {
|
||||
const source = path.get("source");
|
||||
const tagEntry = resolveTagImport(source, source.node.value);
|
||||
|
||||
if (tagEntry) {
|
||||
const meta = path.hub.file.metadata.marko;
|
||||
source.node.value = tagEntry;
|
||||
|
||||
if (!meta.tags.includes(tagEntry)) {
|
||||
meta.tags.push(tagEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -82,6 +168,16 @@ export const translate = {
|
||||
hub: { file }
|
||||
} = path;
|
||||
|
||||
if (file.markoOpts.output === "hydrate") {
|
||||
addDependencies(file, true);
|
||||
return;
|
||||
} else if (
|
||||
file.markoOpts.resolveVirtualDependencies &&
|
||||
file.markoOpts.output !== "html"
|
||||
) {
|
||||
addDependencies(file, false);
|
||||
}
|
||||
|
||||
if (file.metadata.marko.moduleCode) {
|
||||
path
|
||||
.replaceWith(parseScript(file, file.metadata.marko.moduleCode))[0]
|
||||
@ -115,36 +211,9 @@ export const translate = {
|
||||
const { markoOpts, _inlineComponentClass } = file;
|
||||
const includeMetaInSource = markoOpts.meta !== false;
|
||||
const meta = file.metadata.marko;
|
||||
const {
|
||||
styleFile,
|
||||
packageFile,
|
||||
componentFile,
|
||||
componentBrowserFile
|
||||
} = getComponentFiles(path);
|
||||
const { componentFile, componentBrowserFile } = getComponentFiles(path);
|
||||
const isHTML = markoOpts.output === "html";
|
||||
|
||||
if (packageFile) {
|
||||
meta.deps.unshift(`package: ${packageFile}`);
|
||||
}
|
||||
|
||||
if (styleFile) {
|
||||
meta.deps.unshift(styleFile);
|
||||
}
|
||||
|
||||
if (meta.hasComponentBrowser) {
|
||||
meta.component = componentBrowserFile;
|
||||
} else if (meta.hasComponent || meta.hasStatefulTagParams) {
|
||||
meta.component = file.opts.sourceFileName;
|
||||
}
|
||||
|
||||
meta.component =
|
||||
meta.component && resolveRelativePath(file, meta.component);
|
||||
meta.deps = meta.deps.map(filename =>
|
||||
typeof filename === "string"
|
||||
? resolveRelativePath(file, filename)
|
||||
: filename
|
||||
);
|
||||
|
||||
const renderBlock = file._renderBlock;
|
||||
const componentClass =
|
||||
(componentFile &&
|
||||
@ -352,21 +421,6 @@ export const translate = {
|
||||
|
||||
optimizeHTMLWrites(path);
|
||||
}
|
||||
},
|
||||
ImportDeclaration: {
|
||||
exit(path) {
|
||||
const source = path.get("source");
|
||||
const tagEntry = resolveTagImport(source, source.node.value);
|
||||
|
||||
if (tagEntry) {
|
||||
const meta = path.hub.file.metadata.marko;
|
||||
source.node.value = tagEntry;
|
||||
|
||||
if (!meta.tags.includes(tagEntry)) {
|
||||
meta.tags.push(tagEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -374,3 +428,9 @@ function isRenderContent(path) {
|
||||
const { node } = path;
|
||||
return t.MARKO_TYPES.includes(node.type) && !node.static;
|
||||
}
|
||||
|
||||
function resolveRelativeTagEntry(file, tagDef) {
|
||||
// TODO: support transform and other entries.
|
||||
const entry = tagDef.template || tagDef.renderer;
|
||||
return entry && resolveRelativePath(file, entry);
|
||||
}
|
||||
|
||||
@ -2,22 +2,19 @@ import { types as t } from "@marko/compiler";
|
||||
import {
|
||||
assertNoArgs,
|
||||
getTagDef,
|
||||
resolveRelativePath,
|
||||
importDefault
|
||||
importDefault,
|
||||
resolveRelativePath
|
||||
} from "@marko/babel-utils";
|
||||
import { getAttrs, buildEventHandlerArray } from "./util";
|
||||
import nativeTag from "./native-tag";
|
||||
import withPreviousLocation from "../util/with-previous-location";
|
||||
|
||||
// TODO: support transform and other entries.
|
||||
const TAG_FILE_ENTRIES = ["template", "renderer"];
|
||||
|
||||
export default function (path, isNullable) {
|
||||
const {
|
||||
hub: { file },
|
||||
node
|
||||
} = path;
|
||||
const { metadata, markoOpts } = file;
|
||||
const { markoOpts } = file;
|
||||
const { name, key } = node;
|
||||
|
||||
assertNoArgs(path);
|
||||
@ -25,9 +22,22 @@ export default function (path, isNullable) {
|
||||
let tagIdentifier;
|
||||
|
||||
if (t.isStringLiteral(name)) {
|
||||
const tagDef = getTagDef(path);
|
||||
const tagName = name.value;
|
||||
const relativePath = tagDef && resolveRelativeTagEntry(file, tagDef);
|
||||
let relativePath = node.extra && node.extra.relativePath;
|
||||
|
||||
if (!relativePath) {
|
||||
const tagDef = getTagDef(path);
|
||||
if (
|
||||
tagDef &&
|
||||
tagDef.taglibId === "marko-default-core" &&
|
||||
tagDef.renderer
|
||||
) {
|
||||
// Normally new tags should not be added in the translate stage.
|
||||
// We make an exception here for core tags, init-components & _preserve being the primary culprits.
|
||||
// TODO: in the future refactor so this is not needed.
|
||||
relativePath = resolveRelativePath(file, tagDef.renderer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!relativePath) {
|
||||
if (markoOpts.ignoreUnrecognizedTags) {
|
||||
@ -42,10 +52,6 @@ export default function (path, isNullable) {
|
||||
}
|
||||
|
||||
tagIdentifier = importDefault(file, relativePath, tagName);
|
||||
|
||||
if (!metadata.marko.tags.includes(relativePath)) {
|
||||
metadata.marko.tags.push(relativePath);
|
||||
}
|
||||
} else {
|
||||
tagIdentifier = name;
|
||||
}
|
||||
@ -106,10 +112,3 @@ export default function (path, isNullable) {
|
||||
path.replaceWith(customTagRenderCall);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveRelativeTagEntry(file, tagDef) {
|
||||
for (const entry of TAG_FILE_ENTRIES) {
|
||||
if (!tagDef[entry]) continue;
|
||||
return resolveRelativePath(file, tagDef[entry]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,11 +27,7 @@ export default {
|
||||
|
||||
if (tagDef) {
|
||||
if (tagDef.codeGeneratorModulePath) {
|
||||
const {
|
||||
node,
|
||||
hub: { file }
|
||||
} = path;
|
||||
file.metadata.marko.watchFiles.push(tagDef.codeGeneratorModulePath);
|
||||
const { node } = path;
|
||||
tagDef.codeGenerator = markoModules.require(
|
||||
tagDef.codeGeneratorModulePath
|
||||
);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { resolve } from "path";
|
||||
import { types as t } from "@marko/compiler";
|
||||
import write from "../../util/vdom-out-write";
|
||||
import * as FLAGS from "../../util/runtime-flags";
|
||||
@ -10,7 +9,6 @@ import {
|
||||
} from "@marko/babel-utils";
|
||||
import withPreviousLocation from "../../util/with-previous-location";
|
||||
|
||||
const EMPTY_OBJECT = {};
|
||||
const SIMPLE_ATTRS = ["id", "class", "style"];
|
||||
const MAYBE_SVG = {
|
||||
a: true,
|
||||
@ -126,13 +124,9 @@ export function tagArguments(path, isStatic) {
|
||||
const tagDef = getTagDef(path);
|
||||
|
||||
if (tagDef) {
|
||||
const { htmlType, name, parseOptions = EMPTY_OBJECT } = tagDef;
|
||||
const { htmlType, name } = tagDef;
|
||||
if (htmlType === "custom-element") {
|
||||
runtimeFlags |= FLAGS.IS_CUSTOM_ELEMENT;
|
||||
if (parseOptions.import) {
|
||||
// TODO: the taglib should be updated to support this as a top level option.
|
||||
file.metadata.marko.deps.push(resolve(tagDef.dir, parseOptions.import));
|
||||
}
|
||||
} else if (
|
||||
htmlType === "svg" ||
|
||||
(MAYBE_SVG[name] &&
|
||||
|
||||
@ -71,7 +71,7 @@
|
||||
},
|
||||
"<style>": {
|
||||
"node-factory": "./parse-style.js",
|
||||
"code-generator": "./translate-style.js",
|
||||
"transformer": "./transform-style.js",
|
||||
"parse-options": {
|
||||
"rawOpenTag": true
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ export default function (path) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!path.parentPath.parentPath.isProgram()) {
|
||||
if (!path.parentPath.isProgram()) {
|
||||
throw path
|
||||
.get("name")
|
||||
.buildCodeFrameError(
|
||||
155
packages/translator-default/src/util/add-dependencies.js
Normal file
155
packages/translator-default/src/util/add-dependencies.js
Normal file
@ -0,0 +1,155 @@
|
||||
import path from "path";
|
||||
import MagicString from "magic-string";
|
||||
import { types as t } from "@marko/compiler";
|
||||
import { loadFileForImport, resolveRelativePath } from "@marko/babel-utils";
|
||||
export default (entryFile, isHydrate) => {
|
||||
const { modules, resolveVirtualDependency } = entryFile.markoOpts;
|
||||
const program = entryFile.path;
|
||||
|
||||
if (!isHydrate) {
|
||||
addBrowserDeps(entryFile);
|
||||
return;
|
||||
}
|
||||
|
||||
const registerId = t.identifier("register");
|
||||
const watchFiles = new Set();
|
||||
let hasComponents = false;
|
||||
let splitComponentIndex = 0;
|
||||
program.set("body", []);
|
||||
program.skip();
|
||||
|
||||
addHydrateDeps(entryFile);
|
||||
entryFile.metadata.marko.watchFiles = Array.from(watchFiles);
|
||||
|
||||
if (hasComponents) {
|
||||
const initId = t.identifier("init");
|
||||
const markoComponentsImport = importPath(entryFile, "marko/components");
|
||||
if (splitComponentIndex) {
|
||||
markoComponentsImport.specifiers.push(
|
||||
t.importSpecifier(registerId, registerId)
|
||||
);
|
||||
}
|
||||
markoComponentsImport.specifiers.push(t.importSpecifier(initId, initId));
|
||||
program.unshiftContainer("body", markoComponentsImport);
|
||||
program.pushContainer(
|
||||
"body",
|
||||
t.expressionStatement(
|
||||
t.callExpression(
|
||||
initId,
|
||||
entryFile.markoOpts.runtimeId
|
||||
? [t.stringLiteral(entryFile.markoOpts.runtimeId)]
|
||||
: []
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function addHydrateDeps(file) {
|
||||
const meta = file.metadata.marko;
|
||||
|
||||
if (meta.component) {
|
||||
hasComponents = true;
|
||||
|
||||
if (
|
||||
path.basename(meta.component) ===
|
||||
path.basename(file.opts.sourceFileName)
|
||||
) {
|
||||
// Stateful component.
|
||||
program.pushContainer("body", importPath(file, meta.component));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (const watchFile of meta.watchFiles) {
|
||||
watchFiles.add(watchFile);
|
||||
}
|
||||
|
||||
addBrowserDeps(file);
|
||||
|
||||
for (const tag of meta.tags) {
|
||||
if (tag.endsWith(".marko")) {
|
||||
addHydrateDeps(loadFileForImport(file, tag));
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.component) {
|
||||
// Split component
|
||||
const splitComponentId = t.identifier(
|
||||
`component_${splitComponentIndex++}`
|
||||
);
|
||||
const splitComponentImport = importPath(file, meta.component);
|
||||
splitComponentImport.specifiers.push(
|
||||
t.importDefaultSpecifier(splitComponentId)
|
||||
);
|
||||
program.pushContainer("body", splitComponentImport);
|
||||
program.pushContainer(
|
||||
"body",
|
||||
t.expressionStatement(
|
||||
t.callExpression(registerId, [
|
||||
t.stringLiteral(meta.id),
|
||||
splitComponentId
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function addBrowserDeps(file) {
|
||||
const { sourceFileName, sourceMaps } = file.opts;
|
||||
let s;
|
||||
|
||||
for (let dep of file.metadata.marko.deps) {
|
||||
if (typeof dep !== "string") {
|
||||
const { virtualPath } = dep;
|
||||
let { code } = dep;
|
||||
let map;
|
||||
|
||||
if (sourceMaps && dep.startPos !== undefined) {
|
||||
s = s || new MagicString(file.code, { source: sourceFileName });
|
||||
map = s.snip(dep.startPos, dep.endPos).generateMap();
|
||||
|
||||
if (sourceMaps === "inline" || sourceMaps === "both") {
|
||||
if (sourceMaps === "inline") {
|
||||
map = undefined;
|
||||
}
|
||||
|
||||
code += virtualPath.endsWith(".css")
|
||||
? `\n/*# sourceMappingURL=${map.toUrl()}*/`
|
||||
: `\n//# sourceMappingURL=${map.toUrl()}`;
|
||||
}
|
||||
}
|
||||
|
||||
dep = resolveVirtualDependency(sourceFileName, {
|
||||
map,
|
||||
code,
|
||||
virtualPath
|
||||
});
|
||||
}
|
||||
|
||||
program.pushContainer("body", importPath(file, dep));
|
||||
}
|
||||
}
|
||||
|
||||
function importPath(file, req) {
|
||||
let resolved = req;
|
||||
|
||||
if (file !== entryFile) {
|
||||
resolved = resolveRelativePath(
|
||||
entryFile,
|
||||
path.join(
|
||||
file.opts.sourceFileName,
|
||||
"..",
|
||||
path.sep === "/" ? req : req.replace(/\//g, path.sep)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (modules === "cjs") {
|
||||
return t.expressionStatement(
|
||||
t.callExpression(t.identifier("require"), [t.stringLiteral(resolved)])
|
||||
);
|
||||
}
|
||||
|
||||
return t.importDeclaration([], t.stringLiteral(resolved));
|
||||
}
|
||||
};
|
||||
0
packages/translator-default/test/fixtures/at-tags-dynamic/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/at-tags-dynamic/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/at-tags/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/at-tags/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-boolean/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-boolean/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-class/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-class/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-escape/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-escape/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-falsey/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-falsey/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-scoped/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-scoped/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-style/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/attr-style/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/await-tag/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/await-tag/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/cdata/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/cdata/snapshots/hydrate-expected.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import { init } from "marko/components";
|
||||
import "./index.marko";
|
||||
init();
|
||||
@ -0,0 +1,3 @@
|
||||
import { init } from "marko/components";
|
||||
import "./template.marko";
|
||||
init();
|
||||
@ -0,0 +1,3 @@
|
||||
import { init } from "marko/components";
|
||||
import "./template.marko";
|
||||
init();
|
||||
3
packages/translator-default/test/fixtures/class-inline/snapshots/hydrate-expected.js
vendored
Normal file
3
packages/translator-default/test/fixtures/class-inline/snapshots/hydrate-expected.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import { init } from "marko/components";
|
||||
import "./template.marko";
|
||||
init();
|
||||
0
packages/translator-default/test/fixtures/comments/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/comments/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/custom-element-tag/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/custom-element-tag/snapshots/hydrate-expected.js
vendored
Normal file
@ -1 +1,2 @@
|
||||
-- Hello Frank
|
||||
<hello/>
|
||||
<message/>
|
||||
0
packages/translator-default/test/fixtures/custom-tag-data/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/custom-tag-data/snapshots/hydrate-expected.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
packages/translator-default/test/fixtures/custom-tag-migration/new.marko(1,1): A line in concise mode cannot start with a single hyphen. Use "--" instead. See: https://github.com/marko-js/htmljs-parser/issues/43
|
||||
> 1 | - Hello ${input.name}!
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -0,0 +1,3 @@
|
||||
import { init } from "marko/components";
|
||||
import "./template.marko";
|
||||
init();
|
||||
@ -0,0 +1,3 @@
|
||||
packages/translator-default/test/fixtures/custom-tag-template/hello.marko(1,1): A line in concise mode cannot start with a single hyphen. Use "--" instead. See: https://github.com/marko-js/htmljs-parser/issues/43
|
||||
> 1 | - Hello ${input.name}!
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -1 +1 @@
|
||||
<span style="display:block"/>
|
||||
<div/>
|
||||
0
packages/translator-default/test/fixtures/custom-tag-transform/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/custom-tag-transform/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/custom-tag/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/custom-tag/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/data-migration/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/data-migration/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/declaration/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/declaration/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/doctype/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/doctype/snapshots/hydrate-expected.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
<div/>
|
||||
1
packages/translator-default/test/fixtures/dynamic-tag-name/components/tag-b/index.marko
vendored
Normal file
1
packages/translator-default/test/fixtures/dynamic-tag-name/components/tag-b/index.marko
vendored
Normal file
@ -0,0 +1 @@
|
||||
<div/>
|
||||
0
packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/dynamic-tag-name/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/entities/snapshots/hydrate-expected.js
vendored
Normal file
0
packages/translator-default/test/fixtures/entities/snapshots/hydrate-expected.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
packages/translator-default/test/fixtures/error-bad-expression/template.marko(1,18): Unexpected token, expected ","
|
||||
> 1 | <div class=(this is not valid)></div>
|
||||
| ^
|
||||
2 |
|
||||
@ -0,0 +1,7 @@
|
||||
packages/translator-default/test/fixtures/error-class-constructor/template.marko(2,3): The constructor method should not be used for a component, use onCreate instead.
|
||||
1 | class {
|
||||
> 2 | constructor() {
|
||||
| ^^^^^^^^^^^
|
||||
3 |
|
||||
4 | }
|
||||
5 | }
|
||||
@ -0,0 +1,6 @@
|
||||
packages/translator-default/test/fixtures/error-class-file-and-inline/template.marko(1,1): A Marko file can either have an inline class, or an external "component.js", but not both.
|
||||
> 1 | class {
|
||||
| ^^^^^
|
||||
2 | onCreate() {
|
||||
3 |
|
||||
4 | }
|
||||
@ -0,0 +1,7 @@
|
||||
packages/translator-default/test/fixtures/error-class-not-root/template.marko(2,3): "class" tags must be at the root of your Marko template.
|
||||
1 | div
|
||||
> 2 | class extends Test {
|
||||
| ^^^^^
|
||||
3 | onCreate() {
|
||||
4 |
|
||||
5 | }
|
||||
@ -0,0 +1,3 @@
|
||||
import { init } from "marko/components";
|
||||
import "./template.marko";
|
||||
init();
|
||||
@ -0,0 +1,3 @@
|
||||
import { init } from "marko/components";
|
||||
import "./template.marko";
|
||||
init();
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-class-tag-nested-content/template.marko(2,2): The "class" tag does not allow nested body content
|
||||
1 | class {}
|
||||
> 2 | <div/>
|
||||
| ^
|
||||
3 |
|
||||
@ -0,0 +1,6 @@
|
||||
packages/translator-default/test/fixtures/error-class-with-name/template.marko(1,7): Component class cannot have a name.
|
||||
> 1 | class Test {
|
||||
| ^^^^
|
||||
2 | onCreate() {
|
||||
3 |
|
||||
4 | }
|
||||
@ -0,0 +1,6 @@
|
||||
packages/translator-default/test/fixtures/error-class-with-super-class/template.marko(1,15): Component class cannot have a super class.
|
||||
> 1 | class extends Test {
|
||||
| ^^^^
|
||||
2 | onCreate() {
|
||||
3 |
|
||||
4 | }
|
||||
@ -0,0 +1,4 @@
|
||||
packages/translator-default/test/fixtures/error-dynamic-tag-no-value/template.marko(1,3): Missing expression for <${dynamic}> tag.
|
||||
> 1 | <${}/>
|
||||
| ^^
|
||||
2 |
|
||||
6
packages/translator-default/test/fixtures/error-eof/snapshots/hydrate-error-expected.txt
vendored
Normal file
6
packages/translator-default/test/fixtures/error-eof/snapshots/hydrate-error-expected.txt
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
packages/translator-default/test/fixtures/error-eof/template.marko(1,6): EOF reached while parsing attribute name for the "style" tag
|
||||
> 1 | style {
|
||||
| ^
|
||||
2 | div {
|
||||
3 | color: green;
|
||||
4 | }
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-export-tag-nested-content/template.marko(2,2): The "export" tag does not allow nested body content
|
||||
1 | export a from "b";
|
||||
> 2 | <div/>
|
||||
| ^
|
||||
3 |
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-export-tag-root-only/template.marko(2,3): "export" tags must be at the root of your Marko template.
|
||||
1 | <div>
|
||||
> 2 | <export x from "y"/>
|
||||
| ^^^^^^^
|
||||
3 | </div>
|
||||
@ -0,0 +1,3 @@
|
||||
packages/translator-default/test/fixtures/error-id-shorthand-and-attribute/template.marko(1,8): Cannot have shorthand id and id attribute.
|
||||
> 1 | <div#x id="y"/>
|
||||
| ^^^^^^
|
||||
@ -0,0 +1,3 @@
|
||||
packages/translator-default/test/fixtures/error-import-tag-component-missing/template.marko(1,31): Unable to find entry point for custom tag <missing-component>.
|
||||
> 1 | <import MissingComponent from "<missing-component>"/>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-import-tag-nested-content/template.marko(2,2): The "import" tag does not allow nested body content
|
||||
1 | import a from "b";
|
||||
> 2 | <div/>
|
||||
| ^
|
||||
3 |
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-import-tag-root-only/template.marko(2,3): "import" tags must be at the root of your Marko template.
|
||||
1 | <div>
|
||||
> 2 | <import x from "y"/>
|
||||
| ^^^^^^^
|
||||
3 | </div>
|
||||
@ -0,0 +1,4 @@
|
||||
packages/translator-default/test/fixtures/error-invalid-js/template.marko(1,5): Unexpected token
|
||||
> 1 | $ x..y();
|
||||
| ^
|
||||
2 | <div/>
|
||||
@ -0,0 +1,7 @@
|
||||
packages/translator-default/test/fixtures/error-macro-duplicate/template.marko(5,15): A macro with the name "thing" already exists.
|
||||
3 | </macro>
|
||||
4 |
|
||||
> 5 | <macro|stuff| name="thing">
|
||||
| ^^^^^^^^^^^^
|
||||
6 | <div>b</div>
|
||||
7 | </macro>
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-macro-invalid-attributes/template.marko(1,28): The "macro" tag can only have a "name" attribute.
|
||||
> 1 | <macro|stuff| name="thing" x=1>
|
||||
| ^^^
|
||||
2 | <div/>
|
||||
3 | </macro>
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-macro-invalid-name-attribute/template.marko(1,20): The "name" attribute for "macro" tags must be a string literal.
|
||||
> 1 | <macro|stuff| name=1>
|
||||
| ^
|
||||
2 | <div/>
|
||||
3 | </macro>
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-macro-missing-name/template.marko(1,2): The "name" attribute is required on "macro" tags.
|
||||
> 1 | <macro|stuff|>
|
||||
| ^^^^^
|
||||
2 | <div/>
|
||||
3 | </macro>
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-macro-tag-root-only/template.marko(2,3): "static" tags must be at the root of your Marko template.
|
||||
1 | <div>
|
||||
> 2 | <static { console.log(x) }/>
|
||||
| ^^^^^^^
|
||||
3 | </div>
|
||||
@ -0,0 +1,5 @@
|
||||
packages/translator-default/test/fixtures/error-mismatched-closing-tag/template.marko(4,1): The closing "div" tag does not match the corresponding opening "span" tag
|
||||
2 | <span>
|
||||
3 | <span>
|
||||
> 4 | </div>
|
||||
| ^^^^^^
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user