diff --git a/.changeset/sharp-guests-know.md b/.changeset/sharp-guests-know.md
new file mode 100644
index 0000000..0568cf4
--- /dev/null
+++ b/.changeset/sharp-guests-know.md
@@ -0,0 +1,5 @@
+---
+"@marko/vite": minor
+---
+
+Support inline relative asset paths from native tags.
diff --git a/README.md b/README.md
index 78ca24e..6f26f21 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,21 @@ export default defineConfig({
});
```
+# Browser asset references
+
+With @marko/vite when a _static relative path_ is used for certain native tag attributes, the relative asset will be imported and processed by Vite.
+
+As an example, with the following template, the `logo.svg` will be imported and processed as if it was a `import` at the root of the file.
+
+```
+
+
+// Would produce a Vite processed asset and update the src, eg with the following output
+
+```
+
+You can see the list of elements and their attributes which are processed [here](./src/relative-assets-transform.ts).
+
# Linked Mode
By default this plugin operates in `linked` mode (you can disabled this by passing [`linked: false` as an option](#options.linked)). In `linked` mode the plugin automatically discovers all of the entry `.marko` files while compiling the server, and tells `Vite` which modules to load in the browser.
diff --git a/package-lock.json b/package-lock.json
index d939ede..048c3a4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -25,7 +25,7 @@
"@types/babel__core": "^7.20.4",
"@types/jsdom": "^21.1.5",
"@types/mocha": "^10.0.4",
- "@types/node": "^20.9.0",
+ "@types/node": "^20.9.1",
"@types/resolve": "^1.20.5",
"@types/serve-handler": "^6.1.4",
"@typescript-eslint/eslint-plugin": "^6.11.0",
@@ -42,12 +42,12 @@
"mocha": "^10.2.0",
"mocha-snap": "^5.0.0",
"nyc": "^15.1.0",
- "playwright": "^1.39.0",
+ "playwright": "^1.40.0",
"prettier": "^3.1.0",
"serve-handler": "^6.1.5",
"tsx": "^4.1.2",
"typescript": "^5.2.2",
- "vite": "^5.0.0-beta.17"
+ "vite": "^5.0.0"
},
"peerDependencies": {
"@marko/compiler": "^5",
@@ -1981,9 +1981,9 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "20.9.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz",
- "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==",
+ "version": "20.9.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.1.tgz",
+ "integrity": "sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -3470,9 +3470,9 @@
"dev": true
},
"node_modules/electron-to-chromium": {
- "version": "1.4.582",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.582.tgz",
- "integrity": "sha512-89o0MGoocwYbzqUUjc+VNpeOFSOK9nIdC5wY4N+PVUarUK0MtjyTjks75AZS2bW4Kl8MdewdFsWaH0jLy+JNoA==",
+ "version": "1.4.586",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.586.tgz",
+ "integrity": "sha512-qMa+E6yf1fNQbg3G66pHLXeJUP5CCCzNat1VPczOZOqgI2w4u+8y9sQnswMdGs5m4C1rOePq37EVBr/nsPQY7w==",
"dev": true
},
"node_modules/emoji-regex": {
@@ -4955,9 +4955,9 @@
}
},
"node_modules/ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
+ "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
"dev": true,
"engines": {
"node": ">= 4"
@@ -7221,12 +7221,12 @@
}
},
"node_modules/playwright": {
- "version": "1.39.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz",
- "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==",
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.0.tgz",
+ "integrity": "sha512-gyHAgQjiDf1m34Xpwzaqb76KgfzYrhK7iih+2IzcOCoZWr/8ZqmdBw+t0RU85ZmfJMgtgAiNtBQ/KS2325INXw==",
"dev": true,
"dependencies": {
- "playwright-core": "1.39.0"
+ "playwright-core": "1.40.0"
},
"bin": {
"playwright": "cli.js"
@@ -7239,9 +7239,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.39.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz",
- "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==",
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.0.tgz",
+ "integrity": "sha512-fvKewVJpGeca8t0ipM56jkVSU6Eo0RmFvQ/MaCQNDYm+sdvKkMBBWTE1FdeMqIdumRaXXjZChWHvIzCGM/tA/Q==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
@@ -9677,9 +9677,9 @@
}
},
"node_modules/vite": {
- "version": "5.0.0-beta.19",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.0-beta.19.tgz",
- "integrity": "sha512-Huoj7XUlkhSLHhIOf4FgDrxmHJMKgfvG9ocB4kJmTKSeWfLgHIQ86xYC8+eA/RBxFo9zRQXX81VUgW8l7Wri3Q==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.0.tgz",
+ "integrity": "sha512-ESJVM59mdyGpsiNAeHQOR/0fqNoOyWPYesFto8FFZugfmhdHx8Fzd8sF3Q/xkVhZsyOxHfdM7ieiVAorI9RjFw==",
"dev": true,
"dependencies": {
"esbuild": "^0.19.3",
diff --git a/package.json b/package.json
index f404c68..c915903 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
"@types/babel__core": "^7.20.4",
"@types/jsdom": "^21.1.5",
"@types/mocha": "^10.0.4",
- "@types/node": "^20.9.0",
+ "@types/node": "^20.9.1",
"@types/resolve": "^1.20.5",
"@types/serve-handler": "^6.1.4",
"@typescript-eslint/eslint-plugin": "^6.11.0",
@@ -38,12 +38,12 @@
"mocha": "^10.2.0",
"mocha-snap": "^5.0.0",
"nyc": "^15.1.0",
- "playwright": "^1.39.0",
+ "playwright": "^1.40.0",
"prettier": "^3.1.0",
"serve-handler": "^6.1.5",
"tsx": "^4.1.2",
"typescript": "^5.2.2",
- "vite": "^5.0.0-beta.17"
+ "vite": "^5.0.0"
},
"files": [
"dist",
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.loading.0.html b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.loading.0.html
new file mode 100644
index 0000000..e415c58
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.loading.0.html
@@ -0,0 +1,13 @@
+
+
+ Mounted: false Clicks: 0
+
+
+
\ No newline at end of file
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.loading.1.html b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.loading.1.html
new file mode 100644
index 0000000..bf208a0
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.loading.1.html
@@ -0,0 +1,13 @@
+
+
+ Mounted: true Clicks: 0
+
+
+
\ No newline at end of file
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.step-0.0.html b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.step-0.0.html
new file mode 100644
index 0000000..b061209
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/build.expected.step-0.0.html
@@ -0,0 +1,13 @@
+
+
+ Mounted: true Clicks: 1
+
+
+
\ No newline at end of file
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.loading.0.html b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.loading.0.html
new file mode 100644
index 0000000..88fc941
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.loading.0.html
@@ -0,0 +1,13 @@
+
+
+ Mounted: false Clicks: 0
+
+
+
\ No newline at end of file
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.loading.1.html b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.loading.1.html
new file mode 100644
index 0000000..8e906ce
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.loading.1.html
@@ -0,0 +1,13 @@
+
+
+ Mounted: true Clicks: 0
+
+
+
\ No newline at end of file
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.step-0.0.html b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.step-0.0.html
new file mode 100644
index 0000000..90baa51
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/__snapshots__/dev.expected.step-0.0.html
@@ -0,0 +1,13 @@
+
+
+ Mounted: true Clicks: 1
+
+
+
\ No newline at end of file
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/dev-server.mjs b/src/__tests__/fixtures/isomorphic-relative-asset-import/dev-server.mjs
new file mode 100644
index 0000000..64b889d
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/dev-server.mjs
@@ -0,0 +1,38 @@
+// In dev we'll start a Vite dev server in middleware mode,
+// and forward requests to our http request handler.
+
+import { createServer } from "vite";
+import path from "path";
+import url from "url";
+import { createRequire } from "module";
+
+// change to import once marko-vite is updated to ESM
+const markoPlugin = createRequire(import.meta.url)("../../..").default;
+
+const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
+
+const devServer = await createServer({
+ root: __dirname,
+ appType: "custom",
+ logLevel: "silent",
+ plugins: [markoPlugin()],
+ optimizeDeps: { force: true },
+ server: {
+ middlewareMode: true,
+ watch: {
+ ignored: ["**/node_modules/**", "**/dist/**", "**/__snapshots__/**"],
+ },
+ },
+});
+
+export default devServer.middlewares.use(async (req, res, next) => {
+ try {
+ const { handler } = await devServer.ssrLoadModule(
+ path.join(__dirname, "./src/index.js")
+ );
+ await handler(req, res, next);
+ } catch (err) {
+ devServer.ssrFixStacktrace(err);
+ return next(err);
+ }
+});
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/server.mjs b/src/__tests__/fixtures/isomorphic-relative-asset-import/server.mjs
new file mode 100644
index 0000000..7f0d142
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/server.mjs
@@ -0,0 +1,18 @@
+// In production, simply start up the http server.
+import path from 'path'
+import url from 'url';
+import { createServer } from "http";
+import serve from "serve-handler";
+
+globalThis.assetsPath = "/my-prefix/";
+// dyanmic import so globalThis.assetsPath can be set prior to the imported code executing
+const { handler } = await import("./dist/index.mjs");
+
+const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
+const serveOpts = { public: path.resolve(__dirname, "dist") };
+
+export default createServer(async (req, res) => {
+ await handler(req, res);
+ if (res.headersSent) return;
+ await serve(req, res, serveOpts);
+});
diff --git a/src/__tests__/fixtures/isomorphic-relative-asset-import/src/components/class-component.marko b/src/__tests__/fixtures/isomorphic-relative-asset-import/src/components/class-component.marko
new file mode 100644
index 0000000..bc17cc9
--- /dev/null
+++ b/src/__tests__/fixtures/isomorphic-relative-asset-import/src/components/class-component.marko
@@ -0,0 +1,22 @@
+class {
+ onCreate() {
+ this.state = {
+ clickCount: 0,
+ mounted: false
+ };
+ }
+ onMount() {
+ this.state.mounted = true;
+ }
+
+ handleClick() {
+ this.state.clickCount++;
+ }
+}
+
+