├── .husky └── pre-commit ├── src ├── __tests__ │ ├── fixtures │ │ ├── isomorphic-commonjs-jk │ │ │ ├── test.config.ts │ │ │ ├── node_modules │ │ │ │ ├── transient-dep │ │ │ │ │ ├── index.js │ │ │ │ │ ├── index.mjs │ │ │ │ │ └── package.json │ │ │ │ └── dep │ │ │ │ │ ├── package.json │ │ │ │ │ └── index.js │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ ├── package.json │ │ │ ├── vite.config.mts │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ └── index.js │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-commonjs-dir-import │ │ │ ├── test.config.ts │ │ │ ├── node_modules │ │ │ │ └── test-package │ │ │ │ │ ├── sub │ │ │ │ │ ├── index.js │ │ │ │ │ └── package.json │ │ │ │ │ └── package.json │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── index.js │ │ │ │ ├── template.marko │ │ │ │ └── components │ │ │ │ │ └── layout-component.marko │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-custom-entries │ │ │ ├── src │ │ │ │ ├── other.marko │ │ │ │ ├── template.marko │ │ │ │ ├── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ └── class-component.marko │ │ │ │ └── index.js │ │ │ ├── package.json │ │ │ ├── __snapshots__ │ │ │ │ ├── dev.expected.md │ │ │ │ └── build.expected.md │ │ │ ├── test.config.ts │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-relative-asset-import │ │ │ ├── src │ │ │ │ ├── components │ │ │ │ │ ├── script.js │ │ │ │ │ ├── styles.css │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ ├── class-component.marko │ │ │ │ │ └── logo.svg │ │ │ │ ├── template.marko │ │ │ │ └── index.js │ │ │ ├── test.config.ts │ │ │ ├── server.mjs │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ └── dev-server.mjs │ │ ├── isomorphic-commonjs-svg │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ └── class-component.marko │ │ │ │ └── index.js │ │ │ ├── node_modules │ │ │ │ └── test-package │ │ │ │ │ ├── marko.json │ │ │ │ │ ├── package.json │ │ │ │ │ └── components │ │ │ │ │ ├── test-button │ │ │ │ │ └── index.marko │ │ │ │ │ └── test-icon │ │ │ │ │ ├── index.marko │ │ │ │ │ └── icon.svg │ │ │ ├── test.config.ts │ │ │ ├── package.json │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-css-loader-import │ │ │ ├── node_modules │ │ │ │ └── test-package │ │ │ │ │ ├── style.css │ │ │ │ │ └── package.json │ │ │ ├── src │ │ │ │ ├── components │ │ │ │ │ └── local-component │ │ │ │ │ │ ├── index.marko │ │ │ │ │ │ └── style.less │ │ │ │ ├── template.marko │ │ │ │ └── index.js │ │ │ ├── test.config.ts │ │ │ ├── __snapshots__ │ │ │ │ ├── dev.expected.md │ │ │ │ └── build.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-ssr-asset │ │ │ ├── test.config.ts │ │ │ ├── __snapshots__ │ │ │ │ ├── dev.expected.md │ │ │ │ └── build.expected.md │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── index.js │ │ │ │ └── image.svg │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── browser-marko-dep │ │ │ ├── node_modules │ │ │ │ └── test-package │ │ │ │ │ ├── marko.json │ │ │ │ │ ├── package.json │ │ │ │ │ └── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ └── class-component.marko │ │ │ ├── test.config.ts │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── index.js │ │ │ │ └── template.marko │ │ │ ├── index.html │ │ │ └── __snapshots__ │ │ │ │ ├── dev.expected.md │ │ │ │ └── build.expected.md │ │ ├── isomorphic-marko-dep │ │ │ ├── node_modules │ │ │ │ └── test-package │ │ │ │ │ ├── package.json │ │ │ │ │ ├── marko.json │ │ │ │ │ └── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ └── class-component.marko │ │ │ ├── package.json │ │ │ ├── test.config.ts │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── index.js │ │ │ │ └── components │ │ │ │ │ └── layout-component.marko │ │ │ ├── __snapshots__ │ │ │ │ ├── dev.expected.md │ │ │ │ └── build.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-commonjs │ │ │ ├── node_modules │ │ │ │ ├── test-package │ │ │ │ │ ├── marko.json │ │ │ │ │ ├── package.json │ │ │ │ │ └── components │ │ │ │ │ │ ├── test-button │ │ │ │ │ │ ├── foo.js │ │ │ │ │ │ ├── index.marko │ │ │ │ │ │ └── component-browser.js │ │ │ │ │ │ └── test-imports │ │ │ │ │ │ └── index.marko │ │ │ │ └── test-package2 │ │ │ │ │ ├── cjs-exports.js │ │ │ │ │ ├── esm.mjs │ │ │ │ │ ├── package.json │ │ │ │ │ ├── cjs-module.exports.js │ │ │ │ │ └── esm2cjs.js │ │ │ ├── package.json │ │ │ ├── test.config.ts │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ └── class-component.marko │ │ │ │ └── index.js │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── browser-basic │ │ │ ├── test.config.ts │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── index.js │ │ │ │ └── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ └── class-component.marko │ │ │ ├── index.html │ │ │ └── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ ├── browser-marko-shorthand-import │ │ │ ├── node_modules │ │ │ │ └── test-package │ │ │ │ │ ├── package.json │ │ │ │ │ ├── marko.json │ │ │ │ │ └── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ └── class-component.marko │ │ │ ├── test.config.ts │ │ │ ├── package.json │ │ │ ├── src │ │ │ │ ├── index.js │ │ │ │ └── components │ │ │ │ │ └── page.marko │ │ │ ├── index.html │ │ │ └── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ ├── isomorphic-basic │ │ │ ├── test.config.ts │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ └── class-component.marko │ │ │ │ └── index.js │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-glob-import │ │ │ ├── test.config.ts │ │ │ ├── src │ │ │ │ ├── components │ │ │ │ │ └── layout-component.marko │ │ │ │ ├── index.js │ │ │ │ ├── template.marko │ │ │ │ └── modules │ │ │ │ │ └── class-component.marko │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-tags-api-basic │ │ │ ├── test.config.ts │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── tags │ │ │ │ │ ├── stateless.marko │ │ │ │ │ ├── stateful.marko │ │ │ │ │ └── layout.marko │ │ │ │ └── index.js │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-circular-entry-file │ │ │ ├── test.config.ts │ │ │ ├── src │ │ │ │ ├── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ └── class-component.marko │ │ │ │ ├── index.js │ │ │ │ └── template.marko │ │ │ ├── __snapshots__ │ │ │ │ ├── dev.expected.md │ │ │ │ └── build.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-bundle-splitting │ │ │ ├── src │ │ │ │ ├── components │ │ │ │ │ ├── split-bundle-map.js │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ └── class-component.marko │ │ │ │ ├── template.marko │ │ │ │ └── index.js │ │ │ ├── test.config.ts │ │ │ ├── __snapshots__ │ │ │ │ ├── dev.expected.md │ │ │ │ └── build.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-base-url │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ ├── class-component.marko │ │ │ │ │ └── logo.svg │ │ │ │ └── index.js │ │ │ ├── test.config.ts │ │ │ ├── __snapshots__ │ │ │ │ ├── build.expected.md │ │ │ │ └── dev.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ ├── isomorphic-runtime-base-path │ │ │ ├── src │ │ │ │ ├── template.marko │ │ │ │ ├── components │ │ │ │ │ ├── implicit-component.marko │ │ │ │ │ ├── layout-component.marko │ │ │ │ │ ├── class-component.marko │ │ │ │ │ └── logo.svg │ │ │ │ └── index.js │ │ │ ├── __snapshots__ │ │ │ │ ├── dev.expected.md │ │ │ │ └── build.expected.md │ │ │ ├── test.config.ts │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ │ └── isomorphic-modulepreload │ │ │ ├── src │ │ │ ├── components │ │ │ │ ├── implicit-component.marko │ │ │ │ ├── layout-component.marko │ │ │ │ ├── read-head.marko │ │ │ │ ├── class-component.marko │ │ │ │ └── logo.svg │ │ │ ├── template.marko │ │ │ └── index.js │ │ │ ├── test.config.ts │ │ │ ├── __snapshots__ │ │ │ ├── dev.expected.md │ │ │ └── build.expected.md │ │ │ ├── server.mjs │ │ │ └── dev-server.mjs │ └── main.test.ts ├── render-assets-transform.ts ├── read-once-persisted-store.ts ├── server-entry-template.ts ├── resolve.ts ├── relative-assets-transform.ts ├── glob-import-transform.ts ├── manifest-generator.ts ├── esbuild-plugin.ts ├── render-assets-runtime.ts ├── serializer.ts └── cjs-interop-translate.ts ├── .lintstagedrc.json ├── .prettierrc.json ├── .prettierignore ├── .mocharc.json ├── .nycrc.json ├── .changeset ├── config.json └── README.md ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── Feature_request.md │ └── Bug_report.md ├── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md └── workflows │ └── ci.yml ├── tsconfig.json ├── LICENSE ├── eslint.config.mjs ├── package.json └── README.md /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm exec lint-staged 2 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/src/other.marko: -------------------------------------------------------------------------------- 1 | 2 |
3 | Hello 4 |
-------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/node_modules/transient-dep/index.js: -------------------------------------------------------------------------------- 1 | exports.thing = () => 'thing'; -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/src/components/script.js: -------------------------------------------------------------------------------- 1 | globalThis.hello = "world"; 2 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/node_modules/test-package/sub/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'foo'; -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/node_modules/transient-dep/index.mjs: -------------------------------------------------------------------------------- 1 | export const thing = () => 'thing'; -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/src/template.marko: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/node_modules/test-package/style.css: -------------------------------------------------------------------------------- 1 | #app { 2 | color: blue 3 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/src/components/local-component/index.marko: -------------------------------------------------------------------------------- 1 |
Test
2 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/src/components/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: green; 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-ssr-asset/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export const steps = []; 3 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/node_modules/test-package/marko.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags-dir": "./components" 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/node_modules/test-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package" 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/node_modules/test-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package" 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/node_modules/test-package/marko.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags-dir": "./components" 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() {} 3 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package/marko.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags-dir": "./components" 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/node_modules/test-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package" 3 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/node_modules/test-package/marko.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags-dir": "./components" 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-basic/test.config.ts: -------------------------------------------------------------------------------- 1 | export async function steps() { 2 | await page.click("#clickable"); 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/node_modules/test-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package" 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/node_modules/test-package/sub/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "sideEffects:": false 3 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() {} 3 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "test-package": "0.0.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "*.ts": ["eslint --fix", "prettier --write"], 3 | "*{.js,.json,.md,.yml,rc}": ["prettier --write"] 4 | } 5 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "plugins": ["prettier-plugin-packagejson"] 4 | } 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/test.config.ts: -------------------------------------------------------------------------------- 1 | export async function steps() { 2 | await page.click("#clickable"); 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/node_modules/test-package/marko.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags-dir": "./components" 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | foo 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | foo 5 | ``` 6 | 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .nyc_output 3 | package-lock.json 4 | CHANGELOG.md 5 | node_modules 6 | coverage 7 | dist 8 | __snapshots__ 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package", 3 | "type": "commonjs" 4 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/test.config.ts: -------------------------------------------------------------------------------- 1 | export async function steps() { 2 | await page.click("#clickable"); 3 | } 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/node_modules/test-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package", 3 | "type": "commonjs" 4 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package2/cjs-exports.js: -------------------------------------------------------------------------------- 1 | exports.ONE = 1; 2 | exports.TWO = 2; 3 | exports.default = 'd'; -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package2/esm.mjs: -------------------------------------------------------------------------------- 1 | export const ONE = 1; 2 | export const TWO = 2; 3 | export default 'd'; -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package2", 3 | "type": "commonjs" 4 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-basic/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/node_modules/test-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-package", 3 | "version": "1.0.0" 4 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |

5 | thing via dep 6 |

7 | ``` 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |

5 | thing via dep 6 |

7 | ``` 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/node_modules/test-package/components/test-button/index.marko: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | await page.click("#clickable"); 4 | } 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/src/components/local-component/style.less: -------------------------------------------------------------------------------- 1 | @import "~test-package/style.css"; 2 | a { 3 | color: green 4 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-basic/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | template.renderSync().appendTo(document.getElementById("app")); 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browser-marko-dep", 3 | "dependencies": { 4 | "test-package": "0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isomorphic-commonjs-jk", 3 | "dependencies": { 4 | "dep": "0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package2/cjs-module.exports.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ONE: 1, 3 | TWO: 2, 4 | default: 'd' 5 | } 6 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isomorphic-commonjs", 3 | "dependencies": { 4 | "test-package": "0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | await page.click("#clickable"); 4 | } 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | await page.click("#clickable"); 4 | } 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | template.renderSync().appendTo(document.getElementById("app")); 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isomorphic-commonjs", 3 | "dependencies": { 4 | "test-package": "0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-glob-import/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | await page.click("#clickable"); 4 | } 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | await page.click("#clickable"); 4 | } 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browser-marko-dep", 3 | "dependencies": { 4 | "test-package": "0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/src/index.js: -------------------------------------------------------------------------------- 1 | import template from ""; 2 | 3 | template.renderSync().appendTo(document.getElementById("app")); 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | await page.click("#clickable"); 4 | } 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/node_modules/test-package/components/test-icon/index.marko: -------------------------------------------------------------------------------- 1 | import icon from "./icon.svg"; 2 | 3 | icon 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isomorphic-commonjs", 3 | "dependencies": { 4 | "test-package": "0.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/src/components/split-bundle-map.js: -------------------------------------------------------------------------------- 1 | import classComponent from "./class-component.marko"; 2 | 3 | export { classComponent }; 4 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | await page.click("#clickable"); 4 | } 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 |

test marko dep

6 | 7 | 8 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-ssr-asset/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | image 8 | ``` 9 | 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/vite.config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | export default defineConfig({ 4 | ssr: { 5 | noExternal: ["dep"] 6 | } 7 | }) -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
5 | Test 6 |
7 | ``` 8 | 9 | # Step 0 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | import { classComponent } from "./split-bundle-map"; 2 | 3 | <${classComponent}/> 4 | <${classComponent}/> -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
5 | Test 6 |
7 | ``` 8 | 9 | # Step 0 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-ssr-asset/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | image 8 | ``` 9 | 10 | -------------------------------------------------------------------------------- /.mocharc.json: -------------------------------------------------------------------------------- 1 | { 2 | "exit": true, 3 | "timeout": 20000, 4 | "extension": ["js", "ts", "marko"], 5 | "watchFiles": ["src/**/*.ts", "src/**/*.marko"], 6 | "require": ["tsx", "mocha-snap"] 7 | } 8 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/src/components/page.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 |

test marko dep

6 | 7 | 8 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-base-url/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/src/template.marko: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isomorphic-commonjs-dir-import", 3 | "type": "commonjs", 4 | "dependencies": { 5 | "test-package": "0.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package/components/test-button/foo.js: -------------------------------------------------------------------------------- 1 | "use strict";exports.__esModule = true;exports.getFoo = getFoo; 2 | 3 | function getFoo() { 4 | return "foo" 5 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/node_modules/dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dep", 3 | "type": "commonjs", 4 | "main": "./index.js", 5 | "dependencies": { 6 | "transient-dep": "0.0.0" 7 | } 8 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-runtime-base-path/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | for (const el of await page.$$(".clickable")) { 4 | await el.click(); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-base-url/test.config.ts: -------------------------------------------------------------------------------- 1 | export const ssr = true; 2 | export async function steps() { 3 | await page.click("#clickable"); 4 | } 5 | 6 | export const env = { 7 | BASE_URL: "some/base/path/", 8 | }; 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/node_modules/dep/index.js: -------------------------------------------------------------------------------- 1 | Object.defineProperty(exports, "__esModule", { 2 | value: true 3 | }); 4 | const mod = require('transient-dep'); 5 | 6 | exports.thing = () => mod.thing() + ' via dep'; -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package/components/test-button/index.marko: -------------------------------------------------------------------------------- 1 | import { getFoo } from "./foo" 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-glob-import/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello World 5 | 6 | 7 | <${input.renderBody}/> 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/node_modules/transient-dep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "transient-dep", 3 | "exports": { 4 | ".": { 5 | "import": "./index.mjs", 6 | "default": "./index.js" 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
8 |
9 | Hello 10 |
11 |
12 |
13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { color: green } 3 | } 4 | 5 | 6 |

test marko dep

7 | 8 | 9 | 10 |
-------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
8 |
9 | Hello 10 |
11 |
12 |
13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /.nycrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "all": true, 3 | "reporter": ["text", "lcov"], 4 | "extensions": [".js", ".ts", ".marko"], 5 | "include": ["src/**/*.{js,ts,marko}"], 6 | "exclude": ["**/__tests__"], 7 | "parserPlugins": ["objectRestSpread", "typescript"] 8 | } 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/src/tags/stateless.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded stateless tag"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | 10 | ``` 11 | 12 | # Step 0 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/src/tags/stateful.marko: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mounted: ${mounted} 6 | Clicks: ${clickCount} 7 | 8 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-basic/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/test.config.ts: -------------------------------------------------------------------------------- 1 | import type { Options } from "../../.."; 2 | 3 | export const ssr = true; 4 | export const options: Options = { 5 | isEntry(importee) { 6 | return importee.endsWith("src/template.marko"); 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-base-url/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-ssr-asset/src/template.marko: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello World 5 | 6 | 7 | 8 | image 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/src/template.marko: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello World 5 | 6 | 7 |
8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-runtime-base-path/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | 10 | ``` 11 | 12 | # Step 0 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/src/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/node_modules/test-package/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/node_modules/test-package/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/src/template.marko: -------------------------------------------------------------------------------- 1 | import { thing } from 'dep'; 2 | 3 | 4 | 5 | 6 | Hello World 7 | 8 | 9 | 10 |

${thing()}

11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/test.config.ts: -------------------------------------------------------------------------------- 1 | import type { Options } from "../../.."; 2 | 3 | export const ssr = true; 4 | export async function steps() { 5 | await page.click("#clickable"); 6 | } 7 | export const options: Options = { 8 | basePathVar: "assetsPath", 9 | }; 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/node_modules/test-package/components/implicit-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Implicit Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package2/esm2cjs.js: -------------------------------------------------------------------------------- 1 | Object.defineProperty(exports, "__esModule", { 2 | value: true 3 | }); 4 | exports.default = exports.TWO = exports.ONE = void 0; 5 | const ONE = exports.ONE = 1; 6 | const TWO = exports.TWO = 2; 7 | var _default = exports.default = 'd'; -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/src/template.marko: -------------------------------------------------------------------------------- 1 | style { 2 | div { 3 | color: green; 4 | } 5 | } 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-base-url/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-glob-import/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/node_modules/test-package/components/test-button/component-browser.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | 4 | var _default = { 5 | handleClick() { 6 | this.emit('click'); 7 | } 8 | }; 9 | 10 | exports.default = _default; 11 | module.exports = exports.default; -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-runtime-base-path/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}, res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render({}).pipe(res); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/src/template.marko: -------------------------------------------------------------------------------- 1 | export const x = 1; 2 | 3 | import { x as y } from './template.marko'; 4 | 5 | $ console.log(y); 6 | 7 | style { 8 | div { color: green } 9 | } 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/src/template.marko: -------------------------------------------------------------------------------- 1 | // import addMonths from 'date-fns/addMonths'; 2 | 3 | import sub from "test-package/sub"; 4 | style { 5 | div { 6 | color: green; 7 | } 8 | } 9 | 10 | 11 |
12 | ${sub} 13 |
14 |
15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-glob-import/src/template.marko: -------------------------------------------------------------------------------- 1 | static const modules = import.meta.glob('./modules/*.marko', { eager: true }) 2 | 3 | style { 4 | div { color: green } 5 | } 6 | 7 | 8 | 9 | 10 | <${mod}/> 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-glob-import/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 | Mounted: true Clicks: 0 8 |
9 | ``` 10 | 11 | # Step 0 12 | await page.click("#clickable") 13 | 14 | ```diff 15 | - Mounted: true Clicks: 0 16 | + Mounted: true Clicks: 1 17 | 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-glob-import/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 | Mounted: true Clicks: 0 8 |
9 | ``` 10 | 11 | # Step 0 12 | await page.click("#clickable") 13 | 14 | ```diff 15 | - Mounted: true Clicks: 0 16 | + Mounted: true Clicks: 1 17 | 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-ssr-asset/src/index.js: -------------------------------------------------------------------------------- 1 | import imageUrl from "./image.svg"; 2 | import template from "./template.marko"; 3 | 4 | export function handler(req, res) { 5 | if (req.url === "/") { 6 | res.statusCode = 200; 7 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 8 | template.render({ imageUrl }, res); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/src/tags/layout.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded layout tag"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.content}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/src/index.js: -------------------------------------------------------------------------------- 1 | import "./components/read-head.marko"; 2 | 3 | import template from "./template.marko"; 4 | 5 | export function handler(req, res) { 6 | if (req.url === "/") { 7 | res.statusCode = 200; 8 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 9 | template.render({}, res); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-base-url/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-runtime-base-path/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/src/components/layout-component.marko: -------------------------------------------------------------------------------- 1 | static { 2 | if (typeof window === "object") { 3 | document.body.firstElementChild.append("Loaded Layout Component"); 4 | } 5 | } 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 | <${input.renderBody}/> 14 | 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 20 | + Mounted: true Clicks: 1 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 20 | + Mounted: true Clicks: 1 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 20 | + Mounted: true Clicks: 1 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | text: '' 5 | }; 6 | } 7 | onMount() { 8 | fetch('/other').then((response) => response.text()).then((text) => { 9 | this.state.text = text; 10 | }).catch(() => this.state.text = 'broken'); 11 | } 12 | 13 | } 14 | 15 |
$!{state.text}
16 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 20 | + Mounted: true Clicks: 1 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json", 3 | "changelog": [ 4 | "@changesets/changelog-github", 5 | { 6 | "repo": "marko-js/vite" 7 | } 8 | ], 9 | "updateInternalDependencies": "patch", 10 | "baseBranch": "main", 11 | "access": "public", 12 | "commit": false, 13 | "linked": [], 14 | "ignore": [], 15 | "fixed": [] 16 | } 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 20 | + Mounted: true Clicks: 1 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 20 | + Mounted: true Clicks: 1 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Editor 2 | *.sublime* 3 | .vscode 4 | 5 | # OSX 6 | *.DS_Store 7 | 8 | # NPM 9 | **/node_modules/* 10 | !**/__tests__/**/node_modules/test-package 11 | !**/__tests__/**/node_modules/test-package2 12 | !**/__tests__/**/node_modules/dep 13 | !**/__tests__/**/node_modules/transient-dep 14 | npm-debug.log 15 | 16 | # Build 17 | dist 18 | *actual* 19 | *.tsbuildinfo 20 | 21 | # Coverage 22 | .nyc_output 23 | coverage 24 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/src/components/read-head.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | modulePreloads: [], 5 | }; 6 | } 7 | onMount() { 8 | this.state.modulePreloads = document.querySelectorAll( 9 | 'link[rel="modulepreload"]', 10 | ); 11 | } 12 | } 13 | 14 | 15 |
PRELOAD: ${new URL(link.href).pathname}
16 | 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-basic/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 |
12 |
13 | Loaded stateless tagLoaded layout tag 14 | ``` 15 | 16 | # Step 0 17 | await page.click("#clickable") 18 | 19 | ```diff 20 | - Mounted: true Clicks: 0 21 | + Mounted: true Clicks: 1 22 | 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 |
12 |
13 | Loaded stateless tagLoaded layout tag 14 | ``` 15 | 16 | # Step 0 17 | await page.click("#clickable") 18 | 19 | ```diff 20 | - Mounted: true Clicks: 0 21 | + Mounted: true Clicks: 1 22 | 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | 21 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-glob-import/src/modules/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | 21 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | 21 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/node_modules/test-package/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | 21 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | 21 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/node_modules/test-package/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | 21 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/node_modules/test-package/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 | 18 | Mounted: ${state.mounted} 19 | Clicks: ${state.clickCount} 20 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-basic/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | Loaded Implicit Component 5 |
8 |
11 |
14 | Mounted: true Clicks: 0 15 |
16 |
17 |
18 | ``` 19 | 20 | # Step 0 21 | await page.click("#clickable") 22 | 23 | ```diff 24 | - Mounted: true Clicks: 0 25 | + Mounted: true Clicks: 1 26 | 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-basic/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | Loaded Implicit Component 5 |
8 |
11 |
14 | Mounted: true Clicks: 0 15 |
16 |
17 |
18 | ``` 19 | 20 | # Step 0 21 | await page.click("#clickable") 22 | 23 | ```diff 24 | - Mounted: true Clicks: 0 25 | + Mounted: true Clicks: 1 26 | 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/node_modules/test-package/components/test-icon/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-base-url/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false, 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 |
18 | Mounted: ${state.mounted} Clicks: ${state.clickCount} 19 | logo 20 |
21 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-base-url/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 | logo 15 |
16 |
17 | ``` 18 | 19 | # Step 0 20 | await page.click("#clickable") 21 | 22 | ```diff 23 | - Mounted: true Clicks: 0 24 | + Mounted: true Clicks: 1 25 | 26 | ``` 27 | 28 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-base-url/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 11 | logo 15 |
16 |
17 | ``` 18 | 19 | # Step 0 20 | await page.click("#clickable") 21 | 22 | ```diff 23 | - Mounted: true Clicks: 0 24 | + Mounted: true Clicks: 1 25 | 26 | ``` 27 | 28 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/src/index.js: -------------------------------------------------------------------------------- 1 | import template from "./template.marko"; 2 | 3 | export function handler(req, res) { 4 | if (req.url === "/") { 5 | res.statusCode = 200; 6 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 7 | template.render( 8 | {}, 9 | { 10 | write(chunk) { 11 | res.write(chunk); 12 | }, 13 | end(chunk) { 14 | res.end(chunk); 15 | }, 16 | }, 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/src/index.js: -------------------------------------------------------------------------------- 1 | import other from "./other.marko"; 2 | import template from "./template.marko"; 3 | 4 | export function handler(req, res) { 5 | if (req.url === "/") { 6 | res.statusCode = 200; 7 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 8 | template.render({}, res); 9 | } else if (req.url === "/other") { 10 | res.statusCode = 200; 11 | res.setHeader("Content-Type", "text/html; charset=utf-8"); 12 | other.render({}, res); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 | Mounted: true Clicks: 0 8 |
9 |
12 | Mounted: true Clicks: 0 13 |
14 | ``` 15 | 16 | # Step 0 17 | for(const el of await page.$$(".clickable")){await el.click() 18 | 19 | ```diff 20 | - Mounted: true Clicks: 0 21 | + Mounted: true Clicks: 1 22 | - Mounted: true Clicks: 0 23 | + Mounted: true Clicks: 1 24 | 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 LOGO_PATH: /src/components/logo.svg ENV: / 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 LOGO_PATH: /src/components/logo.svg ENV: / 20 | + Mounted: true Clicks: 1 LOGO_PATH: /src/components/logo.svg ENV: / 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | Loaded Implicit Component 5 |

6 | test marko dep 7 |

8 |
11 |
14 |
17 | Mounted: true Clicks: 0 18 |
19 |
20 |
21 | ``` 22 | 23 | # Step 0 24 | await page.click("#clickable") 25 | 26 | ```diff 27 | - Mounted: true Clicks: 0 28 | + Mounted: true Clicks: 1 29 | 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-dep/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | Loaded Implicit Component 5 |

6 | test marko dep 7 |

8 |
11 |
14 |
17 | Mounted: true Clicks: 0 18 |
19 |
20 |
21 | ``` 22 | 23 | # Step 0 24 | await page.click("#clickable") 25 | 26 | ```diff 27 | - Mounted: true Clicks: 0 28 | + Mounted: true Clicks: 1 29 | 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | Loaded Implicit Component 5 |

6 | test marko dep 7 |

8 |
11 |
14 |
17 | Mounted: true Clicks: 0 18 |
19 |
20 |
21 | ``` 22 | 23 | # Step 0 24 | await page.click("#clickable") 25 | 26 | ```diff 27 | - Mounted: true Clicks: 0 28 | + Mounted: true Clicks: 1 29 | 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/browser-marko-shorthand-import/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 | Loaded Implicit Component 5 |

6 | test marko dep 7 |

8 |
11 |
14 |
17 | Mounted: true Clicks: 0 18 |
19 |
20 |
21 | ``` 22 | 23 | # Step 0 24 | await page.click("#clickable") 25 | 26 | ```diff 27 | - Mounted: true Clicks: 0 28 | + Mounted: true Clicks: 1 29 | 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | import logo from "./logo.svg"; 2 | class { 3 | onCreate() { 4 | this.state = { 5 | clickCount: 0, 6 | mounted: false, 7 | }; 8 | } 9 | onMount() { 10 | this.state.mounted = true; 11 | } 12 | 13 | handleClick() { 14 | this.state.clickCount++; 15 | } 16 | } 17 | 18 |
19 | Mounted: ${state.mounted} Clicks: ${state.clickCount} LOGO_PATH: ${logo} ENV: ${import.meta.env.BASE_URL} 20 |
21 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-runtime-base-path/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | import logo from "./logo.svg"; 2 | 3 | class { 4 | onCreate() { 5 | this.state = { 6 | clickCount: 0, 7 | mounted: false 8 | }; 9 | } 10 | onMount() { 11 | this.state.mounted = true; 12 | } 13 | 14 | handleClick() { 15 | this.state.clickCount++; 16 | } 17 | } 18 | 19 | 20 | Mounted: ${state.mounted} 21 | Clicks: ${state.clickCount} 22 | 23 | LOGO_PATH: ${logo} 24 | ENV: ${import.meta.env.BASE_URL} 25 | 26 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 | 12 |
13 |
14 |     cjs-exports=[[object Object], 1, 2]
15 |   cjs-module-exports=[[object Object], 1, 2]
16 |   esm2cjs=[d, 1, 2]
17 |   esm=[d, 1, 2]
18 | 
19 | 
20 | ``` 21 | 22 | # Step 0 23 | await page.click("#clickable") 24 | 25 | ```diff 26 | - foo Mounted: true Clicks: 0 27 | + foo Mounted: true Clicks: 1 28 | 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 | 12 |
13 |
14 |     cjs-exports=[[object Object], 1, 2]
15 |   cjs-module-exports=[[object Object], 1, 2]
16 |   esm2cjs=[d, 1, 2]
17 |   esm=[d, 1, 2]
18 | 
19 | 
20 | ``` 21 | 22 | # Step 0 23 | await page.click("#clickable") 24 | 25 | ```diff 26 | - foo Mounted: true Clicks: 0 27 | + foo Mounted: true Clicks: 1 28 | 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-basic/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-jk/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-glob-import/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-marko-dep/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-modulepreload/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 LOGO_PATH: /my-prefix/logo-[hash].svg ENV: / 11 |
12 |
13 |
14 | PRELOAD: /my-prefix/read-[hash].js 15 |
16 | ``` 17 | 18 | # Step 0 19 | await page.click("#clickable") 20 | 21 | ```diff 22 | - Mounted: true Clicks: 0 LOGO_PATH: /my-prefix/logo-[hash].svg ENV: / 23 | + Mounted: true Clicks: 1 LOGO_PATH: /my-prefix/logo-[hash].svg ENV: / 24 | 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-ssr-asset/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-bundle-splitting/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-svg/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-custom-entries/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-tags-api-basic/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-circular-entry-file/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-commonjs-dir-import/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-css-loader-import/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from 'path' 4 | import serve from "serve-handler"; 5 | import url from 'url'; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | await serve(req, res, serveOpts); 16 | }); 17 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-runtime-base-path/__snapshots__/dev.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 LOGO_PATH: /src/components/logo.svg ENV: / 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | (0,import_assert.default)(await hasScript(/\$mbp[a-z0-1-_\s]*=/i),"Base path script not found in head");await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 LOGO_PATH: /src/components/logo.svg ENV: / 20 | + Mounted: true Clicks: 1 LOGO_PATH: /src/components/logo.svg ENV: / 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-runtime-base-path/__snapshots__/build.expected.md: -------------------------------------------------------------------------------- 1 | # Loading 2 | 3 | ```html 4 |
7 |
10 | Mounted: true Clicks: 0 LOGO_PATH: /my-prefix/logo-[hash].svg ENV: / 11 |
12 |
13 | ``` 14 | 15 | # Step 0 16 | (0,import_assert.default)(await hasScript(/\$mbp[a-z0-1-_\s]*=/i),"Base path script not found in head");await page.click("#clickable") 17 | 18 | ```diff 19 | - Mounted: true Clicks: 0 LOGO_PATH: /my-prefix/logo-[hash].svg ENV: / 20 | + Mounted: true Clicks: 1 LOGO_PATH: /my-prefix/logo-[hash].svg ENV: / 21 | 22 | ``` 23 | 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680Feature request" 3 | about: Suggest an idea for a package in this repo 4 | --- 5 | 6 | ### Description 7 | 8 | 9 | 10 | ### Why 11 | 12 | 13 | 14 | 15 | 16 | ### Possible Implementation & Open Questions 17 | 18 | 19 | 20 | 21 | 22 | ### Is this something you're interested in working on? 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/server.mjs: -------------------------------------------------------------------------------- 1 | // In production, simply start up the http server. 2 | import { createServer } from "http"; 3 | import path from "path"; 4 | import serve from "serve-handler"; 5 | import url from "url"; 6 | 7 | import { handler } from "./dist/index.mjs"; 8 | 9 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 10 | const serveOpts = { public: path.resolve(__dirname, "dist") }; 11 | 12 | export default createServer(async (req, res) => { 13 | await handler(req, res); 14 | if (res.headersSent) return; 15 | if (/(script\.js|styles\.css)$/.test(req.url)) { 16 | res.statusCode = 200; 17 | res.end(); 18 | return; 19 | } 20 | await serve(req, res, serveOpts); 21 | }); 22 | -------------------------------------------------------------------------------- /src/__tests__/fixtures/isomorphic-relative-asset-import/src/components/class-component.marko: -------------------------------------------------------------------------------- 1 | class { 2 | onCreate() { 3 | this.state = { 4 | clickCount: 0, 5 | mounted: false, 6 | }; 7 | } 8 | onMount() { 9 | this.state.mounted = true; 10 | } 11 | 12 | handleClick() { 13 | this.state.clickCount++; 14 | } 15 | } 16 | 17 |
18 | Mounted: ${state.mounted} Clicks: ${state.clickCount} 19 | 20 | logo 21 | logo 22 | `; 72 | } 73 | 74 | function serializeOrNull(basePath: string, nodes: Node[], preload: string[]) { 75 | const result = serialize(basePath, nodes, preload); 76 | if (result.length) { 77 | return result; 78 | } 79 | 80 | return null; 81 | } 82 | 83 | function splitNodesByMarker(nodes: Node[], before: Node[], after: Node[]) { 84 | for (let i = 0; i < nodes.length; i++) { 85 | let node = nodes[i]; 86 | 87 | if ((node as Comment).data === MARKER_COMMENT) { 88 | i++; 89 | for (; i < nodes.length; i++) { 90 | node = nodes[i]; 91 | after.push(node); 92 | } 93 | 94 | break; 95 | } 96 | 97 | before.push(node); 98 | } 99 | } 100 | 101 | function isElement(node: Node): node is Element { 102 | return node.type === ElementType.Tag; 103 | } 104 | -------------------------------------------------------------------------------- /src/esbuild-plugin.ts: -------------------------------------------------------------------------------- 1 | import * as compiler from "@marko/compiler"; 2 | import type { Loader } from "esbuild"; 3 | import fs from "fs"; 4 | import path from "path"; 5 | import type * as vite from "vite"; 6 | 7 | type ESBuildOptions = Exclude< 8 | vite.DepOptimizationConfig["esbuildOptions"], 9 | undefined 10 | >; 11 | type ESBuildPlugin = Exclude[number]; 12 | 13 | const importTagReg = /<([^>]+)>/; 14 | const markoErrorReg = /^(.+?)(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm; 15 | const virtualFileReg = /\?marko-virtual&/; 16 | 17 | export default function esbuildPlugin( 18 | config: compiler.Config, 19 | virtualFiles: Map>, 20 | cacheVirtualFile: (path: string) => void, 21 | ): ESBuildPlugin { 22 | return { 23 | name: "marko", 24 | async setup(build) { 25 | const { platform = "browser" } = build.initialOptions; 26 | const isScan = build.initialOptions.plugins?.some( 27 | (v) => v.name === "vite:dep-scan", 28 | ); 29 | const finalConfig: compiler.Config = { 30 | ...config, 31 | output: platform === "browser" ? "dom" : "html", 32 | }; 33 | 34 | const scanConfig: compiler.Config = { 35 | ...finalConfig, 36 | output: "hydrate", 37 | }; 38 | 39 | build.onResolve({ filter: virtualFileReg }, (args) => { 40 | const resolvedPath = path.resolve(args.resolveDir, args.path); 41 | const isExternal = !/\.(?:[cm]?[jt]s|json)$/i.test(resolvedPath); 42 | if (isExternal && !isScan) { 43 | void cacheVirtualFile(resolvedPath); 44 | } 45 | 46 | return { 47 | path: resolvedPath, 48 | external: isExternal, 49 | }; 50 | }); 51 | 52 | build.onLoad({ filter: virtualFileReg }, async (args) => { 53 | const file = virtualFiles.get(args.path); 54 | if (file) { 55 | return { 56 | contents: (await file).code, 57 | loader: path.extname(args.path).slice(1) as Loader, 58 | resolveDir: path.dirname(args.path), 59 | }; 60 | } 61 | }); 62 | 63 | build.onResolve({ filter: importTagReg }, (args) => { 64 | const tagName = importTagReg.exec(args.path)?.[1]; 65 | if (tagName) { 66 | const tagDef = compiler.taglib 67 | .buildLookup(args.resolveDir) 68 | .getTag(tagName); 69 | const tagFile = tagDef && (tagDef.template || tagDef.renderer); 70 | if (tagFile) { 71 | return { path: tagFile }; 72 | } 73 | } 74 | }); 75 | 76 | build.onLoad({ filter: /\.marko$/ }, async (args) => { 77 | try { 78 | const { code, meta } = await compiler.compileFile( 79 | args.path, 80 | isScan && args.namespace === "" ? scanConfig : finalConfig, 81 | ); 82 | 83 | return { 84 | loader: "js", 85 | contents: code, 86 | watchFiles: meta.watchFiles, 87 | resolveDir: path.dirname(args.path), 88 | }; 89 | } catch (e) { 90 | const text = (e as Error).message; 91 | const errors: any[] = []; 92 | let match: RegExpExecArray | null; 93 | let lines: string[] | undefined; 94 | 95 | while ((match = markoErrorReg.exec(text))) { 96 | const [, file, rawLine, rawCol, text] = match; 97 | const line = parseInt(rawLine, 10) || 1; 98 | const column = parseInt(rawCol, 10) || 1; 99 | lines ||= (await fs.promises.readFile(args.path, "utf-8")).split( 100 | /\n/g, 101 | ); 102 | errors.push({ 103 | text, 104 | location: { 105 | file, 106 | line, 107 | column, 108 | lineText: ` ${lines[line - 1]}`, 109 | }, 110 | }); 111 | } 112 | 113 | if (!errors.length) { 114 | errors.push({ text }); 115 | } 116 | 117 | return { 118 | errors, 119 | }; 120 | } 121 | }); 122 | }, 123 | }; 124 | } 125 | -------------------------------------------------------------------------------- /src/render-assets-runtime.ts: -------------------------------------------------------------------------------- 1 | export const renderAssetsRuntimeId = "\0marko-render-assets.mjs"; 2 | export function getRenderAssetsRuntime(opts: { 3 | isBuild: boolean; 4 | runtimeId?: string; 5 | basePathVar?: string; 6 | }): string { 7 | return `${ 8 | opts.basePathVar && opts.isBuild 9 | ? `const base = globalThis.${opts.basePathVar}; 10 | if (typeof base !== "string") throw new Error("${opts.basePathVar} must be defined when using basePathVar."); 11 | if (!base.endsWith("/")) throw new Error("${opts.basePathVar} must end with a '/' when using basePathVar.");` 12 | : "const base = import.meta.env.BASE_URL;" 13 | } 14 | 15 | export function getPrepend(g) { 16 | return ( 17 | g.___viteRenderAssets("head-prepend") + 18 | g.___viteRenderAssets("head") + 19 | g.___viteRenderAssets("body-prepend") 20 | ); 21 | } 22 | export function getAppend(g) { 23 | return ( 24 | g.___viteRenderAssets("body-prepend") 25 | ); 26 | } 27 | export function addAssets(g, newEntries) { 28 | const entries = g.___viteEntries; 29 | if (entries) { 30 | g.___viteEntries = entries.concat(newEntries); 31 | return true; 32 | } 33 | g.___viteEntries = newEntries; 34 | g.___viteRenderAssets = renderAssets; 35 | g.___viteInjectAttrs = g.cspNonce 36 | ? \` nonce="\${g.cspNonce.replace(/"/g, "'")}"\` 37 | : ""; 38 | g.___viteSeenIds = new Set(); 39 | ${opts.runtimeId ? `g.runtimeId = ${JSON.stringify(opts.runtimeId)};` : ""} 40 | } 41 | 42 | function renderAssets(slot) { 43 | const entries = this.___viteEntries; 44 | let html = ""; 45 | 46 | if (entries) { 47 | const seenIds = this.___viteSeenIds; 48 | const slotWrittenEntriesKey = \`___viteWrittenEntries-\${slot}\`; 49 | const lastWrittenEntry = this[slotWrittenEntriesKey] || 0; 50 | const writtenEntries = (this[slotWrittenEntriesKey] = entries.length); 51 | ${ 52 | opts.basePathVar 53 | ? `if (!this.___flushedMBP && slot !== "head-prepend") { 54 | this.___flushedMBP = true; 55 | html += \`${ 56 | opts.runtimeId ? `$mbp_${opts.runtimeId}` : "$mbp" 57 | }=\${JSON.stringify(base)}\` 58 | }` 59 | : "" 60 | } 61 | for (let i = lastWrittenEntry; i < writtenEntries; i++) { 62 | let entry = entries[i]; 63 | 64 | if (typeof entry === "string") { 65 | entry = __MARKO_MANIFEST__[entry] || {}; 66 | }${ 67 | opts.isBuild 68 | ? "" 69 | : ` else if (slot === "head") { 70 | // In dev mode we have is a list entries of the top level modules that need to be imported. 71 | // To avoid FOUC we will hide the page until all of these modules are loaded. 72 | const { preload } = entry; 73 | if (preload) { 74 | let sep = ""; 75 | html += \`\`; 76 | html += \`\`; 87 | } 88 | }` 89 | } 90 | 91 | const parts = entry[slot]; 92 | 93 | if (parts) { 94 | for (let i = 0; i < parts.length; i++) { 95 | const part = parts[i]; 96 | switch (part) { 97 | case 0: /** InjectType.AssetAttrs */ 98 | html += this.___viteInjectAttrs; 99 | break; 100 | case 1: /** InjectType.PublicPath */ 101 | html += base; 102 | break; 103 | case 2: /** InjectType.Dedupe */ { 104 | const id = parts[++i]; 105 | const skipParts = parts[++i]; 106 | if (seenIds.has(id)) { 107 | i += skipParts; 108 | } else { 109 | seenIds.add(id); 110 | } 111 | break; 112 | } 113 | default: 114 | html += part; 115 | break; 116 | } 117 | } 118 | } 119 | } 120 | } 121 | 122 | return html; 123 | } 124 | `; 125 | } 126 | -------------------------------------------------------------------------------- /src/serializer.ts: -------------------------------------------------------------------------------- 1 | import { ElementType } from "domelementtype"; 2 | import type { Comment, Element, Node, Text } from "domhandler"; 3 | 4 | enum InjectType { 5 | AssetAttrs = 0, 6 | PublicPath = 1, 7 | Dedupe = 2, 8 | } 9 | 10 | const voidElements = new Set([ 11 | "area", 12 | "base", 13 | "br", 14 | "col", 15 | "embed", 16 | "hr", 17 | "img", 18 | "input", 19 | "link", 20 | "meta", 21 | "param", 22 | "source", 23 | "track", 24 | "wbr", 25 | ]); 26 | 27 | export default function serialize( 28 | basePath: string, 29 | nodes: Node[], 30 | preload: string[], 31 | parts?: (string | InjectType)[], 32 | ) { 33 | let curString = parts ? (parts.pop() as string) : ""; 34 | parts ??= []; 35 | 36 | for (const node of nodes) { 37 | switch (node.type) { 38 | case ElementType.Tag: 39 | case ElementType.Style: 40 | case ElementType.Script: { 41 | const tag = node as Element; 42 | const { name } = tag; 43 | let urlAttr: undefined | string; 44 | let isDedupe = 0; 45 | 46 | switch (tag.tagName) { 47 | case "script": 48 | if (tag.attribs.src) { 49 | if (curString) { 50 | parts.push(curString); 51 | curString = ""; 52 | } 53 | isDedupe = parts.push(InjectType.Dedupe, tag.attribs.src, 0) - 1; 54 | } 55 | parts.push(`${curString}<${name}`, InjectType.AssetAttrs); 56 | curString = ""; 57 | urlAttr = "src"; 58 | break; 59 | case "style": 60 | parts.push(`${curString}<${name}`, InjectType.AssetAttrs); 61 | curString = ""; 62 | break; 63 | case "link": 64 | if (tag.attribs.href) { 65 | if (curString) { 66 | parts.push(curString); 67 | curString = ""; 68 | } 69 | isDedupe = 70 | parts.push( 71 | InjectType.Dedupe, 72 | [tag.attribs.rel || "", tag.attribs.href, tag.attribs.as] 73 | .filter((it) => it != null) 74 | .join("#"), 75 | 0, 76 | ) - 1; 77 | } 78 | urlAttr = "href"; 79 | if ( 80 | tag.attribs.rel === "stylesheet" || 81 | tag.attribs.rel === "modulepreload" || 82 | tag.attribs.as === "style" || 83 | tag.attribs.as === "script" 84 | ) { 85 | parts.push(`${curString}<${name}`, InjectType.AssetAttrs); 86 | curString = ""; 87 | } else { 88 | curString += `<${name}`; 89 | } 90 | break; 91 | default: 92 | curString += `<${name}`; 93 | break; 94 | } 95 | 96 | for (const attr of tag.attributes) { 97 | if (attr.value === "") { 98 | curString += ` ${attr.name}`; 99 | } else if (attr.name === urlAttr) { 100 | const id = stripBasePath(basePath, attr.value).replace(/^\.\//, ""); 101 | 102 | if (tag.name === "script") { 103 | preload.push(id); 104 | } 105 | 106 | curString += ` ${attr.name}="`; 107 | parts.push( 108 | curString, 109 | InjectType.PublicPath, 110 | id.replace(/"/g, "'") + '"', 111 | ); 112 | curString = ""; 113 | } else { 114 | curString += ` ${attr.name}="${attr.value.replace(/"/g, "'")}"`; 115 | } 116 | } 117 | 118 | curString += ">"; 119 | 120 | if (tag.children.length) { 121 | parts.push(curString); 122 | serialize(basePath, tag.children, preload, parts); 123 | curString = parts.pop() as string; 124 | } 125 | 126 | if (!voidElements.has(name)) { 127 | curString += ``; 128 | } 129 | if (isDedupe) { 130 | if (curString) { 131 | parts.push(curString); 132 | curString = ""; 133 | } 134 | parts[isDedupe] = parts.length - isDedupe - 1; 135 | } 136 | 137 | break; 138 | } 139 | case ElementType.Text: { 140 | const text = (node as Text).data; 141 | 142 | if (!/^\s*$/.test(text)) { 143 | curString += text; 144 | } 145 | 146 | break; 147 | } 148 | case ElementType.Comment: 149 | curString += ``; 150 | break; 151 | } 152 | } 153 | 154 | if (curString) { 155 | parts.push(curString); 156 | } 157 | 158 | return parts; 159 | } 160 | 161 | function stripBasePath(basePath: string, path: string) { 162 | if (path.startsWith(basePath)) return path.slice(basePath.length); 163 | return path; 164 | } 165 | -------------------------------------------------------------------------------- /src/cjs-interop-translate.ts: -------------------------------------------------------------------------------- 1 | import { types as t } from "@marko/compiler"; 2 | import { importNamed } from "@marko/compiler/babel-utils"; 3 | 4 | import { isCJSModule } from "./resolve"; 5 | 6 | /** 7 | * This plugin is designed to transform imports within Marko files to interop between ESM and CJS. 8 | * In Node, ESM files cannot reliably use named imports and default imports from CJS files. 9 | * Additionally, modules which are transpiled from ESM to CJS will use a `__esModule` property to 10 | * signal that the consuming ESM code should treat `exports.default` as the default import. 11 | * This plugin only modifies imports it determined to be for CJS modules. 12 | * 13 | * Examples: 14 | * 1. Named imports: 15 | * Source: import { bar as baz } from 'foo'; 16 | * Becomes: import * as _foo from 'foo'; 17 | * const { bar: baz } = importNS(_foo); 18 | * 19 | * 2. Default imports: 20 | * Source: import myFoo from 'foo'; 21 | * Becomes: import * as _myFoo from 'foo'; 22 | * const { default: myFoo } = importDefault(_myFoo); 23 | * 24 | * 3. Namespace imports: 25 | * Source: import * as nsFoo from 'foo'; 26 | * Becomes: import * as _nsFoo from 'foo'; 27 | * const nsFoo = importNS(_nsFoo); 28 | * 29 | * 4. Default and named imports: 30 | * Source: import myFoo, { bar as baz } from 'foo'; 31 | * Becomes: import * as _foo from 'foo'; 32 | * const { default: myFoo } = importDefault(_foo); 33 | * const { bar: baz } = importNS(_foo); 34 | */ 35 | 36 | export const cjsInteropHelpersId = "\0marko-cjs-interop.js"; 37 | export const cjsInteropHelpersCode = `export const importNS = m => m && (m.default === void 0 || m.__esModule ? m : m.default); 38 | export const importDefault = m => m?.default?.__esModule ? m.default : m; 39 | `; 40 | 41 | export default { 42 | Program: { 43 | exit(program: t.NodePath) { 44 | const { cjsInteropMarkoVite } = program.hub.file.markoOpts as any; 45 | if (!cjsInteropMarkoVite) return; 46 | const { filter } = cjsInteropMarkoVite; 47 | const children = program.get("body"); 48 | 49 | for (let i = children.length; i--; ) { 50 | const child = children[i]; 51 | if (child.isImportDeclaration()) { 52 | translateImport(child, filter); 53 | } 54 | } 55 | }, 56 | }, 57 | }; 58 | 59 | function translateImport( 60 | importDecl: t.NodePath, 61 | filter: undefined | ((v: string) => boolean), 62 | ) { 63 | // Skip side-effect only, relative, and marko imports 64 | if ( 65 | !importDecl.node.specifiers.length || 66 | /\.(?:mjs|marko)$|\?/.test(importDecl.node.source.value) || 67 | filter?.(importDecl.node.source.value) === false || 68 | !isCJSModule( 69 | importDecl.node.source.value, 70 | (importDecl.hub as any).file.opts.filename, 71 | ) 72 | ) { 73 | return; 74 | } 75 | 76 | let namespaceId: t.Identifier | undefined; 77 | let defaultImportId: t.Identifier | undefined; 78 | let imports: { name: string; alias: string }[] | undefined; 79 | 80 | for (const s of importDecl.node.specifiers) { 81 | if (t.isImportSpecifier(s)) { 82 | (imports ||= []).push({ 83 | name: t.isStringLiteral(s.imported) 84 | ? s.imported.value 85 | : s.imported.name, 86 | alias: s.local.name, 87 | }); 88 | } else if (t.isImportDefaultSpecifier(s)) { 89 | defaultImportId = s.local; 90 | } else if (t.isImportNamespaceSpecifier(s)) { 91 | namespaceId = s.local; 92 | } 93 | } 94 | 95 | const rawImport = importDecl.scope.generateUidIdentifier( 96 | namespaceId?.name || defaultImportId?.name || importDecl.node.source.value, 97 | ); 98 | importDecl.node.specifiers = [t.importNamespaceSpecifier(rawImport)]; 99 | 100 | if (defaultImportId) { 101 | importDecl.insertAfter( 102 | t.variableDeclaration("const", [ 103 | t.variableDeclarator( 104 | t.objectPattern([ 105 | t.objectProperty(t.identifier("default"), defaultImportId), 106 | ]), 107 | t.callExpression( 108 | importNamed( 109 | importDecl.hub.file, 110 | cjsInteropHelpersId, 111 | "importDefault", 112 | ), 113 | [rawImport], 114 | ), 115 | ), 116 | ]), 117 | ); 118 | } 119 | 120 | if (namespaceId) { 121 | importDecl.insertAfter( 122 | t.variableDeclaration("const", [ 123 | t.variableDeclarator( 124 | namespaceId, 125 | t.callExpression( 126 | importNamed(importDecl.hub.file, cjsInteropHelpersId, "importNS"), 127 | [rawImport], 128 | ), 129 | ), 130 | ]), 131 | ); 132 | } 133 | 134 | if (imports) { 135 | importDecl.insertAfter( 136 | t.variableDeclaration("const", [ 137 | t.variableDeclarator( 138 | t.objectPattern( 139 | imports.map(({ name, alias }) => 140 | t.objectProperty( 141 | t.identifier(name), 142 | t.identifier(alias), 143 | false, 144 | name === alias, 145 | ), 146 | ), 147 | ), 148 | t.callExpression( 149 | importNamed(importDecl.hub.file, cjsInteropHelpersId, "importNS"), 150 | [rawImport], 151 | ), 152 | ), 153 | ]), 154 | ); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 |
5 | @marko/vite 6 |
7 | 8 | 9 | 10 | TypeScript 11 | 12 | 13 | 14 | Styled with prettier 15 | 16 | 17 | 18 | Build status 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | NPM Version 27 | 28 | 29 | 30 | Downloads 31 | 32 |

33 | 34 | A Marko plugin for [Vite](https://vitejs.dev/). 35 | 36 | # Installation 37 | 38 | ```console 39 | npm install @marko/vite 40 | ``` 41 | 42 | # Example config 43 | 44 | ```javascript 45 | import { defineConfig } from "vite"; 46 | import marko from "@marko/vite"; 47 | export default defineConfig({ 48 | plugins: [marko()], 49 | }); 50 | ``` 51 | 52 | # Base paths 53 | 54 | When deploying an application under a nested public path, use Vite's [`base` option](https://vitejs.dev/config/shared-options.html#base) to specify a path to prefix all assets. This option can also be specified with the `BASE_URL` environment variable. 55 | 56 | If the base path is not static, see the [basePathVar](#optionsbasepathvar) option for handling more advanced cases. 57 | 58 | # Browser asset references 59 | 60 | 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. 61 | 62 | 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. 63 | 64 | ``` 65 | 66 | 67 | // Would produce a Vite processed asset and update the src, eg with the following output 68 | 69 | ``` 70 | 71 | Most common image, media, and font filetypes are transformed automatically but some file types such as `.js` and `.css` files will not be. Generally these should be imported directly and not rendered as markup. To force the transformation of a path, add `?url` to it. You can see the list of elements and their attributes which are processed [here](./src/relative-assets-transform.ts). 72 | 73 | # Linked Mode 74 | 75 | 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. 76 | 77 | With this you _do not_ create `.html` files for `Vite`, it's Marko all the way down! 78 | Scripts, styles and other content that _would have_ been injected into the `.html` files is instead automatically injected into your `.marko` templates. 79 | 80 | In this mode you must use the [Vite SSR API](https://vitejs.dev/guide/ssr.html#setting-up-the-dev-server). 81 | 82 | Here's an example using `express`. 83 | 84 | ```js 85 | import { createServer } from "vite"; 86 | 87 | const app = express(); 88 | let loadTemplate; 89 | 90 | if (process.env.NODE_ENV === "production") { 91 | // Use Vite's built asset in prod mode. 92 | loadTemplate = () => import("./dist"); 93 | } else { 94 | // Hookup the vite dev server. 95 | const vite = await createViteServer({ 96 | server: { middlewareMode: true } 97 | }); 98 | 99 | app.use(vite.middlewares); 100 | loadTemplate = () => vite.ssrLoadModule("./template.marko"); 101 | } 102 | 103 | app.get("/", async (req, res) => { 104 | const template = (await loadTemplate()).default; 105 | // When the template is loaded, it will automaticall have `vite` assets inlined. 106 | template.render({ hello: "world" }, res); 107 | ); 108 | 109 | app.listen(3000); 110 | ``` 111 | 112 | > For a more real world setup check out our [vite express](https://github.com/marko-js/examples/tree/master/examples/vite-express) example app. 113 | 114 | # Options 115 | 116 | ### options.babelConfig 117 | 118 | You can manually override Marko's Babel configuration by passing a `babelConfig` object to the `@marko/vite` plugin. If no babel configuration is specified, babel related config files will not be considered. 119 | 120 | ```javascript 121 | marko({ 122 | babelConfig: { 123 | presets: ["@babel/preset-env"], 124 | }, 125 | }); 126 | ``` 127 | 128 | ### options.runtimeId 129 | 130 | In some cases you may want to embed multiple isolated copies of Marko on the page. Since Marko relies on some `window` properties to initialize this can cause issues. For example, by default Marko will read the server rendered hydration code from `window.$components`. In Marko you can change these `window` properties by rendering with `{ $global: { runtimeId: "MY_MARKO_RUNTIME_ID" } }` as input on the server side. 131 | 132 | This plugin exposes a `runtimeId` option produces output that automatically sets `$global.runtimeId` on the server side and initializes properly in the browser. 133 | 134 | ```js 135 | marko({ runtimeId: "MY_MARKO_RUNTIME_ID" }); 136 | ``` 137 | 138 | ### options.linked 139 | 140 | Set this to `false` to opt out of [linked mode](#linked-mode). When this is false, the plugin will only handle resolving and transforming `.marko` files. 141 | 142 | ### options.basePathVar 143 | 144 | 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. 145 | 146 | First configure `@marko/vite`. 147 | 148 | ```js 149 | marko({ basePathVar: "__MY_ASSET_BASE_PATH__" }); 150 | ``` 151 | 152 | Then ensure you set that variable at runtime. 153 | 154 | ```js 155 | globalThis.__MY_ASSET_BASE_PATH__ = getAssetUrl(); // Note this must end with a `/`. 156 | require("./dist/index.mjs"); // load the built vite app. 157 | ``` 158 | 159 | ## Code of Conduct 160 | 161 | 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. 162 | -------------------------------------------------------------------------------- /src/__tests__/main.test.ts: -------------------------------------------------------------------------------- 1 | import { defaultNormalizer, defaultSerializer } from "@marko/fixture-snapshots"; 2 | import { diffLines } from "diff"; 3 | import { once } from "events"; 4 | import fs from "fs"; 5 | import type http from "http"; 6 | import { JSDOM } from "jsdom"; 7 | import snap from "mocha-snap"; 8 | import { createRequire } from "module"; 9 | import net from "net"; 10 | import path from "path"; 11 | import * as playwright from "playwright"; 12 | import url from "url"; 13 | 14 | import markoPlugin, { type Options } from ".."; 15 | 16 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); 17 | 18 | declare global { 19 | const page: playwright.Page; 20 | namespace NodeJS { 21 | interface Global { 22 | page: playwright.Page; 23 | } 24 | } 25 | } 26 | 27 | declare namespace globalThis { 28 | let page: playwright.Page; 29 | } 30 | 31 | declare let __loading__: Promise | undefined; 32 | 33 | type Step = () => Promise | unknown; 34 | 35 | const requireCwd = createRequire(process.cwd()); 36 | let vite: typeof import("vite"); 37 | let browser: playwright.Browser; 38 | 39 | before(async () => { 40 | vite = await import("vite"); 41 | browser = await playwright.chromium.launch(); 42 | const context = await browser.newContext(); 43 | context.on("console", (msg) => console.log(`[${msg.type()}] ${msg.text()}`)); 44 | await context.addInitScript(() => { 45 | // needed for esbuild. 46 | (window as any).__name = (v: any) => v; 47 | __loading__ = undefined; 48 | 49 | const seen = new Set(); 50 | let remaining = 0; 51 | let resolve: undefined | (() => void); 52 | window.addEventListener("error", onError); 53 | window.addEventListener("unhandledrejection", onError); 54 | onMutate(document, (_, obs) => { 55 | if (!document.body) return; 56 | obs.disconnect(); 57 | trackAssets(); 58 | onMutate(document.body, trackAssets); 59 | }); 60 | 61 | function onMutate(target: Node, fn: MutationCallback) { 62 | new MutationObserver(fn).observe(target, { 63 | childList: true, 64 | subtree: true, 65 | }); 66 | } 67 | function trackAssets() { 68 | for (const el of document.querySelectorAll< 69 | HTMLScriptElement | HTMLLinkElement 70 | >("script[src],link[rel=stylesheet][href]")) { 71 | const href = "src" in el ? el.src : el.href; 72 | if (href && !seen.has(href)) { 73 | const link = document.createElement("link"); 74 | __loading__ ||= new Promise((r) => (resolve = r)); 75 | seen.add(href); 76 | remaining++; 77 | 78 | if ("src" in el) { 79 | if (el.getAttribute("type") === "module") { 80 | link.rel = "modulepreload"; 81 | } else { 82 | link.rel = "preload"; 83 | link.as = "script"; 84 | } 85 | } else { 86 | link.rel = "preload"; 87 | link.as = "style"; 88 | } 89 | 90 | link.href = href; 91 | link.onload = link.onerror = () => { 92 | link.onload = link.onerror = null; 93 | link.remove(); 94 | seen.delete(href); 95 | if (!--remaining) { 96 | resolve?.(); 97 | resolve = __loading__ = undefined; 98 | } 99 | }; 100 | document.head.append(link); 101 | } 102 | } 103 | } 104 | function onError(ev: ErrorEvent | PromiseRejectionEvent) { 105 | const msg = 106 | ev instanceof PromiseRejectionEvent 107 | ? `${ev.reason}\n` 108 | : `${ev.error || `Error loading ${(ev.target as any).outerHTML}`}\n`; 109 | if (!msg.includes("WebSocket closed")) { 110 | let errorContainer = document.getElementById("error"); 111 | if (!errorContainer) { 112 | errorContainer = document.createElement("pre"); 113 | errorContainer.id = "error"; 114 | (document.getElementById("app") || document.body).appendChild( 115 | errorContainer, 116 | ); 117 | } 118 | errorContainer.insertAdjacentText("beforeend", msg); 119 | } 120 | } 121 | }); 122 | 123 | globalThis.page = await context.newPage(); 124 | }); 125 | 126 | after(() => browser.close()); 127 | 128 | const FIXTURES = path.join(__dirname, "fixtures"); 129 | 130 | for (const fixture of fs.readdirSync(FIXTURES)) { 131 | describe(fixture, () => { 132 | const dir = path.join(FIXTURES, fixture); 133 | const config = requireCwd(path.join(dir, "test.config.ts")) as { 134 | ssr: boolean; 135 | steps?: Step | Step[]; 136 | options?: Options; 137 | env?: Record; 138 | }; 139 | 140 | if (config.env) { 141 | const preservedEnv: [string, string | undefined | false][] = []; 142 | before(() => { 143 | for (const [key, value] of Object.entries(config.env!)) { 144 | preservedEnv.push([ 145 | key, 146 | key in process.env ? process.env[key] : false, 147 | ]); 148 | process.env[key] = value; 149 | } 150 | }); 151 | 152 | after(() => { 153 | for (const [key, value] of preservedEnv) { 154 | if (value === false) { 155 | delete process.env[key]; 156 | } else { 157 | process.env[key] = value; 158 | } 159 | } 160 | }); 161 | } 162 | 163 | const steps: Step[] = config.steps 164 | ? Array.isArray(config.steps) 165 | ? config.steps 166 | : [config.steps] 167 | : []; 168 | 169 | if (config.ssr) { 170 | it("dev", async () => { 171 | const port = await getAvailablePort(); 172 | const server = ( 173 | await import(url.pathToFileURL(path.join(dir, "dev-server.mjs")).href) 174 | ).default.listen(port) as http.Server; 175 | try { 176 | await once(server, "listening"); 177 | await testPage(dir, steps, port); 178 | } finally { 179 | server.close(); 180 | } 181 | }); 182 | 183 | it("build", async () => { 184 | await vite.build({ 185 | root: dir, 186 | logLevel: "error", 187 | plugins: [markoPlugin(config.options)], 188 | build: { 189 | write: true, 190 | minify: false, 191 | assetsInlineLimit: 0, 192 | emptyOutDir: false, // Avoid server / client deleting files from each other. 193 | ssr: path.join(dir, "src/index.js"), 194 | }, 195 | }); 196 | 197 | await vite.build({ 198 | root: dir, 199 | logLevel: "error", 200 | plugins: [markoPlugin(config.options)], 201 | build: { 202 | write: true, 203 | minify: false, 204 | assetsInlineLimit: 0, 205 | emptyOutDir: false, // Avoid server / client deleting files from each other. 206 | }, 207 | }); 208 | 209 | const port = await getAvailablePort(); 210 | const server = ( 211 | await import(url.pathToFileURL(path.join(dir, "server.mjs")).href) 212 | ).default.listen(port) as http.Server; 213 | 214 | try { 215 | await once(server, "listening"); 216 | await testPage(dir, steps, port); 217 | } finally { 218 | server.close(); 219 | } 220 | }); 221 | } else { 222 | it("dev", async () => { 223 | const port = await getAvailablePort(); 224 | const devServer = await vite.createServer({ 225 | root: dir, 226 | server: { 227 | port, 228 | watch: { 229 | ignored: [ 230 | "**/node_modules/**", 231 | "**/dist/**", 232 | "**/__snapshots__/**", 233 | ], 234 | }, 235 | }, 236 | logLevel: "error", 237 | optimizeDeps: { force: true }, 238 | plugins: [markoPlugin({ ...config.options, linked: false })], 239 | }); 240 | 241 | try { 242 | await devServer.listen(); 243 | await testPage(dir, steps, port); 244 | } finally { 245 | await devServer.close(); 246 | } 247 | }); 248 | 249 | it("build", async () => { 250 | await vite.build({ 251 | root: dir, 252 | logLevel: "error", 253 | plugins: [markoPlugin({ ...config.options, linked: false })], 254 | build: { 255 | write: true, 256 | minify: false, 257 | }, 258 | }); 259 | 260 | const port = await getAvailablePort(); 261 | const previewServer = await vite.preview({ 262 | root: dir, 263 | server: { 264 | watch: { 265 | ignored: [ 266 | "**/node_modules/**", 267 | "**/dist/**", 268 | "**/__snapshots__/**", 269 | ], 270 | }, 271 | }, 272 | preview: { port }, 273 | }); 274 | 275 | try { 276 | await testPage(dir, steps, port); 277 | } finally { 278 | await previewServer.close(); 279 | } 280 | }); 281 | } 282 | }); 283 | } 284 | 285 | async function testPage(dir: string, steps: Step[], port: number) { 286 | await page.goto(`http://localhost:${port}`); 287 | 288 | const title = await page.title(); 289 | if (title === "Error") { 290 | const error = new Error("Error in response"); 291 | const html = await page.locator("pre").innerHTML(); 292 | if (html) { 293 | error.stack = JSDOM.fragment(html.replace(/
/g, "\n")).textContent!; 294 | } 295 | throw error; 296 | } 297 | 298 | let snapshot = ""; 299 | let prevHtml: string | undefined; 300 | 301 | await page.waitForSelector("#app"); 302 | snapshot += `# Loading\n\n`; 303 | const html = await getHTML(); 304 | snapshot += htmlSnapshot(html, prevHtml); 305 | prevHtml = html; 306 | 307 | for (const [i, step] of steps.entries()) { 308 | snapshot += `# Step ${i}\n${getStepString(step)}\n\n`; 309 | await step(); 310 | const html = await getHTML(); 311 | if (html === prevHtml) continue; 312 | snapshot += htmlSnapshot(html, prevHtml); 313 | prevHtml = html; 314 | } 315 | 316 | await snap(snapshot, { ext: ".md", dir }); 317 | } 318 | 319 | async function getHTML() { 320 | return defaultSerializer( 321 | defaultNormalizer( 322 | JSDOM.fragment( 323 | await page.evaluate(async () => { 324 | do { 325 | await __loading__; 326 | await new Promise((r) => { 327 | requestAnimationFrame(() => { 328 | const { port1, port2 } = new MessageChannel(); 329 | port1.onmessage = r; 330 | port2.postMessage(0); 331 | }); 332 | }); 333 | } while (__loading__); 334 | 335 | return document.getElementById("app")?.innerHTML || ""; 336 | }), 337 | ), 338 | ), 339 | ) 340 | .replace(/-[a-z0-9_-]+(\.\w+)/gi, "-[hash]$1") 341 | .replace(/[?&][tv]=[\d.]+/, ""); 342 | } 343 | 344 | async function getAvailablePort() { 345 | return new Promise((resolve) => { 346 | const server = net.createServer().listen(0, () => { 347 | const { port } = server.address() as net.AddressInfo; 348 | server.close(() => resolve(port)); 349 | }); 350 | }); 351 | } 352 | 353 | function getStepString(step: Step) { 354 | return step 355 | .toString() 356 | .replace(/^.*?{\s*([\s\S]*?)\s*}.*?$/, "$1") 357 | .replace(/^ {4}/gm, "") 358 | .replace(/;$/, ""); 359 | } 360 | 361 | function htmlSnapshot(html: string, prevHtml?: string) { 362 | if (prevHtml) { 363 | const diff = diffLines(prevHtml, html) 364 | .map((part) => 365 | part.added ? `+${part.value}` : part.removed ? `-${part.value}` : "", 366 | ) 367 | .filter(Boolean) 368 | .join(""); 369 | return `\`\`\`diff\n${diff}\n\`\`\`\n\n`; 370 | } 371 | return `\`\`\`html\n${html}\n\`\`\`\n\n`; 372 | } 373 | --------------------------------------------------------------------------------