@marko/vite 2.3.14 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -138,6 +138,23 @@ Storage mechanism to preserve data between SSR and client builds when building i
138
138
  ```
139
139
  Reads/writes data to memory. This option can be used when building with Vite programatically.
140
140
 
141
+ ### options.basePathVar
142
+
143
+ Set this to variable/identifier which all asset base paths should be prefixed with. All asset paths used by Vite will either be relative (if possible) or prefixed with this identifier. The identifier must be defined as a string before any other server code executes.
144
+
145
+ First configure `@marko/vite`.
146
+
147
+ ```js
148
+ marko({ basePathVar: "__MY_ASSET_BASE_PATH__" });
149
+ ```
150
+
151
+ Then ensure you set that variable at runtime.
152
+
153
+ ```js
154
+ globalThis.__MY_ASSET_BASE_PATH__ = getAssetUrl(); // Note this must end with a `/`.
155
+ require("./dist/index.mjs"); // load the built vite app.
156
+ ```
157
+
141
158
  ## Code of Conduct
142
159
 
143
160
  This project adheres to the [eBay Code of Conduct](./.github/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  serialize
3
- } from "./chunk-VL2HLMVE.mjs";
3
+ } from "./chunk-SELVH7LO.mjs";
4
4
 
5
5
  // src/manifest-generator.ts
6
6
  import { Parser } from "htmlparser2";
7
7
  import { ElementType } from "domelementtype";
8
8
  import { DomHandler } from "domhandler";
9
9
  var MARKER_COMMENT = "MARKO_VITE";
10
- function generateDocManifest(rawHtml) {
10
+ function generateDocManifest(basePath, rawHtml) {
11
11
  return new Promise((resolve, reject) => {
12
12
  const parser = new Parser(
13
13
  new DomHandler(function(err, dom) {
@@ -34,10 +34,10 @@ function generateDocManifest(rawHtml) {
34
34
  body
35
35
  );
36
36
  resolve({
37
- "head-prepend": serializeOrNull(headPrepend),
38
- head: serializeOrNull(head),
39
- "body-prepend": serializeOrNull(bodyPrepend),
40
- body: serializeOrNull(body)
37
+ "head-prepend": serializeOrNull(basePath, headPrepend),
38
+ head: serializeOrNull(basePath, head),
39
+ "body-prepend": serializeOrNull(basePath, bodyPrepend),
40
+ body: serializeOrNull(basePath, body)
41
41
  });
42
42
  })
43
43
  );
@@ -50,8 +50,8 @@ function generateInputDoc(entry) {
50
50
  entry
51
51
  )}></script></body></html>`;
52
52
  }
53
- function serializeOrNull(nodes) {
54
- const result = serialize(nodes);
53
+ function serializeOrNull(basePath, nodes) {
54
+ const result = serialize(basePath, nodes);
55
55
  if (result.length) {
56
56
  return result;
57
57
  }
@@ -16,7 +16,7 @@ var voidElements = /* @__PURE__ */ new Set([
16
16
  "track",
17
17
  "wbr"
18
18
  ]);
19
- function serialize(nodes, parts) {
19
+ function serialize(basePath, nodes, parts) {
20
20
  let curString = parts ? parts.pop() : "";
21
21
  parts ?? (parts = []);
22
22
  for (const node of nodes) {
@@ -26,30 +26,45 @@ function serialize(nodes, parts) {
26
26
  case ElementType.Script: {
27
27
  const tag = node;
28
28
  const { name } = tag;
29
+ let urlAttr;
29
30
  curString += `<${name}`;
30
31
  switch (tag.tagName) {
31
32
  case "script":
32
- parts.push(curString);
33
+ parts.push(curString, 0 /* AssetAttrs */);
34
+ urlAttr = "src";
33
35
  curString = "";
34
36
  break;
35
37
  case "style":
36
- parts.push(curString);
38
+ parts.push(curString, 0 /* AssetAttrs */);
37
39
  curString = "";
38
40
  break;
39
41
  case "link":
40
42
  if (tag.attribs.rel === "stylesheet") {
41
- parts.push(curString);
43
+ urlAttr = "href";
44
+ parts.push(curString, 0 /* AssetAttrs */);
42
45
  curString = "";
43
46
  }
44
47
  break;
45
48
  }
46
49
  for (const attr of tag.attributes) {
47
- curString += ` ${attr.value === "" ? attr.name : `${attr.name}="${attr.value.replace(/"/g, "&#39;")}"`}`;
50
+ if (attr.value === "") {
51
+ curString += ` ${attr.name}`;
52
+ } else if (attr.name === urlAttr) {
53
+ curString += ` ${attr.name}="`;
54
+ parts.push(
55
+ curString,
56
+ 1 /* PublicPath */,
57
+ stripBasePath(basePath, attr.value).replace(/"/g, "&#39;").replace(/^\.\//, "") + '"'
58
+ );
59
+ curString = "";
60
+ } else {
61
+ curString += ` ${attr.name}="${attr.value.replace(/"/g, "&#39;")}"`;
62
+ }
48
63
  }
49
64
  curString += ">";
50
65
  if (tag.children.length) {
51
66
  parts.push(curString);
52
- serialize(tag.children, parts);
67
+ serialize(basePath, tag.children, parts);
53
68
  curString = parts.pop();
54
69
  }
55
70
  if (!voidElements.has(name)) {
@@ -74,6 +89,11 @@ function serialize(nodes, parts) {
74
89
  }
75
90
  return parts;
76
91
  }
92
+ function stripBasePath(basePath, path) {
93
+ if (path.startsWith(basePath))
94
+ return path.slice(basePath.length);
95
+ return path;
96
+ }
77
97
 
78
98
  export {
79
99
  serialize
@@ -0,0 +1,25 @@
1
+ // src/server-entry-template.ts
2
+ import path from "path";
3
+ var server_entry_template_default = async (opts) => {
4
+ const fileNameStr = JSON.stringify(`./${path.basename(opts.fileName)}`);
5
+ const base = opts.basePathVar ? ` base=${opts.basePathVar}` : "";
6
+ return `import template from ${fileNameStr};
7
+ export * from ${fileNameStr};
8
+ ${opts.basePathVar ? `
9
+ static if (typeof ${opts.basePathVar} !== "string") throw new Error("${opts.basePathVar} must be defined when using basePathVar.");
10
+ static if (!${opts.basePathVar}.endsWith("/")) throw new Error("${opts.basePathVar} must end with a '/' when using basePathVar.");
11
+ ` : ""}${opts.runtimeId ? `$ out.global.runtimeId = ${JSON.stringify(opts.runtimeId)};
12
+ ` : ""}$ (out.global.___viteEntries || (out.global.___viteEntries = [])).push(${opts.entryData});
13
+ <_vite${base} slot="head-prepend"/>
14
+ <_vite${base} slot="head"/>
15
+ <_vite${base} slot="body-prepend"/>
16
+ <\${template} ...input/>
17
+ <init-components/>
18
+ <await-reorderer/>
19
+ <_vite${base} slot="body"/>
20
+ `;
21
+ };
22
+
23
+ export {
24
+ server_entry_template_default
25
+ };
@@ -9,12 +9,20 @@ static function renderAssets(slot) {
9
9
 
10
10
  for (let i = lastWrittenEntry; i < writtenEntries; i++) {
11
11
  const entry = entries[i];
12
- const parts = typeof __MARKO_MANIFEST__ === "object"
13
- ? __MARKO_MANIFEST__[entry]?.[slot]
14
- : entry[slot];
12
+ const parts =
13
+ typeof __MARKO_MANIFEST__ === "object"
14
+ ? __MARKO_MANIFEST__[entry]?.[slot]
15
+ : entry[slot];
15
16
 
16
17
  if (parts) {
17
- html += parts.join(this.___viteInjectAttrs);
18
+ for (const part of parts) {
19
+ html +=
20
+ part === 0 /** InjectType.AssetAttrs */
21
+ ? this.___viteInjectAttrs
22
+ : part === 1 /** InjectType.PublicPath */
23
+ ? this.___viteBasePath
24
+ : part;
25
+ }
18
26
  }
19
27
  }
20
28
  }
@@ -26,6 +34,13 @@ $ if (!out.global.___viteRenderAssets) {
26
34
  ? ` nonce="${out.global.cspNonce.replace(/"/g, "&#39;")}"`
27
35
  : "";
28
36
  out.global.___viteRenderAssets = renderAssets;
37
+
38
+ if (input.base) {
39
+ out.global.___viteBasePath = input.base;
40
+ out.script(`$mbp${out.global.runtimeId ? `_${out.global.runtimeId}` : ""}=${JSON.stringify(input.base)}`);
41
+ } else {
42
+ out.global.___viteBasePath = import.meta.env.BASE_URL;
43
+ }
29
44
  }
30
45
 
31
46
  <__flush_here_and_after__>
package/dist/index.d.ts CHANGED
@@ -3,11 +3,23 @@ import type * as Compiler from "@marko/compiler";
3
3
  import { BuildStore } from "./store";
4
4
  export * from "./store";
5
5
  export type { BuildStore } from "./store";
6
+ declare module "@marko/babel-utils" {
7
+ interface Taglib {
8
+ id: string;
9
+ dirname: string;
10
+ path: string;
11
+ tags: TagDefinition[];
12
+ }
13
+ interface TaglibLookup {
14
+ taglibsById: Record<string, Taglib>;
15
+ }
16
+ }
6
17
  export interface Options {
7
18
  linked?: boolean;
8
19
  compiler?: string;
9
20
  runtimeId?: string;
10
21
  translator?: string;
22
+ basePathVar?: string;
11
23
  babelConfig?: Compiler.Config["babelConfig"];
12
24
  store?: BuildStore;
13
25
  }
package/dist/index.js CHANGED
@@ -61,7 +61,7 @@ const thisFile = typeof __filename === "string" ? __filename : (0, import_url.fi
61
61
  function markoPlugin(opts = {}) {
62
62
  var _a;
63
63
  let compiler;
64
- const { runtimeId, linked = true } = opts;
64
+ const { runtimeId, basePathVar, linked = true } = opts;
65
65
  const baseConfig = {
66
66
  cache,
67
67
  runtimeId,
@@ -80,7 +80,9 @@ function markoPlugin(opts = {}) {
80
80
  }
81
81
  };
82
82
  const resolveViteVirtualDep = (from, dep) => {
83
- const query = `${virtualFileQuery}&id=${normalizePath(dep.virtualPath)}`;
83
+ const query = `${virtualFileQuery}&id=${encodeURIComponent(
84
+ normalizePath(dep.virtualPath)
85
+ )}`;
84
86
  const normalizedFrom = normalizePath(from);
85
87
  const id = normalizePath(normalizedFrom) + query;
86
88
  if (devServer) {
@@ -116,6 +118,8 @@ function markoPlugin(opts = {}) {
116
118
  let registeredTag = false;
117
119
  let serverManifest;
118
120
  let store;
121
+ let cjsImports;
122
+ let basePath = "/";
119
123
  const entrySources = /* @__PURE__ */ new Map();
120
124
  const transformWatchFiles = /* @__PURE__ */ new Map();
121
125
  const transformOptionalFiles = /* @__PURE__ */ new Map();
@@ -126,6 +130,7 @@ function markoPlugin(opts = {}) {
126
130
  // Must be pre to allow us to resolve assets before vite.
127
131
  async config(config, env) {
128
132
  compiler ?? (compiler = await import(opts.compiler || "@marko/compiler"));
133
+ compiler.configure(baseConfig);
129
134
  root = normalizePath(config.root || process.cwd());
130
135
  devEntryFile = import_path.default.join(root, "index.html");
131
136
  devEntryFilePosix = normalizePath(devEntryFile);
@@ -150,14 +155,24 @@ function markoPlugin(opts = {}) {
150
155
  }
151
156
  const lookup = compiler.taglib.buildLookup(root);
152
157
  const taglibDeps = [];
158
+ const optimizeTaglibDeps = [];
153
159
  for (const name in lookup.taglibsById) {
154
160
  const taglib = lookup.taglibsById[name];
155
161
  if (!/^marko-(.+-)?core$/.test(taglib.id) && /[\\/]node_modules[\\/]/.test(taglib.dirname)) {
162
+ let isEsm;
156
163
  for (const tagName in taglib.tags) {
157
164
  const tag = taglib.tags[tagName];
158
165
  const entry = tag.template || tag.renderer;
159
166
  if (entry) {
160
- taglibDeps.push((0, import_relative_import_path.relativeImportPath)(devEntryFile, entry));
167
+ const relativePath = (0, import_relative_import_path.relativeImportPath)(devEntryFile, entry);
168
+ taglibDeps.push(relativePath);
169
+ if (isBuild || (isEsm ?? (isEsm = getModuleType(taglib.path) === "esm"))) {
170
+ optimizeTaglibDeps.push(relativePath);
171
+ } else {
172
+ (cjsImports ?? (cjsImports = /* @__PURE__ */ new Map())).set(normalizePath(entry), {
173
+ template: tag.template
174
+ });
175
+ }
161
176
  }
162
177
  }
163
178
  }
@@ -168,7 +183,7 @@ function markoPlugin(opts = {}) {
168
183
  ...optimizeDeps.include || [],
169
184
  ...compiler.getRuntimeEntryFiles("dom", opts.translator),
170
185
  ...compiler.getRuntimeEntryFiles("html", opts.translator),
171
- ...taglibDeps
186
+ ...optimizeTaglibDeps
172
187
  ])
173
188
  );
174
189
  const optimizeExtensions = optimizeDeps.extensions ?? (optimizeDeps.extensions = []);
@@ -184,6 +199,29 @@ function markoPlugin(opts = {}) {
184
199
  )
185
200
  );
186
201
  }
202
+ if (basePathVar) {
203
+ config.experimental ?? (config.experimental = {});
204
+ if (config.experimental.renderBuiltUrl) {
205
+ throw new Error(
206
+ "Cannot use @marko/vite `basePathVar` with Vite's `renderBuiltUrl` option."
207
+ );
208
+ }
209
+ config.experimental.renderBuiltUrl = (fileName, { hostType, ssr: ssr2 }) => {
210
+ switch (hostType) {
211
+ case "html":
212
+ return fileName;
213
+ case "js":
214
+ return {
215
+ runtime: `${ssr2 ? basePathVar : `$mbp${runtimeId ? `_${runtimeId}` : ""}`}+${JSON.stringify(fileName)}`
216
+ };
217
+ default:
218
+ return { relative: true };
219
+ }
220
+ };
221
+ }
222
+ },
223
+ configResolved(config) {
224
+ basePath = config.base;
187
225
  },
188
226
  configureServer(_server) {
189
227
  ssrConfig.hot = domConfig.hot = true;
@@ -282,6 +320,22 @@ function markoPlugin(opts = {}) {
282
320
  return null;
283
321
  },
284
322
  async load(id) {
323
+ if (cjsImports == null ? void 0 : cjsImports.has(id)) {
324
+ const tag = cjsImports.get(id);
325
+ if (!tag.esmWrapper) {
326
+ const { ast } = await compiler.compileFile(tag.template, {
327
+ output: "source",
328
+ ast: true,
329
+ sourceMaps: false,
330
+ code: false
331
+ });
332
+ tag.esmWrapper = await createEsmWrapper(
333
+ id,
334
+ getExportIdentifiers(ast)
335
+ );
336
+ }
337
+ return tag.esmWrapper;
338
+ }
285
339
  switch (getMarkoQuery(id)) {
286
340
  case serverEntryQuery: {
287
341
  const fileName = id.slice(0, -serverEntryQuery.length);
@@ -300,6 +354,7 @@ function markoPlugin(opts = {}) {
300
354
  } else {
301
355
  entryData = JSON.stringify(
302
356
  await (0, import_manifest_generator.generateDocManifest)(
357
+ basePath,
303
358
  await devServer.transformIndexHtml(
304
359
  "/",
305
360
  (0, import_manifest_generator.generateInputDoc)(posixFileNameToURL(fileName, root))
@@ -310,7 +365,8 @@ function markoPlugin(opts = {}) {
310
365
  return (0, import_server_entry_template.default)({
311
366
  fileName,
312
367
  entryData,
313
- runtimeId
368
+ runtimeId,
369
+ basePathVar
314
370
  });
315
371
  }
316
372
  case browserEntryQuery: {
@@ -336,7 +392,7 @@ function markoPlugin(opts = {}) {
336
392
  id = `${id.slice(0, -markoExt.length)}.entry.marko`;
337
393
  }
338
394
  }
339
- if (!isMarkoFile(id)) {
395
+ if (!isMarkoFile(id) || (cjsImports == null ? void 0 : cjsImports.has(id))) {
340
396
  return null;
341
397
  }
342
398
  if (ssr && entrySources.has(id)) {
@@ -420,6 +476,7 @@ if (import.meta.hot) import.meta.hot.accept(() => {});`;
420
476
  }
421
477
  if ((chunk == null ? void 0 : chunk.type) === "asset") {
422
478
  browserManifest[entryId] = await (0, import_manifest_generator.generateDocManifest)(
479
+ basePath,
423
480
  chunk.source.toString()
424
481
  );
425
482
  delete bundle[chunkId];
@@ -508,5 +565,83 @@ function isEmpty(obj) {
508
565
  }
509
566
  return true;
510
567
  }
568
+ function findPackageJson(file, root = process.cwd()) {
569
+ let currentDir = import_path.default.dirname(file);
570
+ while (currentDir !== root && currentDir.length > root.length) {
571
+ const pkgPath = import_path.default.join(currentDir, "package.json");
572
+ if (import_fs.default.existsSync(pkgPath)) {
573
+ return pkgPath;
574
+ }
575
+ currentDir = import_path.default.dirname(currentDir);
576
+ }
577
+ return null;
578
+ }
579
+ const moduleTypeMap = /* @__PURE__ */ new Map();
580
+ function getModuleType(file) {
581
+ const pkgPath = findPackageJson(file);
582
+ if (pkgPath) {
583
+ let moduleType = moduleTypeMap.get(pkgPath);
584
+ if (!moduleType) {
585
+ const pkg = JSON.parse(import_fs.default.readFileSync(pkgPath, "utf8"));
586
+ moduleType = pkg.type === "module" || pkg.exports ? "esm" : "cjs";
587
+ moduleTypeMap.set(pkgPath, moduleType);
588
+ }
589
+ return moduleType;
590
+ }
591
+ return "esm";
592
+ }
593
+ let requireHookInstalled = false;
594
+ async function createEsmWrapper(url, exports) {
595
+ if (!requireHookInstalled) {
596
+ await import("@marko/compiler/register.js");
597
+ requireHookInstalled = true;
598
+ }
599
+ let code = `import { createRequire } from 'module';
600
+ const mod = createRequire(import.meta.url)('${url}');
601
+ `;
602
+ let namedExports;
603
+ for (const name of exports) {
604
+ if (name === "default") {
605
+ code += "export default mod.default;\n";
606
+ } else if (namedExports) {
607
+ namedExports += `, ${name}`;
608
+ } else {
609
+ namedExports = name;
610
+ }
611
+ }
612
+ if (namedExports) {
613
+ code += `export const { ${namedExports} } = mod;
614
+ `;
615
+ }
616
+ return code;
617
+ }
618
+ function getExportIdentifiers(ast) {
619
+ const exports = /* @__PURE__ */ new Set();
620
+ for (const node of ast.program.body) {
621
+ switch (node.type) {
622
+ case "ExportDefaultDeclaration":
623
+ case "MarkoTag":
624
+ exports.add("default");
625
+ break;
626
+ case "ExportNamedDeclaration":
627
+ if (node.declaration) {
628
+ for (const declarator of node.declaration.declarations) {
629
+ exports.add(declarator.id.name);
630
+ }
631
+ }
632
+ for (const specifier of node.specifiers) {
633
+ if (specifier.type !== "ExportSpecifier") {
634
+ exports.add(specifier.exported.name);
635
+ }
636
+ }
637
+ break;
638
+ case "ExportAllDeclaration":
639
+ throw new Error(
640
+ 'Re-exporting using `export * from "..."` is not supported.'
641
+ );
642
+ }
643
+ }
644
+ return exports;
645
+ }
511
646
  // Annotate the CommonJS export names for ESM import in node:
512
647
  0 && (module.exports = {});
package/dist/index.mjs CHANGED
@@ -4,11 +4,11 @@ import {
4
4
  import {
5
5
  generateDocManifest,
6
6
  generateInputDoc
7
- } from "./chunk-DSFBTWOA.mjs";
8
- import "./chunk-VL2HLMVE.mjs";
7
+ } from "./chunk-FHYNYHDA.mjs";
8
+ import "./chunk-SELVH7LO.mjs";
9
9
  import {
10
10
  server_entry_template_default
11
- } from "./chunk-EYX7LIK3.mjs";
11
+ } from "./chunk-U7T7RXXE.mjs";
12
12
  import "./chunk-KIYHBIE6.mjs";
13
13
  import {
14
14
  MemoryStore
@@ -41,7 +41,7 @@ var thisFile = typeof __filename === "string" ? __filename : fileURLToPath(impor
41
41
  function markoPlugin(opts = {}) {
42
42
  var _a;
43
43
  let compiler;
44
- const { runtimeId, linked = true } = opts;
44
+ const { runtimeId, basePathVar, linked = true } = opts;
45
45
  const baseConfig = {
46
46
  cache,
47
47
  runtimeId,
@@ -60,7 +60,9 @@ function markoPlugin(opts = {}) {
60
60
  }
61
61
  };
62
62
  const resolveViteVirtualDep = (from, dep) => {
63
- const query = `${virtualFileQuery}&id=${normalizePath(dep.virtualPath)}`;
63
+ const query = `${virtualFileQuery}&id=${encodeURIComponent(
64
+ normalizePath(dep.virtualPath)
65
+ )}`;
64
66
  const normalizedFrom = normalizePath(from);
65
67
  const id = normalizePath(normalizedFrom) + query;
66
68
  if (devServer) {
@@ -96,6 +98,8 @@ function markoPlugin(opts = {}) {
96
98
  let registeredTag = false;
97
99
  let serverManifest;
98
100
  let store;
101
+ let cjsImports;
102
+ let basePath = "/";
99
103
  const entrySources = /* @__PURE__ */ new Map();
100
104
  const transformWatchFiles = /* @__PURE__ */ new Map();
101
105
  const transformOptionalFiles = /* @__PURE__ */ new Map();
@@ -106,6 +110,7 @@ function markoPlugin(opts = {}) {
106
110
  // Must be pre to allow us to resolve assets before vite.
107
111
  async config(config, env) {
108
112
  compiler ?? (compiler = await import(opts.compiler || "@marko/compiler"));
113
+ compiler.configure(baseConfig);
109
114
  root = normalizePath(config.root || process.cwd());
110
115
  devEntryFile = path.join(root, "index.html");
111
116
  devEntryFilePosix = normalizePath(devEntryFile);
@@ -130,14 +135,24 @@ function markoPlugin(opts = {}) {
130
135
  }
131
136
  const lookup = compiler.taglib.buildLookup(root);
132
137
  const taglibDeps = [];
138
+ const optimizeTaglibDeps = [];
133
139
  for (const name in lookup.taglibsById) {
134
140
  const taglib = lookup.taglibsById[name];
135
141
  if (!/^marko-(.+-)?core$/.test(taglib.id) && /[\\/]node_modules[\\/]/.test(taglib.dirname)) {
142
+ let isEsm;
136
143
  for (const tagName in taglib.tags) {
137
144
  const tag = taglib.tags[tagName];
138
145
  const entry = tag.template || tag.renderer;
139
146
  if (entry) {
140
- taglibDeps.push(relativeImportPath(devEntryFile, entry));
147
+ const relativePath = relativeImportPath(devEntryFile, entry);
148
+ taglibDeps.push(relativePath);
149
+ if (isBuild || (isEsm ?? (isEsm = getModuleType(taglib.path) === "esm"))) {
150
+ optimizeTaglibDeps.push(relativePath);
151
+ } else {
152
+ (cjsImports ?? (cjsImports = /* @__PURE__ */ new Map())).set(normalizePath(entry), {
153
+ template: tag.template
154
+ });
155
+ }
141
156
  }
142
157
  }
143
158
  }
@@ -148,7 +163,7 @@ function markoPlugin(opts = {}) {
148
163
  ...optimizeDeps.include || [],
149
164
  ...compiler.getRuntimeEntryFiles("dom", opts.translator),
150
165
  ...compiler.getRuntimeEntryFiles("html", opts.translator),
151
- ...taglibDeps
166
+ ...optimizeTaglibDeps
152
167
  ])
153
168
  );
154
169
  const optimizeExtensions = optimizeDeps.extensions ?? (optimizeDeps.extensions = []);
@@ -164,6 +179,29 @@ function markoPlugin(opts = {}) {
164
179
  )
165
180
  );
166
181
  }
182
+ if (basePathVar) {
183
+ config.experimental ?? (config.experimental = {});
184
+ if (config.experimental.renderBuiltUrl) {
185
+ throw new Error(
186
+ "Cannot use @marko/vite `basePathVar` with Vite's `renderBuiltUrl` option."
187
+ );
188
+ }
189
+ config.experimental.renderBuiltUrl = (fileName, { hostType, ssr: ssr2 }) => {
190
+ switch (hostType) {
191
+ case "html":
192
+ return fileName;
193
+ case "js":
194
+ return {
195
+ runtime: `${ssr2 ? basePathVar : `$mbp${runtimeId ? `_${runtimeId}` : ""}`}+${JSON.stringify(fileName)}`
196
+ };
197
+ default:
198
+ return { relative: true };
199
+ }
200
+ };
201
+ }
202
+ },
203
+ configResolved(config) {
204
+ basePath = config.base;
167
205
  },
168
206
  configureServer(_server) {
169
207
  ssrConfig.hot = domConfig.hot = true;
@@ -262,6 +300,22 @@ function markoPlugin(opts = {}) {
262
300
  return null;
263
301
  },
264
302
  async load(id) {
303
+ if (cjsImports == null ? void 0 : cjsImports.has(id)) {
304
+ const tag = cjsImports.get(id);
305
+ if (!tag.esmWrapper) {
306
+ const { ast } = await compiler.compileFile(tag.template, {
307
+ output: "source",
308
+ ast: true,
309
+ sourceMaps: false,
310
+ code: false
311
+ });
312
+ tag.esmWrapper = await createEsmWrapper(
313
+ id,
314
+ getExportIdentifiers(ast)
315
+ );
316
+ }
317
+ return tag.esmWrapper;
318
+ }
265
319
  switch (getMarkoQuery(id)) {
266
320
  case serverEntryQuery: {
267
321
  const fileName = id.slice(0, -serverEntryQuery.length);
@@ -280,6 +334,7 @@ function markoPlugin(opts = {}) {
280
334
  } else {
281
335
  entryData = JSON.stringify(
282
336
  await generateDocManifest(
337
+ basePath,
283
338
  await devServer.transformIndexHtml(
284
339
  "/",
285
340
  generateInputDoc(posixFileNameToURL(fileName, root))
@@ -290,7 +345,8 @@ function markoPlugin(opts = {}) {
290
345
  return server_entry_template_default({
291
346
  fileName,
292
347
  entryData,
293
- runtimeId
348
+ runtimeId,
349
+ basePathVar
294
350
  });
295
351
  }
296
352
  case browserEntryQuery: {
@@ -316,7 +372,7 @@ function markoPlugin(opts = {}) {
316
372
  id = `${id.slice(0, -markoExt.length)}.entry.marko`;
317
373
  }
318
374
  }
319
- if (!isMarkoFile(id)) {
375
+ if (!isMarkoFile(id) || (cjsImports == null ? void 0 : cjsImports.has(id))) {
320
376
  return null;
321
377
  }
322
378
  if (ssr && entrySources.has(id)) {
@@ -400,6 +456,7 @@ if (import.meta.hot) import.meta.hot.accept(() => {});`;
400
456
  }
401
457
  if ((chunk == null ? void 0 : chunk.type) === "asset") {
402
458
  browserManifest[entryId] = await generateDocManifest(
459
+ basePath,
403
460
  chunk.source.toString()
404
461
  );
405
462
  delete bundle[chunkId];
@@ -488,6 +545,84 @@ function isEmpty(obj) {
488
545
  }
489
546
  return true;
490
547
  }
548
+ function findPackageJson(file, root = process.cwd()) {
549
+ let currentDir = path.dirname(file);
550
+ while (currentDir !== root && currentDir.length > root.length) {
551
+ const pkgPath = path.join(currentDir, "package.json");
552
+ if (fs.existsSync(pkgPath)) {
553
+ return pkgPath;
554
+ }
555
+ currentDir = path.dirname(currentDir);
556
+ }
557
+ return null;
558
+ }
559
+ var moduleTypeMap = /* @__PURE__ */ new Map();
560
+ function getModuleType(file) {
561
+ const pkgPath = findPackageJson(file);
562
+ if (pkgPath) {
563
+ let moduleType = moduleTypeMap.get(pkgPath);
564
+ if (!moduleType) {
565
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
566
+ moduleType = pkg.type === "module" || pkg.exports ? "esm" : "cjs";
567
+ moduleTypeMap.set(pkgPath, moduleType);
568
+ }
569
+ return moduleType;
570
+ }
571
+ return "esm";
572
+ }
573
+ var requireHookInstalled = false;
574
+ async function createEsmWrapper(url, exports) {
575
+ if (!requireHookInstalled) {
576
+ await import("@marko/compiler/register.js");
577
+ requireHookInstalled = true;
578
+ }
579
+ let code = `import { createRequire } from 'module';
580
+ const mod = createRequire(import.meta.url)('${url}');
581
+ `;
582
+ let namedExports;
583
+ for (const name of exports) {
584
+ if (name === "default") {
585
+ code += "export default mod.default;\n";
586
+ } else if (namedExports) {
587
+ namedExports += `, ${name}`;
588
+ } else {
589
+ namedExports = name;
590
+ }
591
+ }
592
+ if (namedExports) {
593
+ code += `export const { ${namedExports} } = mod;
594
+ `;
595
+ }
596
+ return code;
597
+ }
598
+ function getExportIdentifiers(ast) {
599
+ const exports = /* @__PURE__ */ new Set();
600
+ for (const node of ast.program.body) {
601
+ switch (node.type) {
602
+ case "ExportDefaultDeclaration":
603
+ case "MarkoTag":
604
+ exports.add("default");
605
+ break;
606
+ case "ExportNamedDeclaration":
607
+ if (node.declaration) {
608
+ for (const declarator of node.declaration.declarations) {
609
+ exports.add(declarator.id.name);
610
+ }
611
+ }
612
+ for (const specifier of node.specifiers) {
613
+ if (specifier.type !== "ExportSpecifier") {
614
+ exports.add(specifier.exported.name);
615
+ }
616
+ }
617
+ break;
618
+ case "ExportAllDeclaration":
619
+ throw new Error(
620
+ 'Re-exporting using `export * from "..."` is not supported.'
621
+ );
622
+ }
623
+ }
624
+ return exports;
625
+ }
491
626
  export {
492
627
  FileStore,
493
628
  MemoryStore,
@@ -6,6 +6,6 @@ export interface DocManifest {
6
6
  "body-prepend": SerializedOrNull;
7
7
  body: SerializedOrNull;
8
8
  }
9
- export declare function generateDocManifest(rawHtml: string): Promise<DocManifest>;
9
+ export declare function generateDocManifest(basePath: string, rawHtml: string): Promise<DocManifest>;
10
10
  export declare function generateInputDoc(entry: string): string;
11
11
  export {};
@@ -37,7 +37,7 @@ var import_domelementtype = require("domelementtype");
37
37
  var import_domhandler = require("domhandler");
38
38
  var import_serializer = __toESM(require("./serializer"));
39
39
  const MARKER_COMMENT = "MARKO_VITE";
40
- function generateDocManifest(rawHtml) {
40
+ function generateDocManifest(basePath, rawHtml) {
41
41
  return new Promise((resolve, reject) => {
42
42
  const parser = new import_htmlparser2.Parser(
43
43
  new import_domhandler.DomHandler(function(err, dom) {
@@ -64,10 +64,10 @@ function generateDocManifest(rawHtml) {
64
64
  body
65
65
  );
66
66
  resolve({
67
- "head-prepend": serializeOrNull(headPrepend),
68
- head: serializeOrNull(head),
69
- "body-prepend": serializeOrNull(bodyPrepend),
70
- body: serializeOrNull(body)
67
+ "head-prepend": serializeOrNull(basePath, headPrepend),
68
+ head: serializeOrNull(basePath, head),
69
+ "body-prepend": serializeOrNull(basePath, bodyPrepend),
70
+ body: serializeOrNull(basePath, body)
71
71
  });
72
72
  })
73
73
  );
@@ -80,8 +80,8 @@ function generateInputDoc(entry) {
80
80
  entry
81
81
  )}></script></body></html>`;
82
82
  }
83
- function serializeOrNull(nodes) {
84
- const result = (0, import_serializer.default)(nodes);
83
+ function serializeOrNull(basePath, nodes) {
84
+ const result = (0, import_serializer.default)(basePath, nodes);
85
85
  if (result.length) {
86
86
  return result;
87
87
  }
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generateDocManifest,
3
3
  generateInputDoc
4
- } from "./chunk-DSFBTWOA.mjs";
5
- import "./chunk-VL2HLMVE.mjs";
4
+ } from "./chunk-FHYNYHDA.mjs";
5
+ import "./chunk-SELVH7LO.mjs";
6
6
  export {
7
7
  generateDocManifest,
8
8
  generateInputDoc
@@ -1,2 +1,7 @@
1
1
  import type { Node } from "domhandler";
2
- export default function serialize(nodes: Node[], parts?: string[]): string[];
2
+ declare enum InjectType {
3
+ AssetAttrs = 0,
4
+ PublicPath = 1
5
+ }
6
+ export default function serialize(basePath: string, nodes: Node[], parts?: (string | InjectType)[]): (string | InjectType)[];
7
+ export {};
@@ -22,6 +22,11 @@ __export(serializer_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(serializer_exports);
24
24
  var import_domelementtype = require("domelementtype");
25
+ var InjectType = /* @__PURE__ */ ((InjectType2) => {
26
+ InjectType2[InjectType2["AssetAttrs"] = 0] = "AssetAttrs";
27
+ InjectType2[InjectType2["PublicPath"] = 1] = "PublicPath";
28
+ return InjectType2;
29
+ })(InjectType || {});
25
30
  const voidElements = /* @__PURE__ */ new Set([
26
31
  "area",
27
32
  "base",
@@ -38,7 +43,7 @@ const voidElements = /* @__PURE__ */ new Set([
38
43
  "track",
39
44
  "wbr"
40
45
  ]);
41
- function serialize(nodes, parts) {
46
+ function serialize(basePath, nodes, parts) {
42
47
  let curString = parts ? parts.pop() : "";
43
48
  parts ?? (parts = []);
44
49
  for (const node of nodes) {
@@ -48,30 +53,45 @@ function serialize(nodes, parts) {
48
53
  case import_domelementtype.ElementType.Script: {
49
54
  const tag = node;
50
55
  const { name } = tag;
56
+ let urlAttr;
51
57
  curString += `<${name}`;
52
58
  switch (tag.tagName) {
53
59
  case "script":
54
- parts.push(curString);
60
+ parts.push(curString, 0 /* AssetAttrs */);
61
+ urlAttr = "src";
55
62
  curString = "";
56
63
  break;
57
64
  case "style":
58
- parts.push(curString);
65
+ parts.push(curString, 0 /* AssetAttrs */);
59
66
  curString = "";
60
67
  break;
61
68
  case "link":
62
69
  if (tag.attribs.rel === "stylesheet") {
63
- parts.push(curString);
70
+ urlAttr = "href";
71
+ parts.push(curString, 0 /* AssetAttrs */);
64
72
  curString = "";
65
73
  }
66
74
  break;
67
75
  }
68
76
  for (const attr of tag.attributes) {
69
- curString += ` ${attr.value === "" ? attr.name : `${attr.name}="${attr.value.replace(/"/g, "&#39;")}"`}`;
77
+ if (attr.value === "") {
78
+ curString += ` ${attr.name}`;
79
+ } else if (attr.name === urlAttr) {
80
+ curString += ` ${attr.name}="`;
81
+ parts.push(
82
+ curString,
83
+ 1 /* PublicPath */,
84
+ stripBasePath(basePath, attr.value).replace(/"/g, "&#39;").replace(/^\.\//, "") + '"'
85
+ );
86
+ curString = "";
87
+ } else {
88
+ curString += ` ${attr.name}="${attr.value.replace(/"/g, "&#39;")}"`;
89
+ }
70
90
  }
71
91
  curString += ">";
72
92
  if (tag.children.length) {
73
93
  parts.push(curString);
74
- serialize(tag.children, parts);
94
+ serialize(basePath, tag.children, parts);
75
95
  curString = parts.pop();
76
96
  }
77
97
  if (!voidElements.has(name)) {
@@ -96,5 +116,10 @@ function serialize(nodes, parts) {
96
116
  }
97
117
  return parts;
98
118
  }
119
+ function stripBasePath(basePath, path) {
120
+ if (path.startsWith(basePath))
121
+ return path.slice(basePath.length);
122
+ return path;
123
+ }
99
124
  // Annotate the CommonJS export names for ESM import in node:
100
125
  0 && (module.exports = {});
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  serialize
3
- } from "./chunk-VL2HLMVE.mjs";
3
+ } from "./chunk-SELVH7LO.mjs";
4
4
  export {
5
5
  serialize as default
6
6
  };
@@ -2,5 +2,6 @@ declare const _default: (opts: {
2
2
  fileName: string;
3
3
  entryData: string;
4
4
  runtimeId?: string;
5
+ basePathVar?: string;
5
6
  }) => Promise<string>;
6
7
  export default _default;
@@ -34,17 +34,21 @@ module.exports = __toCommonJS(server_entry_template_exports);
34
34
  var import_path = __toESM(require("path"));
35
35
  var server_entry_template_default = async (opts) => {
36
36
  const fileNameStr = JSON.stringify(`./${import_path.default.basename(opts.fileName)}`);
37
+ const base = opts.basePathVar ? ` base=${opts.basePathVar}` : "";
37
38
  return `import template from ${fileNameStr};
38
39
  export * from ${fileNameStr};
39
- ${opts.runtimeId ? `$ out.global.runtimeId = ${JSON.stringify(opts.runtimeId)};
40
+ ${opts.basePathVar ? `
41
+ static if (typeof ${opts.basePathVar} !== "string") throw new Error("${opts.basePathVar} must be defined when using basePathVar.");
42
+ static if (!${opts.basePathVar}.endsWith("/")) throw new Error("${opts.basePathVar} must end with a '/' when using basePathVar.");
43
+ ` : ""}${opts.runtimeId ? `$ out.global.runtimeId = ${JSON.stringify(opts.runtimeId)};
40
44
  ` : ""}$ (out.global.___viteEntries || (out.global.___viteEntries = [])).push(${opts.entryData});
41
- <_vite slot="head-prepend"/>
42
- <_vite slot="head"/>
43
- <_vite slot="body-prepend"/>
45
+ <_vite${base} slot="head-prepend"/>
46
+ <_vite${base} slot="head"/>
47
+ <_vite${base} slot="body-prepend"/>
44
48
  <\${template} ...input/>
45
49
  <init-components/>
46
50
  <await-reorderer/>
47
- <_vite slot="body"/>
51
+ <_vite${base} slot="body"/>
48
52
  `;
49
53
  };
50
54
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  server_entry_template_default
3
- } from "./chunk-EYX7LIK3.mjs";
3
+ } from "./chunk-U7T7RXXE.mjs";
4
4
  export {
5
5
  server_entry_template_default as default
6
6
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@marko/vite",
3
3
  "description": "A Marko plugin for Vite",
4
- "version": "2.3.14",
4
+ "version": "2.4.0",
5
5
  "author": "Dylan Piercey <dpiercey@ebay.com>",
6
6
  "bugs": "https://github.com/marko-js/vite/issues",
7
7
  "dependencies": {
@@ -1,21 +0,0 @@
1
- // src/server-entry-template.ts
2
- import path from "path";
3
- var server_entry_template_default = async (opts) => {
4
- const fileNameStr = JSON.stringify(`./${path.basename(opts.fileName)}`);
5
- return `import template from ${fileNameStr};
6
- export * from ${fileNameStr};
7
- ${opts.runtimeId ? `$ out.global.runtimeId = ${JSON.stringify(opts.runtimeId)};
8
- ` : ""}$ (out.global.___viteEntries || (out.global.___viteEntries = [])).push(${opts.entryData});
9
- <_vite slot="head-prepend"/>
10
- <_vite slot="head"/>
11
- <_vite slot="body-prepend"/>
12
- <\${template} ...input/>
13
- <init-components/>
14
- <await-reorderer/>
15
- <_vite slot="body"/>
16
- `;
17
- };
18
-
19
- export {
20
- server_entry_template_default
21
- };