Skip to content

Commit

Permalink
feat: optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
Aslemammad committed Apr 25, 2022
1 parent d245ef3 commit 773b6e7
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 24 deletions.
38 changes: 14 additions & 24 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import path from "path";
import crypto from "crypto";
import anyMatch from "anymatch";
import { pathToFileURL, fileURLToPath } from "url";

import getServerEntryTemplate from "./server-entry-template";
import {
generateInputDoc,
generateDocManifest,
DocManifest,
} from "./manifest-generator";
import esbuildPlugin from "./marko-plugin";

export interface Options {
// Defaults to true, set to false to disable automatic component discovery and hydration.
Expand Down Expand Up @@ -170,7 +172,6 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {
}
}
}

const domDeps = Array.from(
new Set(
compiler
Expand All @@ -181,36 +182,26 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {

const optimizeDeps = (config.optimizeDeps ??= {});
optimizeDeps.include ??= [];
optimizeDeps.include = optimizeDeps.include.concat(
domDeps.filter((dep) => path.extname(dep) !== markoExt)
);

optimizeDeps.exclude ??= [];
optimizeDeps.exclude = optimizeDeps.exclude.concat(
domDeps.filter((dep) => path.extname(dep) === markoExt)
);
optimizeDeps.include = optimizeDeps.include.concat(domDeps);

if (!isBuild) {
const serverDeps = Array.from(
new Set(
compiler
.getRuntimeEntryFiles("html", opts.translator)
.concat(taglibDeps)
)
new Set(compiler.getRuntimeEntryFiles("html", opts.translator))
);
const ssr = ((config as any).ssr ??= {});
ssr.external ??= [];
ssr.external = ssr.external.concat(serverDeps);
// Vite cannot handle commonjs modules, which many Marko component libraries
// use in conjunction with the `.marko` files. To support this
// we tell Vite to ignore all `.marko` files in node_modules for the server.
// and instead use the require hook.
(await import("@marko/compiler/register.js")).default({
...ssrConfig,
sourceMaps: "inline",
modules: "cjs",
});
}
return {
...config,
optimizeDeps: {
...config.optimizeDeps,
extensions: [...(config?.optimizeDeps?.extensions || []), ".marko"],
esbuildOptions: {
plugins: [esbuildPlugin()],
} as any,
},
};
},
configureServer(_server) {
ssrConfig.hot = domConfig.hot = true;
Expand Down Expand Up @@ -415,7 +406,6 @@ export default function markoPlugin(opts: Options = {}): vite.Plugin[] {

transformWatchFiles.set(id, meta.watchFiles!);
}

return { code, map };
},
},
Expand Down
137 changes: 137 additions & 0 deletions src/marko-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import fs from "fs";
import path from "path";
import type * as esbuild from "esbuild";
import type * as Compiler from "@marko/compiler";

const cache = new Map<string, Compiler.CompileResult>();
const markoErrorRegExp = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;

export interface Options {
// Override the Marko compiler instance being used. (primarily for tools wrapping this module)
compiler?: string;
// Sets a custom runtimeId to avoid conflicts with multiple copies of Marko on the same page.
runtimeId?: string;
// Overrides the Marko translator being used.
translator?: string;
// Overrides the Babel config that Marko will use.
babelConfig?: Compiler.Config["babelConfig"];
}

export default function esbuildPlugin(opts: Options = {}): esbuild.Plugin {
let compiler: typeof Compiler;
const { runtimeId, translator } = opts;
const babelConfig = {
...opts.babelConfig,
caller: {
name: "@marko/esbuild",
supportsStaticESM: true,
supportsDynamicImport: true,
supportsTopLevelAwait: true,
supportsExportNamespaceFrom: true,
...opts.babelConfig?.caller,
},
};

return {
name: "marko",
async setup(build) {
const { platform = "browser", sourcemap } = build.initialOptions;
const output = platform === "browser" ? "dom" : "html";
let resolveVirtualDependency: Compiler.Config["resolveVirtualDependency"];
compiler ??= await import(opts.compiler || "@marko/compiler");

if (platform === "browser") {
const virtualFiles = new Map<string, { code: string; map?: unknown }>();
resolveVirtualDependency = (from, dep) => {
virtualFiles.set(path.join(from, "..", dep.virtualPath), dep);
return dep.virtualPath;
};

build.onResolve({ filter: /\.marko\./ }, (args) => {
return {
namespace: "marko:virtual",
path: path.resolve(args.resolveDir, args.path),
};
});

build.onLoad(
{ filter: /\.marko\./, namespace: "marko:virtual" },
(args) => ({
contents: virtualFiles.get(args.path)!.code,
loader: path.extname(args.path).slice(1) as esbuild.Loader,
})
);

build.onResolve({ filter: /\.marko$/ }, async (args) => ({
namespace: args.kind === "entry-point" ? "marko:hydrate" : "file",
path: path.resolve(args.resolveDir, args.path),
}));

build.onLoad(
{ filter: /\.marko$/, namespace: "marko:hydrate" },
(args) => compileSafe(args.path, "hydrate")
);
}

build.onLoad({ filter: /\.marko$/, namespace: "file" }, (args) =>
compileSafe(args.path, output)
);

async function compileSafe(
filename: string,
output: Exclude<Compiler.Config["output"], void>
): Promise<esbuild.OnLoadResult> {
try {
const { code, meta } = await compiler.compileFile(filename, {
cache,
output,
runtimeId,
translator,
babelConfig,
resolveVirtualDependency,
writeVersionComment: false,
sourceMaps: output === "hydrate" || !sourcemap ? false : "inline",
});

return {
loader: "js",
contents: code,
watchFiles: meta.watchFiles,
resolveDir: path.dirname(filename),
};
} catch (e) {
const text = (e as Error).message;
const errors: esbuild.PartialMessage[] = [];
let match: RegExpExecArray | null;
let lines: string[] | undefined;

while ((match = markoErrorRegExp.exec(text))) {
const [, file, rawLine, rawCol, text] = match;
const line = parseInt(rawLine, 10) || 1;
const column = parseInt(rawCol, 10) || 1;
lines ||= (await fs.promises.readFile(filename, "utf-8")).split(
/\r\n|\r|\n/g
);
errors.push({
text,
location: {
file,
line,
column,
lineText: ` ${lines[line - 1]}`,
},
});
}

if (!errors.length) {
errors.push({ text });
}

return {
errors,
};
}
}
},
};
}

0 comments on commit 773b6e7

Please sign in to comment.