├── packages ├── website │ ├── .gitignore │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── types │ │ │ └── index.ts │ │ ├── smartquotes.d.ts │ │ ├── components │ │ │ ├── smart-quotes.tsx │ │ │ ├── code.tsx │ │ │ └── providers.tsx │ │ ├── lib │ │ │ ├── shiki.ts │ │ │ └── load-docs.ts │ │ ├── utils │ │ │ └── index.ts │ │ ├── waku.server.tsx │ │ └── atoms │ │ │ └── index.ts │ ├── waku.config.ts │ └── tsconfig.json ├── waku │ ├── cli.js │ ├── tests │ │ ├── fixtures │ │ │ ├── plugin-fs-router-typegen-empty │ │ │ │ └── pages │ │ │ │ │ └── .gitkeep │ │ │ ├── plugin-fs-router-typegen-complex │ │ │ │ └── pages │ │ │ │ │ ├── blog │ │ │ │ │ ├── [slug].tsx │ │ │ │ │ └── _components │ │ │ │ │ │ └── widget.tsx │ │ │ │ │ ├── docs │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── admin │ │ │ │ │ └── dashboard.tsx │ │ │ │ │ └── (group) │ │ │ │ │ └── landing │ │ │ │ │ └── index.tsx │ │ │ ├── plugin-fs-router-typegen-with-createpages │ │ │ │ ├── pages │ │ │ │ │ └── index.tsx │ │ │ │ └── waku.server.tsx │ │ │ ├── plugin-fs-router-typegen-with-fsrouter │ │ │ │ ├── pages │ │ │ │ │ └── index.tsx │ │ │ │ └── waku.server.tsx │ │ │ ├── plugin-fs-router-typegen │ │ │ │ └── pages │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ ├── one-two-three.tsx │ │ │ │ │ ├── one__two_three.tsx │ │ │ │ │ ├── one_two_three.tsx │ │ │ │ │ ├── øné_two_three.tsx │ │ │ │ │ └── [category] │ │ │ │ │ ├── _layout.tsx │ │ │ │ │ └── [...tags] │ │ │ │ │ └── index.tsx │ │ │ ├── plugin-fs-router-typegen-with-fsrouter-alias │ │ │ │ └── waku.server.tsx │ │ │ └── plugin-fs-router-typegen-with-fsrouter-fake │ │ │ │ └── waku.server.tsx │ │ ├── tsconfig.json │ │ └── config.test.ts │ ├── src │ │ ├── client.ts │ │ ├── lib │ │ │ ├── vite-entries │ │ │ │ ├── entry.ssr.tsx │ │ │ │ ├── entry.server.tsx │ │ │ │ └── entry.browser.tsx │ │ │ ├── global-types.ts │ │ │ ├── utils │ │ │ │ ├── fs-router.ts │ │ │ │ └── create-pages.ts │ │ │ └── constants.ts │ │ ├── main.react-server.ts │ │ ├── internals.ts │ │ ├── router │ │ │ └── server.ts │ │ └── minimal │ │ │ └── server.ts │ ├── tsconfig.json │ └── .swcrc └── create-waku │ ├── cli.js │ ├── tsconfig.json │ └── tsup.config.ts ├── examples ├── 37_css-stylex │ ├── src │ │ └── index.css │ └── tsconfig.json ├── 01_template │ ├── src │ │ ├── styles.css │ │ └── components │ │ │ ├── header.tsx │ │ │ └── footer.tsx │ ├── public │ │ ├── robots.txt │ │ └── images │ │ │ └── favicon.png │ ├── .gitignore │ ├── waku.config.ts │ └── tsconfig.json ├── 06_form-demo │ ├── private │ │ └── message.txt │ ├── .gitignore │ ├── public │ │ └── images │ │ │ └── favicon.png │ ├── src │ │ ├── styles.css │ │ └── components │ │ │ └── footer.tsx │ ├── waku.config.ts │ └── tsconfig.json ├── 07_cloudflare │ ├── public │ │ ├── 404.html │ │ └── images │ │ │ └── favicon.png │ ├── src │ │ ├── styles.css │ │ ├── components │ │ │ ├── header.tsx │ │ │ └── footer.tsx │ │ └── waku.server.tsx │ ├── .gitignore │ └── tsconfig.json ├── 12_nossr │ ├── src │ │ ├── styles.css │ │ ├── components │ │ │ ├── header.tsx │ │ │ └── footer.tsx │ │ └── waku.server.ts │ ├── .gitignore │ ├── public │ │ └── images │ │ │ └── favicon.png │ ├── waku.config.ts │ └── tsconfig.json ├── 21_create-pages │ ├── private │ │ └── hi.txt │ ├── src │ │ ├── styles.css │ │ ├── components │ │ │ ├── NestedQuxPage.tsx │ │ │ ├── HomePage.tsx │ │ │ ├── BarPage.tsx │ │ │ ├── NestedBazPage.tsx │ │ │ ├── StaticSlice.tsx │ │ │ ├── DynamicSlice.tsx │ │ │ ├── FooPage.tsx │ │ │ ├── DeeplyNestedLayout.tsx │ │ │ ├── NestedLayout.tsx │ │ │ ├── Root.tsx │ │ │ ├── SlicePage.tsx │ │ │ └── funcs.ts │ │ └── waku.client.tsx │ └── tsconfig.json ├── 02_template_js │ ├── src │ │ ├── styles.css │ │ └── components │ │ │ ├── header.jsx │ │ │ └── footer.jsx │ ├── .gitignore │ ├── public │ │ └── images │ │ │ └── favicon.png │ └── waku.config.js ├── 08_jotai-demo │ ├── src │ │ ├── styles.css │ │ └── components │ │ │ ├── header.tsx │ │ │ └── footer.tsx │ ├── .gitignore │ ├── public │ │ └── images │ │ │ └── favicon.png │ └── tsconfig.json ├── 22_define-router │ ├── private │ │ └── hi.txt │ ├── src │ │ ├── styles.css │ │ ├── components │ │ │ ├── NestedBazPage.tsx │ │ │ ├── HomePage.tsx │ │ │ ├── BarPage.tsx │ │ │ ├── FooPage.tsx │ │ │ └── Root.tsx │ │ └── waku.client.tsx │ └── tsconfig.json ├── 42_react-tweet │ ├── src │ │ ├── styles.css │ │ ├── components │ │ │ ├── header.tsx │ │ │ └── footer.tsx │ │ ├── waku.client.tsx │ │ └── templates │ │ │ └── home-page.tsx │ ├── .gitignore │ ├── public │ │ └── images │ │ │ └── favicon.png │ ├── waku.config.ts │ └── tsconfig.json ├── 31_minimal │ ├── public │ │ └── 404.html │ ├── src │ │ ├── components │ │ │ └── Counter.tsx │ │ └── waku.client.tsx │ ├── tsconfig.json │ └── package.json ├── 32_minimal_js │ ├── public │ │ └── 404.html │ ├── package.json │ └── src │ │ ├── components │ │ └── counter.jsx │ │ └── waku.client.jsx ├── 37_css │ ├── src │ │ ├── components │ │ │ ├── app.css │ │ │ ├── app.module.css │ │ │ ├── layout.styles.css │ │ │ └── counter.tsx │ │ ├── type.d.ts │ │ └── waku.client.tsx │ ├── tsconfig.json │ └── package.json ├── 43_weave-render │ ├── src │ │ ├── styles.css │ │ ├── components │ │ │ ├── HomePage.tsx │ │ │ ├── BarPage.tsx │ │ │ ├── FooPage.tsx │ │ │ └── FooLayout.tsx │ │ └── waku.client.tsx │ └── tsconfig.json ├── 03_demo │ ├── .gitignore │ ├── public │ │ └── images │ │ │ └── favicon.png │ ├── src │ │ ├── lib │ │ │ └── pokemon.ts │ │ ├── styles.css │ │ └── components │ │ │ ├── reload.tsx │ │ │ └── footer.tsx │ ├── waku.config.ts │ └── tsconfig.json ├── 04_cssmodules │ ├── .gitignore │ ├── public │ │ └── images │ │ │ └── favicon.png │ ├── src │ │ ├── types.d.ts │ │ ├── pages │ │ │ ├── about.module.css │ │ │ ├── index.module.css │ │ │ └── _layout.module.css │ │ └── components │ │ │ ├── footer.module.css │ │ │ ├── header.tsx │ │ │ ├── header.module.css │ │ │ ├── footer.tsx │ │ │ └── counter.tsx │ ├── waku.config.ts │ └── tsconfig.json ├── 41_path-alias │ ├── src │ │ ├── components │ │ │ └── MyFragment.tsx │ │ └── waku.client.tsx │ ├── waku.config.ts │ └── tsconfig.json ├── 37_css-vanilla-extract │ ├── src │ │ ├── server.css.ts │ │ ├── client.css.ts │ │ ├── pages │ │ │ └── index.tsx │ │ └── components │ │ │ └── counter.tsx │ ├── waku.config.ts │ └── tsconfig.json ├── 54_jotai │ ├── waku.config.ts │ ├── src │ │ └── waku.client.tsx │ └── tsconfig.json ├── 11_fs-router │ ├── src │ │ ├── pages │ │ │ ├── api │ │ │ │ └── hello.ts │ │ │ ├── index.tsx │ │ │ ├── nested │ │ │ │ ├── _layout.tsx │ │ │ │ └── [name].tsx │ │ │ ├── bar.tsx │ │ │ ├── foo │ │ │ │ └── index.tsx │ │ │ ├── debug.tsx │ │ │ ├── _slices │ │ │ │ ├── one.tsx │ │ │ │ └── two.tsx │ │ │ ├── slice-page.tsx │ │ │ └── _components │ │ │ │ └── Counter.tsx │ │ ├── waku.server.tsx │ │ └── waku.client.tsx │ ├── tsconfig.json │ └── package.json ├── 33_promise │ ├── src │ │ ├── components │ │ │ └── Hello.tsx │ │ └── waku.client.tsx │ ├── tsconfig.json │ └── package.json ├── 34_functions │ ├── src │ │ ├── components2 │ │ │ ├── ButtonClient.tsx │ │ │ ├── funcs2.ts │ │ │ ├── funcs.ts │ │ │ └── ButtonServer.tsx │ │ ├── als.ts │ │ └── waku.client.tsx │ └── tsconfig.json ├── 38_cookies │ ├── src │ │ ├── middleware │ │ │ └── noop.ts │ │ ├── components │ │ │ └── Counter.tsx │ │ └── waku.client.tsx │ ├── private │ │ └── items.json │ └── tsconfig.json ├── 52_tanstack-router │ ├── src │ │ ├── server-fns.ts │ │ ├── waku.client.tsx │ │ └── waku.server.tsx │ └── tsconfig.json ├── 51_spa │ ├── src │ │ ├── waku.client.tsx │ │ ├── functions │ │ │ └── greet.tsx │ │ └── waku.server.tsx │ ├── tsconfig.json │ └── package.json ├── 36_form │ ├── src │ │ ├── components │ │ │ └── funcs.ts │ │ ├── als.ts │ │ └── waku.client.tsx │ ├── tsconfig.json │ └── package.json ├── 39_api │ ├── src │ │ ├── waku.client.tsx │ │ └── components │ │ │ └── App.tsx │ ├── tsconfig.json │ └── package.json ├── 35_nesting │ ├── tsconfig.json │ └── package.json ├── 53_islands │ ├── src │ │ ├── waku.client.tsx │ │ └── components │ │ │ └── Dynamic.tsx │ ├── tsconfig.json │ └── package.json └── 45_view-transitions │ ├── tsconfig.json │ └── src │ └── components │ └── Link.tsx ├── e2e └── fixtures │ ├── create-pages │ ├── private │ │ └── hi.txt │ ├── src │ │ ├── styles.css │ │ └── components │ │ │ ├── slice003.tsx │ │ │ ├── HomePage.tsx │ │ │ ├── NestedBazPage.tsx │ │ │ ├── ErrorRender.tsx │ │ │ ├── NoSsr.tsx │ │ │ ├── FooPage.tsx │ │ │ ├── OnlyClient.tsx │ │ │ ├── slice001.tsx │ │ │ ├── slice002.tsx │ │ │ ├── DynamicLayout.tsx │ │ │ ├── DeeplyNestedLayout.tsx │ │ │ ├── ServerThrows │ │ │ └── index.tsx │ │ │ ├── NestedLayout.tsx │ │ │ └── ErrorBoundary.tsx │ └── tsconfig.json │ ├── fs-router │ ├── private │ │ └── hi.txt │ ├── src │ │ ├── pages │ │ │ ├── css-split │ │ │ │ ├── page1 │ │ │ │ │ ├── styles.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── nested │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── _layout.tsx │ │ │ │ ├── page2 │ │ │ │ │ ├── styles.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── nested │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── _layout.tsx │ │ │ │ └── index.tsx │ │ │ ├── api │ │ │ │ ├── empty.ts │ │ │ │ ├── hi.txt.ts │ │ │ │ ├── has-default.ts │ │ │ │ └── hi.ts │ │ │ ├── _slices │ │ │ │ ├── two.tsx │ │ │ │ └── one.tsx │ │ │ ├── subroute │ │ │ │ ├── index.tsx │ │ │ │ └── [...catchAll].tsx │ │ │ ├── hello-server.tsx │ │ │ ├── nested │ │ │ │ ├── _layout.tsx │ │ │ │ └── [name].tsx │ │ │ ├── bar.tsx │ │ │ ├── foo │ │ │ │ └── index.tsx │ │ │ ├── index.tsx │ │ │ ├── page-with-segment │ │ │ │ ├── (article) │ │ │ │ │ └── [slug].tsx │ │ │ │ └── article │ │ │ │ │ └── [slug].tsx │ │ │ └── page-with-slices │ │ │ │ └── index.tsx │ │ ├── components │ │ │ ├── say-hello.tsx │ │ │ └── hello-client.tsx │ │ └── functions │ │ │ └── say-hello.tsx │ ├── tsconfig.json │ └── package.json │ ├── define-router │ ├── private │ │ └── hi.txt │ ├── README.md │ ├── src │ │ ├── routes │ │ │ ├── foo │ │ │ │ └── page.tsx │ │ │ ├── page.tsx │ │ │ ├── bar1 │ │ │ │ └── page.tsx │ │ │ └── bar2 │ │ │ │ └── page.tsx │ │ ├── components │ │ │ ├── slice001.tsx │ │ │ └── slice002.tsx │ │ └── waku.client.tsx │ ├── tsconfig.json │ └── package.json │ ├── tailwindcss │ ├── src │ │ ├── styles.css │ │ ├── components │ │ │ └── client.tsx │ │ └── pages │ │ │ ├── _layout.tsx │ │ │ └── index.tsx │ ├── .gitignore │ ├── waku.config.ts │ └── tsconfig.json │ ├── rsc-asset │ ├── src │ │ ├── components │ │ │ ├── test-client.txt │ │ │ └── test-server.txt │ │ ├── type.d.ts │ │ ├── waku.client.tsx │ │ └── waku.server.tsx │ ├── tsconfig.json │ └── package.json │ ├── hot-reload │ ├── declaration.d.ts │ ├── src │ │ ├── pages │ │ │ ├── css-modules.module.css │ │ │ ├── css-modules-client.module.css │ │ │ ├── css-modules-client.tsx │ │ │ ├── about.tsx │ │ │ ├── css-modules.tsx │ │ │ └── index.tsx │ │ └── components │ │ │ └── message.tsx │ ├── waku.config.ts │ ├── tsconfig.json │ └── package.json │ ├── partial-build │ ├── README.md │ ├── src │ │ └── pages │ │ │ ├── index.tsx │ │ │ └── _root.tsx │ ├── waku.config.ts │ └── tsconfig.json │ ├── ssr-basic │ ├── .env │ ├── README.md │ ├── private │ │ └── config.ts │ ├── public │ │ └── background.css │ ├── waku.config.ts │ ├── src │ │ └── components │ │ │ ├── test-client.tsx │ │ │ ├── test-app.tsx │ │ │ └── test-env │ │ │ └── server.tsx │ └── tsconfig.json │ ├── rsc-css-modules │ ├── declaration.d.ts │ ├── README.md │ ├── src │ │ ├── components │ │ │ ├── app.module.css │ │ │ └── clientCounter.module.css │ │ └── waku.client.tsx │ └── tsconfig.json │ ├── rsc-basic │ ├── README.md │ ├── index.html │ ├── modules │ │ └── ai │ │ │ ├── src │ │ │ ├── client.js │ │ │ ├── index.d.ts │ │ │ └── shared.js │ │ │ └── package.json │ ├── src │ │ ├── components │ │ │ ├── ServerThrows │ │ │ │ ├── actions.ts │ │ │ │ └── index.tsx │ │ │ ├── ServerAction │ │ │ │ ├── Server.tsx │ │ │ │ └── Client.tsx │ │ │ └── ServerPing │ │ │ │ ├── index.tsx │ │ │ │ └── actions.tsx │ │ └── waku.client.tsx │ └── tsconfig.json │ ├── ssr-swr │ ├── README.md │ ├── src │ │ ├── waku.client.tsx │ │ └── components │ │ │ └── App.tsx │ └── tsconfig.json │ ├── base-path │ ├── src │ │ ├── styles.css │ │ ├── pages │ │ │ ├── static.tsx │ │ │ ├── index.tsx │ │ │ └── dynamic.tsx │ │ └── components │ │ │ ├── counter.tsx │ │ │ └── hydrated.tsx │ ├── waku.config.ts │ ├── setup-static.js │ └── tsconfig.json │ ├── render-type │ ├── README.md │ ├── src │ │ ├── Echo.tsx │ │ ├── build │ │ │ ├── dynamic.tsx │ │ │ └── static.tsx │ │ ├── root.tsx │ │ ├── waku.client.tsx │ │ ├── ClientEcho.tsx │ │ └── ServerEcho.tsx │ ├── waku.config.ts │ └── tsconfig.json │ ├── ssg-performance │ ├── README.md │ ├── src │ │ ├── Path.tsx │ │ └── pages │ │ │ └── _layout.tsx │ └── tsconfig.json │ ├── monorepo │ ├── packages │ │ ├── dummy-library │ │ │ ├── src │ │ │ │ ├── index.d.ts │ │ │ │ ├── client.js │ │ │ │ └── index.js │ │ │ └── package.json │ │ ├── context-library │ │ │ ├── src │ │ │ │ ├── index.js │ │ │ │ ├── index.d.ts │ │ │ │ └── context-provider.js │ │ │ └── package.json │ │ └── waku-project │ │ │ ├── public │ │ │ └── images │ │ │ │ └── favicon.png │ │ │ ├── src │ │ │ └── components │ │ │ │ └── header.tsx │ │ │ └── tsconfig.json │ ├── pnpm-workspace.yaml │ └── package.json │ ├── ssr-catch-error │ ├── src │ │ ├── pages │ │ │ ├── no-error.tsx │ │ │ ├── invalid.tsx │ │ │ └── index.tsx │ │ ├── components │ │ │ └── server │ │ │ │ └── throws.tsx │ │ └── waku.server.tsx │ ├── waku.config.ts │ └── tsconfig.json │ ├── ssr-context-provider │ ├── README.md │ ├── src │ │ ├── components │ │ │ ├── context-provider.tsx │ │ │ └── app.tsx │ │ └── waku.client.tsx │ └── tsconfig.json │ ├── ssr-target-bundle │ ├── src │ │ ├── components │ │ │ ├── image-not-inlined.jpg │ │ │ └── Textarea.tsx │ │ ├── type.d.ts │ │ └── waku.client.tsx │ ├── README.md │ └── tsconfig.json │ ├── custom-library-adapter │ ├── waku.config.ts │ ├── src │ │ └── pages │ │ │ └── index.tsx │ ├── modules │ │ └── custom-adapter │ │ │ └── package.json │ └── tsconfig.json │ ├── wildcard-api-routes │ ├── src │ │ └── pages │ │ │ ├── api │ │ │ ├── [...misc].ts │ │ │ ├── greet.ts │ │ │ └── v1 │ │ │ │ └── [...apiWildcard].ts │ │ │ ├── _layout.tsx │ │ │ ├── _root.tsx │ │ │ └── [...wildcard].tsx │ └── tsconfig.json │ ├── waku-jotai-integration │ ├── waku.config.ts │ ├── src │ │ └── pages │ │ │ └── _layout.tsx │ └── tsconfig.json │ ├── custom-user-adapter │ ├── src │ │ ├── waku.server.tsx │ │ └── pages │ │ │ └── index.tsx │ └── tsconfig.json │ ├── ssg-wildcard │ ├── src │ │ └── pages │ │ │ ├── _layout.tsx │ │ │ └── [...wildcard].tsx │ ├── tsconfig.json │ └── package.json │ ├── broken-links │ ├── public │ │ └── serve.json │ ├── src │ │ ├── components │ │ │ └── ClientTitle.tsx │ │ └── pages │ │ │ ├── dynamic-not-found │ │ │ ├── sync.tsx │ │ │ └── async │ │ │ │ ├── index.tsx │ │ │ │ └── _layout.tsx │ │ │ ├── exists.tsx │ │ │ └── 404.tsx │ └── tsconfig.json │ ├── ssr-redirect │ ├── src │ │ └── pages │ │ │ ├── destination.tsx │ │ │ ├── sync.tsx │ │ │ ├── async │ │ │ ├── index.tsx │ │ │ └── _layout.tsx │ │ │ └── index.tsx │ ├── tsconfig.json │ └── package.json │ ├── styled-components │ ├── src │ │ ├── pages │ │ │ ├── index.tsx │ │ │ └── _layout.tsx │ │ └── components │ │ │ └── Counter.tsx │ └── tsconfig.json │ └── use-router │ ├── src │ └── pages │ │ ├── static.tsx │ │ └── dynamic.tsx │ ├── tsconfig.json │ └── package.json ├── .prettierignore ├── tsconfig.e2e.json ├── .codesandbox └── ci.json ├── docs └── community │ └── examples.mdx ├── .gitignore ├── tsconfig.eslint.json ├── pnpm-workspace.yaml └── .github └── workflows ├── lint.yml └── pkg-pr-new.yml /packages/website/.gitignore: -------------------------------------------------------------------------------- 1 | .env.local 2 | -------------------------------------------------------------------------------- /examples/37_css-stylex/src/index.css: -------------------------------------------------------------------------------- 1 | @stylex; 2 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/private/hi.txt: -------------------------------------------------------------------------------- 1 | hello from a text file! -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/private/hi.txt: -------------------------------------------------------------------------------- 1 | hello from a text file! -------------------------------------------------------------------------------- /examples/01_template/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /examples/06_form-demo/private/message.txt: -------------------------------------------------------------------------------- 1 | Hello from server! -------------------------------------------------------------------------------- /examples/07_cloudflare/public/404.html: -------------------------------------------------------------------------------- 1 |

Not Found

2 | -------------------------------------------------------------------------------- /examples/12_nossr/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /examples/21_create-pages/private/hi.txt: -------------------------------------------------------------------------------- 1 | hello from a text file! -------------------------------------------------------------------------------- /e2e/fixtures/define-router/private/hi.txt: -------------------------------------------------------------------------------- 1 | hello from a text file! -------------------------------------------------------------------------------- /e2e/fixtures/tailwindcss/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /examples/02_template_js/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /examples/07_cloudflare/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /examples/08_jotai-demo/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /examples/22_define-router/private/hi.txt: -------------------------------------------------------------------------------- 1 | hello from a text file! 2 | -------------------------------------------------------------------------------- /examples/42_react-tweet/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-asset/src/components/test-client.txt: -------------------------------------------------------------------------------- 1 | test-client-ok 2 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-asset/src/components/test-server.txt: -------------------------------------------------------------------------------- 1 | test-server-ok 2 | -------------------------------------------------------------------------------- /examples/01_template/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /RSC/ -------------------------------------------------------------------------------- /examples/31_minimal/public/404.html: -------------------------------------------------------------------------------- 1 |

Custom Not Found Page

2 | -------------------------------------------------------------------------------- /examples/32_minimal_js/public/404.html: -------------------------------------------------------------------------------- 1 |

Custom Not Found Page

2 | -------------------------------------------------------------------------------- /examples/37_css/src/components/app.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/declaration.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css'; 2 | -------------------------------------------------------------------------------- /e2e/fixtures/partial-build/README.md: -------------------------------------------------------------------------------- 1 | # Partial builds for static websites 2 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/.env: -------------------------------------------------------------------------------- 1 | WAKU_PUBLIC_TEST=ok 2 | WAKU_PRIVATE_TEST=ok 3 | -------------------------------------------------------------------------------- /packages/waku/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import './dist/cli.js'; 4 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-empty/pages/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-css-modules/declaration.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css'; 2 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/README.md: -------------------------------------------------------------------------------- 1 | # SSR Basic 2 | 3 | RSC features with SSR. 4 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/README.md: -------------------------------------------------------------------------------- 1 | # RSC Basic 2 | 3 | Only RSC features, no SSR. 4 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-swr/README.md: -------------------------------------------------------------------------------- 1 | # SSR SWR 2 | 3 | RSC features with SSR with SWR. 4 | -------------------------------------------------------------------------------- /packages/create-waku/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import './dist/index.js'; 4 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/src/styles.css: -------------------------------------------------------------------------------- 1 | .test-style { 2 | color: rgb(255, 150, 0); 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fefefe; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/README.md: -------------------------------------------------------------------------------- 1 | # RSC Router 2 | 3 | Only RSC features, no SSR. 4 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/README.md: -------------------------------------------------------------------------------- 1 | # Render types 2 | 3 | Test different render types. 4 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fefefe; 3 | } 4 | -------------------------------------------------------------------------------- /examples/22_define-router/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fefefe; 3 | } 4 | -------------------------------------------------------------------------------- /examples/43_weave-render/src/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fefefe; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/private/config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | content: 'hello world', 3 | }; 4 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/public/background.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f0f0f0; 3 | } 4 | -------------------------------------------------------------------------------- /examples/37_css/src/components/app.module.css: -------------------------------------------------------------------------------- 1 | .title { 2 | background-color: pink; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/src/pages/css-modules.module.css: -------------------------------------------------------------------------------- 1 | .h1 { 2 | background-color: green; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/ssg-performance/README.md: -------------------------------------------------------------------------------- 1 | # SSG Performance 2 | 3 | Test high volume SSG performance. 4 | -------------------------------------------------------------------------------- /examples/37_css/src/components/layout.styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: lightyellow; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/page1/styles.css: -------------------------------------------------------------------------------- 1 | .test-css-split { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/page2/styles.css: -------------------------------------------------------------------------------- 1 | .test-css-split { 2 | color: blue; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/dummy-library/src/index.d.ts: -------------------------------------------------------------------------------- 1 | export declare function Hello(): string; 2 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | linkWorkspacePackages: true 4 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/src/pages/css-modules-client.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | background-color: red; 3 | } 4 | -------------------------------------------------------------------------------- /examples/03_demo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /examples/12_nossr/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /packages/website/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/packages/website/public/favicon.ico -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/api/empty.ts: -------------------------------------------------------------------------------- 1 | export const GET = async () => { 2 | return new Response(null); 3 | }; 4 | -------------------------------------------------------------------------------- /examples/01_template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /examples/02_template_js/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /examples/04_cssmodules/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /examples/06_form-demo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /examples/08_jotai-demo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /examples/42_react-tweet/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | 3 | export default defineConfig({}); 4 | -------------------------------------------------------------------------------- /e2e/fixtures/tailwindcss/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | -------------------------------------------------------------------------------- /e2e/fixtures/ssg-performance/src/Path.tsx: -------------------------------------------------------------------------------- 1 | export function Path({ path }: { path: string }) { 2 | return

{path}

; 3 | } 4 | -------------------------------------------------------------------------------- /examples/03_demo/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/03_demo/public/images/favicon.png -------------------------------------------------------------------------------- /examples/12_nossr/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/12_nossr/public/images/favicon.png -------------------------------------------------------------------------------- /e2e/fixtures/ssr-catch-error/src/pages/no-error.tsx: -------------------------------------------------------------------------------- 1 | export default async function HomePage() { 2 | return

No Error

; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-context-provider/README.md: -------------------------------------------------------------------------------- 1 | # SSR Context Provider 2 | 3 | To cover https://github.com/wakujs/waku/issues/631 case 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /.codesandbox 2 | /.github 3 | pnpm-lock.yaml 4 | pnpm-workspace.yaml 5 | dist 6 | worker-configuration.d.ts 7 | .wrangler 8 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/dummy-library/src/client.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export function Hello() { 4 | return 'hello'; 5 | } 6 | -------------------------------------------------------------------------------- /examples/01_template/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/01_template/public/images/favicon.png -------------------------------------------------------------------------------- /examples/04_cssmodules/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/04_cssmodules/public/images/favicon.png -------------------------------------------------------------------------------- /examples/06_form-demo/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/06_form-demo/public/images/favicon.png -------------------------------------------------------------------------------- /examples/07_cloudflare/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/07_cloudflare/public/images/favicon.png -------------------------------------------------------------------------------- /examples/08_jotai-demo/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/08_jotai-demo/public/images/favicon.png -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/src/components/message.tsx: -------------------------------------------------------------------------------- 1 | export const Message = () => { 2 | return
Mesg 1000
; 3 | }; 4 | -------------------------------------------------------------------------------- /examples/02_template_js/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/02_template_js/public/images/favicon.png -------------------------------------------------------------------------------- /examples/42_react-tweet/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/examples/42_react-tweet/public/images/favicon.png -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/slice003.tsx: -------------------------------------------------------------------------------- 1 | export function Slice003() { 2 | return
Slice 003
; 3 | } 4 | -------------------------------------------------------------------------------- /packages/waku/src/client.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Highly experimental, the name might change. 3 | */ 4 | export const unstable_allowServer = (x: T) => x; 5 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-complex/pages/blog/[slug].tsx: -------------------------------------------------------------------------------- 1 | export default function BlogPost() { 2 | return null; 3 | } 4 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-complex/pages/docs/_layout.tsx: -------------------------------------------------------------------------------- 1 | export default function DocsLayout() { 2 | return null; 3 | } 4 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-complex/pages/blog/_components/widget.tsx: -------------------------------------------------------------------------------- 1 | export default function Widget() { 2 | return null; 3 | } 4 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-with-createpages/pages/index.tsx: -------------------------------------------------------------------------------- 1 | export default function HomePage() { 2 | return
Home
; 3 | } 4 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-with-fsrouter/pages/index.tsx: -------------------------------------------------------------------------------- 1 | export default function HomePage() { 2 | return
Home
; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | 3 | export default defineConfig({ 4 | basePath: '/custom/base/', 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return
css-split / index
; 3 | } 4 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/types.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.css' { 2 | const classes: { readonly [key: string]: string }; 3 | export default classes; 4 | } 5 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-asset/src/type.d.ts: -------------------------------------------------------------------------------- 1 | // FIXME this is a hack for now 2 | 3 | declare module '*?no-inline' { 4 | const src: string; 5 | export default src; 6 | } 7 | -------------------------------------------------------------------------------- /examples/03_demo/src/lib/pokemon.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | 3 | export const pokemon = JSON.parse( 4 | fs.readFileSync('./private/pokemon.json', 'utf8'), 5 | ); 6 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/context-library/src/index.js: -------------------------------------------------------------------------------- 1 | export { ContextProvider } from './context-provider'; 2 | export { ContextConsumer } from './context-consumer'; 3 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-css-modules/README.md: -------------------------------------------------------------------------------- 1 | # RSC CSS Modules 2 | 3 | Only RSC features, no SSR. Using css modules to style the application, both on server and client components. 4 | -------------------------------------------------------------------------------- /examples/07_cloudflare/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .env* 4 | *.tsbuildinfo 5 | .cache 6 | .DS_Store 7 | *.pem 8 | .wrangler 9 | worker-configuration.d.ts 10 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/src/routes/foo/page.tsx: -------------------------------------------------------------------------------- 1 | const Foo = () => ( 2 |
3 |

Foo

4 |
5 | ); 6 | 7 | export default Foo; 8 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/page1/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return
css-split / page1 / index
; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/page2/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return
css-split / page2 / index
; 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-target-bundle/src/components/image-not-inlined.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/e2e/fixtures/ssr-target-bundle/src/components/image-not-inlined.jpg -------------------------------------------------------------------------------- /e2e/fixtures/custom-library-adapter/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | 3 | export default defineConfig({ 4 | unstable_adapter: 'custom-adapter', 5 | }); 6 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/waku-project/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wakujs/waku/HEAD/e2e/fixtures/monorepo/packages/waku-project/public/images/favicon.png -------------------------------------------------------------------------------- /e2e/fixtures/wildcard-api-routes/src/pages/api/[...misc].ts: -------------------------------------------------------------------------------- 1 | export async function GET(__request: Request): Promise { 2 | return new Response('/api root catch-all'); 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/wildcard-api-routes/src/pages/api/greet.ts: -------------------------------------------------------------------------------- 1 | export async function GET(__request: Request): Promise { 2 | return new Response('Greetings from the API!'); 3 | } 4 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/NestedQuxPage.tsx: -------------------------------------------------------------------------------- 1 | const Qux = () => ( 2 |
3 |

Nested

4 |

Qux

5 |
6 | ); 7 | 8 | export default Qux; 9 | -------------------------------------------------------------------------------- /examples/22_define-router/src/components/NestedBazPage.tsx: -------------------------------------------------------------------------------- 1 | const Baz = () => ( 2 |
3 |

Nested

4 |

Baz

5 |
6 | ); 7 | 8 | export default Baz; 9 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/dummy-library/src/index.js: -------------------------------------------------------------------------------- 1 | // Do not add '.js' extension to reproduce the issue 2 | // https://github.com/wakujs/waku/pull/1143 3 | export * from './client'; 4 | -------------------------------------------------------------------------------- /e2e/fixtures/wildcard-api-routes/src/pages/api/v1/[...apiWildcard].ts: -------------------------------------------------------------------------------- 1 | export async function GET(__request: Request): Promise { 2 | return new Response('API Wildcard!'); 3 | } 4 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/HomePage.tsx: -------------------------------------------------------------------------------- 1 | const Home = () => ( 2 |
3 |

Home

4 |

This is the home page.

5 |
6 | ); 7 | 8 | export default Home; 9 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/HomePage.tsx: -------------------------------------------------------------------------------- 1 | const Home = () => ( 2 |
3 |

Home

4 |

This is the home page.

5 |
6 | ); 7 | 8 | export default Home; 9 | -------------------------------------------------------------------------------- /examples/22_define-router/src/components/HomePage.tsx: -------------------------------------------------------------------------------- 1 | const Home = () => ( 2 |
3 |

Home

4 |

This is the home page.

5 |
6 | ); 7 | 8 | export default Home; 9 | -------------------------------------------------------------------------------- /examples/43_weave-render/src/components/HomePage.tsx: -------------------------------------------------------------------------------- 1 | const Home = () => ( 2 |
3 |

Home

4 |

This is the home page.

5 |
6 | ); 7 | 8 | export default Home; 9 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-css-modules/src/components/app.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: flex; 3 | flex-direction: column; 4 | } 5 | 6 | .text { 7 | font-size: 18px; 8 | color: blue; 9 | } 10 | -------------------------------------------------------------------------------- /examples/03_demo/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | 3 | @theme { 4 | --font-*: initial; 5 | --font-nunito: 'Nunito', sans-serif; 6 | --font-zen-maru-gothic: 'Zen Maru Gothic', serif; 7 | } 8 | -------------------------------------------------------------------------------- /examples/41_path-alias/src/components/MyFragment.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export const MyFragment = ({ children }: { children: ReactNode }) => ( 4 | <>{children} 5 | ); 6 | -------------------------------------------------------------------------------- /packages/waku/src/lib/vite-entries/entry.ssr.tsx: -------------------------------------------------------------------------------- 1 | export { 2 | renderHtmlStream as INTERNAL_renderHtmlStream, 3 | renderHtmlFallback as INTERNAL_renderHtmlFallback, 4 | } from '../vite-rsc/ssr.js'; 5 | -------------------------------------------------------------------------------- /tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "types": ["node"] 6 | }, 7 | "include": ["playwright.config.ts", "./e2e/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/page1/nested/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
css-split / page1 / nested / index
4 | ); 5 | } 6 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/page2/nested/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
css-split / page2 / nested / index
4 | ); 5 | } 6 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/06_form-demo/src/styles.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | 3 | @theme { 4 | --font-*: initial; 5 | --font-nunito: 'Nunito', sans-serif; 6 | --font-zen-maru-gothic: 'Zen Maru Gothic', serif; 7 | } 8 | -------------------------------------------------------------------------------- /packages/website/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export type BlogFrontmatter = { 2 | slug: string; 3 | title: string; 4 | description: string; 5 | author: string; 6 | release: string; 7 | date: string; 8 | }; 9 | -------------------------------------------------------------------------------- /packages/website/src/smartquotes.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'smartquotes' { 2 | interface SmartQuotesInstance { 3 | listen(): void; 4 | } 5 | export default function smartquotes(): SmartQuotesInstance; 6 | } 7 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-css-modules/src/components/clientCounter.module.css: -------------------------------------------------------------------------------- 1 | .counterWrapper { 2 | display: flex; 3 | flex-direction: row; 4 | gap: 4px; 5 | } 6 | 7 | .counterButton { 8 | padding: 8px; 9 | } 10 | -------------------------------------------------------------------------------- /e2e/fixtures/ssg-performance/src/pages/_layout.tsx: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren } from 'react'; 2 | 3 | export default function Layout({ children }: PropsWithChildren) { 4 | return
{children}
; 5 | } 6 | -------------------------------------------------------------------------------- /packages/waku/src/main.react-server.ts: -------------------------------------------------------------------------------- 1 | export { Link, useRouter, Slice } from 'waku/router/client'; 2 | 3 | export { createPages, fsRouter } from 'waku/router/server'; 4 | 5 | export { getEnv } from 'waku/server'; 6 | -------------------------------------------------------------------------------- /examples/12_nossr/waku.config.ts: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite'; 2 | import { defineConfig } from 'waku/config'; 3 | 4 | export default defineConfig({ 5 | vite: { 6 | plugins: [tailwindcss()], 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /examples/37_css-vanilla-extract/src/server.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | export const serverStyle = style({ 4 | border: '1px green solid', 5 | padding: '0.5rem', 6 | margin: '0.5rem', 7 | }); 8 | -------------------------------------------------------------------------------- /examples/54_jotai/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | 3 | export default defineConfig({ 4 | vite: { 5 | optimizeDeps: { 6 | exclude: ['waku-jotai'], 7 | }, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-complex/pages/docs/index.tsx: -------------------------------------------------------------------------------- 1 | const getConfig = () => ({ render: 'dynamic' }); 2 | 3 | export { getConfig }; 4 | 5 | export default function Docs() { 6 | return null; 7 | } 8 | -------------------------------------------------------------------------------- /e2e/fixtures/partial-build/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | export default function HomePage() { 2 | return
Home
; 3 | } 4 | 5 | export async function getConfig() { 6 | return { 7 | render: 'static', 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | 3 | export default defineConfig({ 4 | vite: { 5 | optimizeDeps: { 6 | exclude: ['@ai-sdk/rsc'], 7 | }, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/BarPage.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from './Counter'; 2 | 3 | const Bar = () => ( 4 |
5 |

Bar

6 | 7 |
8 | ); 9 | 10 | export default Bar; 11 | -------------------------------------------------------------------------------- /examples/22_define-router/src/components/BarPage.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from './Counter'; 2 | 3 | const Bar = () => ( 4 |
5 |

Bar

6 | 7 |
8 | ); 9 | 10 | export default Bar; 11 | -------------------------------------------------------------------------------- /examples/22_define-router/src/components/FooPage.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from './Counter'; 2 | 3 | const Foo = () => ( 4 |
5 |

Foo

6 | 7 |
8 | ); 9 | 10 | export default Foo; 11 | -------------------------------------------------------------------------------- /examples/37_css-vanilla-extract/src/client.css.ts: -------------------------------------------------------------------------------- 1 | import { style } from '@vanilla-extract/css'; 2 | 3 | export const clientStyle = style({ 4 | border: '1px orange solid', 5 | padding: '0.5rem', 6 | margin: '0.5rem', 7 | }); 8 | -------------------------------------------------------------------------------- /examples/43_weave-render/src/components/BarPage.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from './Counter'; 2 | 3 | const Bar = () => ( 4 |
5 |

Bar

6 | 7 |
8 | ); 9 | 10 | export default Bar; 11 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-complex/pages/admin/dashboard.tsx: -------------------------------------------------------------------------------- 1 | export function getConfig() { 2 | return { render: 'dynamic' }; 3 | } 4 | 5 | export default function Dashboard() { 6 | return null; 7 | } 8 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/NestedBazPage.tsx: -------------------------------------------------------------------------------- 1 | const Baz = () => ( 2 |
3 |

Nested

4 |

Baz

5 |

{new Date().toISOString()}

6 |
7 | ); 8 | 9 | export default Baz; 10 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/api/hi.txt.ts: -------------------------------------------------------------------------------- 1 | import { readFile } from 'node:fs/promises'; 2 | 3 | export const GET = async () => { 4 | const text = await readFile('./private/hi.txt', 'utf-8'); 5 | return new Response(text); 6 | }; 7 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/page1/_layout.tsx: -------------------------------------------------------------------------------- 1 | import './styles.css'; 2 | import type { PropsWithChildren } from 'react'; 3 | 4 | export default function Layout(props: PropsWithChildren) { 5 | return props.children; 6 | } 7 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/css-split/page2/_layout.tsx: -------------------------------------------------------------------------------- 1 | import './styles.css'; 2 | import type { PropsWithChildren } from 'react'; 3 | 4 | export default function Layout(props: PropsWithChildren) { 5 | return props.children; 6 | } 7 | -------------------------------------------------------------------------------- /e2e/fixtures/tailwindcss/waku.config.ts: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite'; 2 | import { defineConfig } from 'waku/config'; 3 | 4 | export default defineConfig({ 5 | vite: { 6 | plugins: [tailwindcss()], 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/NestedBazPage.tsx: -------------------------------------------------------------------------------- 1 | const Baz = () => ( 2 |
3 |

Nested

4 |

Baz

5 |

{new Date().toISOString()}

6 |
7 | ); 8 | 9 | export default Baz; 10 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/StaticSlice.tsx: -------------------------------------------------------------------------------- 1 | export default function StaticSlice() { 2 | return ( 3 |

4 | Static Slice {new Date().toLocaleString()} 5 |

6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-complex/pages/(group)/landing/index.tsx: -------------------------------------------------------------------------------- 1 | export default function LandingPage() { 2 | return null; 3 | } 4 | 5 | export function getConfig() { 6 | return { render: 'static' }; 7 | } 8 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/api/has-default.ts: -------------------------------------------------------------------------------- 1 | export default function handler(req: Request) { 2 | return new Response('default: ' + req.method); 3 | } 4 | 5 | export function GET(_req: Request) { 6 | return new Response('GET'); 7 | } 8 | -------------------------------------------------------------------------------- /e2e/fixtures/waku-jotai-integration/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | 3 | export default defineConfig({ 4 | vite: { 5 | optimizeDeps: { 6 | exclude: ['waku-jotai'], 7 | }, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /examples/41_path-alias/waku.config.ts: -------------------------------------------------------------------------------- 1 | import tsconfigPaths from 'vite-tsconfig-paths'; 2 | import { defineConfig } from 'waku/config'; 3 | 4 | export default defineConfig({ 5 | vite: { 6 | plugins: [tsconfigPaths()], 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen/pages/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return null; 3 | } 4 | 5 | export const getConfig = async () => { 6 | return { 7 | render: 'dynamic', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/ErrorRender.tsx: -------------------------------------------------------------------------------- 1 | const ErrorRender = async () => { 2 | await new Promise((resolve) => setTimeout(resolve, 1)); 3 | throw new Error('Something unexpected happened'); 4 | }; 5 | export default ErrorRender; 6 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/NoSsr.tsx: -------------------------------------------------------------------------------- 1 | import { OnlyClient } from './OnlyClient.js'; 2 | 3 | const NoSsr = () => ( 4 |
5 |

No SSR

6 | 7 |
8 | ); 9 | 10 | export default NoSsr; 11 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/DynamicSlice.tsx: -------------------------------------------------------------------------------- 1 | export default function DynamicSlice() { 2 | return ( 3 |

4 | Dynamic Slice Component {new Date().toLocaleString()} 5 |

6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /examples/37_css/src/type.d.ts: -------------------------------------------------------------------------------- 1 | // FIXME this is a hack for now 2 | 3 | type CSSModuleClasses = { readonly [key: string]: string }; 4 | 5 | declare module '*.module.css' { 6 | const classes: CSSModuleClasses; 7 | export default classes; 8 | } 9 | -------------------------------------------------------------------------------- /packages/waku/src/lib/global-types.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | var __WAKU_RSC_RELOAD_LISTENERS__: (() => void)[] | undefined; 3 | var __WAKU_REFETCH_RSC__: (() => void) | undefined; 4 | var __WAKU_REFETCH_ROUTE__: (() => void) | undefined; 5 | } 6 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-with-fsrouter-alias/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { fsRouter as createRouter } from 'waku'; 2 | import adapter from 'waku/adapters/default'; 3 | 4 | export default adapter(createRouter({} as never)); 5 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen/pages/_layout.tsx: -------------------------------------------------------------------------------- 1 | export default function Layout() { 2 | return null; 3 | } 4 | 5 | export const getConfig = async () => { 6 | return { 7 | render: 'static', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/api/hi.ts: -------------------------------------------------------------------------------- 1 | export async function GET() { 2 | return new Response('Hello from API!'); 3 | } 4 | 5 | export async function POST(req: Request) { 6 | return new Response(`POST Hello from API! ${await req.text()}`); 7 | } 8 | -------------------------------------------------------------------------------- /e2e/fixtures/tailwindcss/src/components/client.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export function TestClient() { 4 | return ( 5 |
6 | test-client 7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen/pages/one-two-three.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return null; 3 | } 4 | 5 | export const getConfig = async () => { 6 | return { 7 | render: 'dynamic', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen/pages/one__two_three.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return null; 3 | } 4 | 5 | export const getConfig = async () => { 6 | return { 7 | render: 'dynamic', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen/pages/one_two_three.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return null; 3 | } 4 | 5 | export const getConfig = async () => { 6 | return { 7 | render: 'dynamic', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen/pages/øné_two_three.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return null; 3 | } 4 | 5 | export const getConfig = async () => { 6 | return { 7 | render: 'dynamic', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/waku/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "lib": ["esnext", "dom", "dom.iterable"] 7 | }, 8 | "include": ["src"] 9 | } 10 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/components/say-hello.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { use } from 'react'; 4 | 5 | export function SayHello({ promise }: { promise: Promise }) { 6 | const name = use(promise); 7 | return
Hello {name}
; 8 | } 9 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/_slices/two.tsx: -------------------------------------------------------------------------------- 1 | export default function Slice002() { 2 | return

Slice 002

; 3 | } 4 | 5 | export const getConfig = () => { 6 | return { 7 | render: 'static', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/modules/ai/src/client.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { useActions } from './shared.js'; 3 | 4 | export { useActions }; 5 | 6 | export function createAI() { 7 | throw new Error('You should not call createAI in the client side'); 8 | } 9 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | export async function GET() { 2 | return new Response('Hello from API!'); 3 | } 4 | 5 | export async function POST(req: Request) { 6 | return new Response(`Hello from API! ${new URL(req.url).pathname}`); 7 | } 8 | -------------------------------------------------------------------------------- /examples/33_promise/src/components/Hello.tsx: -------------------------------------------------------------------------------- 1 | export const Hello = () => { 2 | return ( 3 |
4 | This is a component without {'"use client"'}. 5 |
6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /examples/42_react-tweet/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | export const Header = () => { 2 | return ( 3 |
4 |

Waku starter

5 |
6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen/pages/[category]/_layout.tsx: -------------------------------------------------------------------------------- 1 | export default function Layout() { 2 | return null; 3 | } 4 | 5 | export const getConfig = async () => { 6 | return { 7 | render: 'static', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /.codesandbox/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/waku"], 3 | "installCommand": "csb-install-FIXME", 4 | "buildCommand": "compile", 5 | "sandboxes": ["vanilla", "vanilla-typescript-vanilla-ts", "new", "react-typescript-react-ts"], 6 | "node": "20" 7 | } 8 | -------------------------------------------------------------------------------- /e2e/fixtures/custom-user-adapter/src/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { fsRouter } from 'waku'; 2 | import adapter from './custom-adapter.js'; 3 | 4 | const router = fsRouter(import.meta.glob('./**/*.tsx', { base: './pages' })); 5 | 6 | export default adapter(router); 7 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/src/components/ServerThrows/actions.ts: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | export const throws = async (input: string): Promise => { 4 | if (!input) { 5 | throw new Error('Something unexpected happened'); 6 | } 7 | return input; 8 | }; 9 | -------------------------------------------------------------------------------- /e2e/fixtures/tailwindcss/src/pages/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | import '../styles.css'; 3 | 4 | export default async function RootLayout({ 5 | children, 6 | }: { 7 | children: ReactNode; 8 | }) { 9 | return children; 10 | } 11 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/FooPage.tsx: -------------------------------------------------------------------------------- 1 | import 'server-only'; 2 | 3 | import { Counter } from './Counter'; 4 | 5 | const Foo = () => ( 6 |
7 |

Foo

8 | 9 |
10 | ); 11 | 12 | export default Foo; 13 | -------------------------------------------------------------------------------- /examples/43_weave-render/src/components/FooPage.tsx: -------------------------------------------------------------------------------- 1 | import 'server-only'; 2 | 3 | import { Counter } from './Counter'; 4 | 5 | const Foo = () => ( 6 |
7 |

Foo

8 | 9 |
10 | ); 11 | 12 | export default Foo; 13 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen/pages/[category]/[...tags]/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return null; 3 | } 4 | 5 | export const getConfig = async () => { 6 | return { 7 | render: 'dynamic', 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/FooPage.tsx: -------------------------------------------------------------------------------- 1 | import 'server-only'; 2 | 3 | import { Counter } from './Counter.js'; 4 | 5 | const Foo = () => ( 6 |
7 |

Foo

8 | 9 |
10 | ); 11 | 12 | export default Foo; 13 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | const Home = () => ( 2 |
3 |

Home

4 |
5 | ); 6 | 7 | export const getConfig = () => { 8 | return { 9 | render: 'dynamic', 10 | } as const; 11 | }; 12 | 13 | export default Home; 14 | -------------------------------------------------------------------------------- /examples/34_functions/src/components2/ButtonClient.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export default function ButtonClient({ 4 | onClick, 5 | }: { 6 | onClick: () => Promise; 7 | }) { 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/src/Echo.tsx: -------------------------------------------------------------------------------- 1 | export function Echo({ echo, timestamp }: { echo: string; timestamp: number }) { 2 | return ( 3 |
4 |

{echo}

5 |

{timestamp}

6 |
7 | ); 8 | } 9 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-target-bundle/src/type.d.ts: -------------------------------------------------------------------------------- 1 | // FIXME this is a hack for now 2 | 3 | declare module '*.jpg' { 4 | const src: string; 5 | export default src; 6 | } 7 | 8 | declare module '*?url' { 9 | const src: string; 10 | export default src; 11 | } 12 | -------------------------------------------------------------------------------- /examples/38_cookies/src/middleware/noop.ts: -------------------------------------------------------------------------------- 1 | import type { MiddlewareHandler } from 'hono'; 2 | 3 | const noopMiddleware = (): MiddlewareHandler => { 4 | return async (_c, next) => { 5 | await next(); 6 | }; 7 | }; 8 | 9 | export default noopMiddleware; 10 | -------------------------------------------------------------------------------- /packages/waku/src/internals.ts: -------------------------------------------------------------------------------- 1 | export { createServerEntryAdapter as unstable_createServerEntryAdapter } from './lib/vite-rsc/handler.js'; 2 | export * as unstable_constants from './lib/constants.js'; 3 | export * as unstable_honoMiddleware from './lib/hono/middleware.js'; 4 | -------------------------------------------------------------------------------- /docs/community/examples.mdx: -------------------------------------------------------------------------------- 1 | # Community Work 2 | 3 | - [Waku with yarn pnp](https://github.com/bysxx/waku-with-yarn-pnp) @bysxx 4 | - [Waku with TailwindCSS v4 & Shadcn/ui & SSR pre-hydrated theme logic](https://github.com/JesseKoldewijn/waku-tw4-shadcn-starter) @JesseKoldewijn 5 | -------------------------------------------------------------------------------- /e2e/fixtures/partial-build/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | 3 | export default defineConfig({ 4 | vite: { 5 | environments: { 6 | client: { 7 | build: { emptyOutDir: false }, 8 | }, 9 | }, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /e2e/fixtures/ssg-wildcard/src/pages/_layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | const Layout = ({ children }: { children: ReactNode }) => ( 4 |
5 | Waku 6 | {children} 7 |
8 | ); 9 | 10 | export default Layout; 11 | -------------------------------------------------------------------------------- /examples/37_css-vanilla-extract/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; 2 | import { defineConfig } from 'waku/config'; 3 | 4 | export default defineConfig({ 5 | vite: { 6 | plugins: [vanillaExtractPlugin()], 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-with-fsrouter/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { fsRouter } from 'waku'; 2 | import adapter from 'waku/adapters/default'; 3 | 4 | export default adapter( 5 | fsRouter(import.meta.glob('./**/*.{tsx,ts}', { base: './pages' })), 6 | ); 7 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/setup-static.js: -------------------------------------------------------------------------------- 1 | import { cpSync, mkdirSync, rmSync } from 'node:fs'; 2 | 3 | rmSync('dist/.tmp', { recursive: true, force: true }); 4 | mkdirSync('dist/.tmp/custom', { recursive: true }); 5 | cpSync('dist/public', 'dist/.tmp/custom/base', { recursive: true }); 6 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/context-library/src/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { ReactElement, ReactNode } from 'react'; 2 | 3 | export declare function ContextProvider(propx: { 4 | children: ReactNode; 5 | }): ReactElement; 6 | export declare function ContextConsumer(): ReactElement; 7 | -------------------------------------------------------------------------------- /examples/52_tanstack-router/src/server-fns.ts: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | export const getServerTime = async () => { 4 | // Wait for 1 second 5 | await new Promise((resolve) => setTimeout(resolve, 1000)); 6 | // Return the current time 7 | return new Date().toISOString(); 8 | }; 9 | -------------------------------------------------------------------------------- /packages/waku/src/lib/utils/fs-router.ts: -------------------------------------------------------------------------------- 1 | const IGNORED_PATH_PARTS = new Set(['_components', '_hooks']); 2 | 3 | /** Ignore paths like `_components` and `_hooks` in pages dir */ 4 | export const isIgnoredPath = (paths: string[]) => 5 | paths.some((p) => IGNORED_PATH_PARTS.has(p)); 6 | -------------------------------------------------------------------------------- /e2e/fixtures/broken-links/public/serve.json: -------------------------------------------------------------------------------- 1 | { 2 | "redirects": [ 3 | { "source": "/redirect", "destination": "/exists" }, 4 | { "source": "/RSC/R/redirect.txt", "destination": "/RSC/R/exists.txt" }, 5 | { "source": "/broken-redirect", "destination": "/broken" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-catch-error/src/components/server/throws.tsx: -------------------------------------------------------------------------------- 1 | export const ThrowsComponent = async () => { 2 | await new Promise((_, reject) => { 3 | reject(new Error('Unexpected error')); 4 | }); 5 | return
Success
; 6 | }; 7 | 8 | export default ThrowsComponent; 9 | -------------------------------------------------------------------------------- /e2e/fixtures/wildcard-api-routes/src/pages/_layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | const Layout = ({ children }: { children: ReactNode }) => ( 4 |
5 | Waku 6 | {children} 7 |
8 | ); 9 | 10 | export default Layout; 11 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/OnlyClient.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export const OnlyClient = () => { 4 | if (typeof window === 'undefined') { 5 | throw new Error('This component must be used in a client context'); 6 | } 7 | return

Only client component

; 8 | }; 9 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/slice001.tsx: -------------------------------------------------------------------------------- 1 | export const Slice001 = () => { 2 | // TODO is there a more reasonable way? 3 | // eslint-disable-next-line react-hooks/purity 4 | const rand = Math.random(); 5 | return

Slice 001 ({rand})

; 6 | }; 7 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/slice002.tsx: -------------------------------------------------------------------------------- 1 | export const Slice002 = () => { 2 | // TODO is there a more reasonable way? 3 | // eslint-disable-next-line react-hooks/purity 4 | const rand = Math.random(); 5 | return

Slice 002 ({rand})

; 6 | }; 7 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/src/components/slice001.tsx: -------------------------------------------------------------------------------- 1 | export const Slice001 = () => { 2 | // TODO is there a more reasonable way? 3 | // eslint-disable-next-line react-hooks/purity 4 | const rand = Math.random(); 5 | return

Slice 001 ({rand})

; 6 | }; 7 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/src/components/slice002.tsx: -------------------------------------------------------------------------------- 1 | export const Slice002 = () => { 2 | // TODO is there a more reasonable way? 3 | // eslint-disable-next-line react-hooks/purity 4 | const rand = Math.random(); 5 | return

Slice 002 ({rand})

; 6 | }; 7 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/subroute/index.tsx: -------------------------------------------------------------------------------- 1 | const Subroute = () => ( 2 |
3 |

Subroute

4 |
5 | ); 6 | 7 | export const getConfig = () => { 8 | return { 9 | render: 'dynamic', 10 | } as const; 11 | }; 12 | 13 | export default Subroute; 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | node_modules 4 | dist 5 | /packages/waku/README.md 6 | /packages/website/.vercel 7 | /packages/create-waku/template 8 | .env.local 9 | .devcontainer 10 | .vscode 11 | *.tsbuildinfo 12 | .cache 13 | .nvmrc 14 | .node-version 15 | pages.gen.ts 16 | test-results 17 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/modules/ai/src/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | declare function createAI( 4 | actions: Record any>, 5 | ): (props: { children: ReactNode }) => ReactNode; 6 | 7 | declare function useActions(): Record; 8 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/pages/about.module.css: -------------------------------------------------------------------------------- 1 | .h1 { 2 | font-size: 2.25rem; 3 | line-height: 2.5rem; 4 | font-weight: 700; 5 | letter-spacing: -0.025em; 6 | } 7 | 8 | .link { 9 | margin-top: 1rem; 10 | display: inline-block; 11 | text-decoration-line: underline; 12 | } 13 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | .h1 { 2 | font-size: 2.25rem; 3 | line-height: 2.5rem; 4 | font-weight: 700; 5 | letter-spacing: -0.025em; 6 | } 7 | 8 | .link { 9 | margin-top: 1rem; 10 | display: inline-block; 11 | text-decoration-line: underline; 12 | } 13 | -------------------------------------------------------------------------------- /packages/website/src/components/smart-quotes.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useEffect } from 'react'; 4 | import smartquotes from 'smartquotes'; 5 | 6 | export function SmartQuotes() { 7 | useEffect(() => { 8 | smartquotes().listen(); 9 | }, []); 10 | 11 | return null; 12 | } 13 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/DynamicLayout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export default function DynamicLayout({ children }: { children: ReactNode }) { 4 | return ( 5 | <> 6 | 7 | {children} 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-with-fsrouter-fake/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { createPages as fsRouter } from 'waku'; 2 | import adapter from 'waku/adapters/default'; 3 | 4 | export default adapter( 5 | fsRouter(import.meta.glob('./**/*.{tsx,ts}', { base: './pages' }) as never), 6 | ); 7 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/src/pages/static.tsx: -------------------------------------------------------------------------------- 1 | export default async function AboutPage() { 2 | return ( 3 |
4 |

Static page

5 |
Renderd at {new Date().toISOString()}
6 |
Argv: {JSON.stringify(process.argv.slice(2))}
7 |
8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /e2e/fixtures/broken-links/src/components/ClientTitle.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useEffect } from 'react'; 4 | 5 | export const ClientTitle = ({ children }: { children: string }) => { 6 | useEffect(() => { 7 | document.title = children; 8 | }, [children]); 9 | return null; 10 | }; 11 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/src/routes/page.tsx: -------------------------------------------------------------------------------- 1 | import { Slice } from 'waku/router/client'; 2 | 3 | const Home = () => ( 4 |
5 |

Home

6 |

This is the home page.

7 | 8 |
9 | ); 10 | 11 | export default Home; 12 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-catch-error/src/pages/invalid.tsx: -------------------------------------------------------------------------------- 1 | export default async function InvalidPage() { 2 | return ( 3 |
4 |

Invalid Page

5 |
6 | ); 7 | } 8 | 9 | export const getConfig = async () => { 10 | return { 11 | render: 'dynamic', 12 | } as const; 13 | }; 14 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-catch-error/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | 3 | export default defineConfig({ 4 | /** 5 | * Base path for HTTP requests to indicate RSC requests. 6 | * Defaults to "RSC". 7 | */ 8 | rscBase: 'RSC', // Just for clarification in tests 9 | }); 10 | -------------------------------------------------------------------------------- /packages/waku/tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "..", 5 | "outDir": "./dist", 6 | "lib": ["esnext"] 7 | }, 8 | "include": ["."], 9 | "references": [ 10 | { 11 | "path": ".." 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monorepo", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/*" 6 | ], 7 | "dependencies": { 8 | "react": "19.2.3", 9 | "react-dom": "19.2.3", 10 | "react-server-dom-webpack": "19.2.3", 11 | "waku": "latest" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/DeeplyNestedLayout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export const DeeplyNestedLayout = ({ children }: { children: ReactNode }) => { 4 | return ( 5 |
6 |

Deeply Nested Layout

7 | {children} 8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/ServerThrows/index.tsx: -------------------------------------------------------------------------------- 1 | import { throws } from '../funcs.js'; 2 | import { Counter } from './Counter.js'; 3 | 4 | export function ServerThrows() { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /e2e/fixtures/custom-library-adapter/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 |

Hello from custom adapter

5 |
6 | ); 7 | } 8 | 9 | export const getConfig = async () => ({ render: 'static' as const }); 10 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/hello-server.tsx: -------------------------------------------------------------------------------- 1 | import { HelloClient } from '../components/hello-client.js'; 2 | 3 | export default async function HelloServer() { 4 | return ; 5 | } 6 | 7 | export const getConfig = () => { 8 | return { 9 | render: 'dynamic', 10 | } as const; 11 | }; 12 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-redirect/src/pages/destination.tsx: -------------------------------------------------------------------------------- 1 | export default async function DestinationPage() { 2 | return ( 3 |
4 |

Destination Page

5 |
6 | ); 7 | } 8 | 9 | export const getConfig = async () => { 10 | return { 11 | render: 'static', 12 | } as const; 13 | }; 14 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-target-bundle/src/components/Textarea.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import TextareaAutosize from 'react-textarea-autosize'; 3 | 4 | export const Textarea = () => { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/DeeplyNestedLayout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export const DeeplyNestedLayout = ({ children }: { children: ReactNode }) => { 4 | return ( 5 |
6 |

Deeply Nested Layout

7 | {children} 8 |
9 | ); 10 | }; 11 | -------------------------------------------------------------------------------- /examples/43_weave-render/src/components/FooLayout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | const FooLayout = ({ children }: { children: ReactNode }) => { 4 | return ( 5 |
6 |

FOO layout

7 | {children} 8 |
9 | ); 10 | }; 11 | 12 | export default FooLayout; 13 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/nested/_layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | const NestedLayout = ({ children }: { children: ReactNode }) => { 4 | return ( 5 |
6 |

Nested Layout

7 | {children} 8 |
9 | ); 10 | }; 11 | 12 | export default NestedLayout; 13 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/src/pages/css-modules-client.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import styles from './css-modules-client.module.css'; 4 | 5 | export default function CssModulesClient() { 6 | return ( 7 |
8 | Hello 9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /e2e/fixtures/styled-components/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from '../components/Counter'; 2 | 3 | export default function HomePage() { 4 | return ( 5 |
6 | Waku - styled-components 7 |

styled-components Example

8 | 9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/nested/_layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | const NestedLayout = ({ children }: { children: ReactNode }) => { 4 | return ( 5 |
6 |

Nested Layout

7 | {children} 8 |
9 | ); 10 | }; 11 | 12 | export default NestedLayout; 13 | -------------------------------------------------------------------------------- /examples/52_tanstack-router/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { App } from './app'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | ); 10 | 11 | createRoot(document as any).render(rootElement); 12 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/NestedLayout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | const NestedLayout = ({ children }: { children: ReactNode }) => { 4 | return ( 5 |
6 |

Nested Layout

7 | {children} 8 |
9 | ); 10 | }; 11 | 12 | export default NestedLayout; 13 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/NestedLayout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | const NestedLayout = ({ children }: { children: ReactNode }) => { 4 | return ( 5 |
6 |

Nested Layout

7 | {children} 8 |
9 | ); 10 | }; 11 | 12 | export default NestedLayout; 13 | -------------------------------------------------------------------------------- /examples/51_spa/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import App from './components/App'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | ); 10 | 11 | createRoot(document as any).render(rootElement); 12 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/Root.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export default function Root({ children }: { children: ReactNode }) { 4 | return ( 5 | 6 | 7 | Waku 8 | 9 | {children} 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/SlicePage.tsx: -------------------------------------------------------------------------------- 1 | import { Slice } from 'waku/router/client'; 2 | 3 | export default function SlicePage() { 4 | return ( 5 |
6 |

Slice Page

7 | 8 | 9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /examples/22_define-router/src/components/Root.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export default function Root({ children }: { children: ReactNode }) { 4 | return ( 5 | 6 | 7 | Waku 8 | 9 | {children} 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { Router } from 'waku/router/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | ); 10 | 11 | createRoot(document as any).render(rootElement); 12 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/functions/say-hello.tsx: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | import { SayHello } from '../components/say-hello.js'; 4 | 5 | export async function sayHello() { 6 | const promise = new Promise((resolve) => 7 | setTimeout(() => resolve('React'), 1000), 8 | ); 9 | return ; 10 | } 11 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/bar.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from './_components/Counter.js'; 2 | 3 | const Bar = () => ( 4 |
5 |

Bar

6 | 7 |
8 | ); 9 | 10 | export const getConfig = () => { 11 | return { 12 | render: 'dynamic', 13 | } as const; 14 | }; 15 | 16 | export default Bar; 17 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-catch-error/src/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { fsRouter } from 'waku'; 2 | import adapter from 'waku/adapters/default'; 3 | import validatorMiddleware from './middleware/validator'; 4 | 5 | export default adapter( 6 | fsRouter(import.meta.glob('./**/*.tsx', { base: './pages' })), 7 | { middlewareFns: [validatorMiddleware] }, 8 | ); 9 | -------------------------------------------------------------------------------- /e2e/fixtures/styled-components/src/pages/_layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | import { StyledComponentsRegistry } from '../components/StyledComponentsRegistry'; 3 | 4 | export default function RootLayout({ children }: { children: ReactNode }) { 5 | return {children}; 6 | } 7 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/bar.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from './_components/Counter'; 2 | 3 | const Bar = () => ( 4 |
5 |

Bar

6 | 7 |
8 | ); 9 | 10 | export const getConfig = () => { 11 | return { 12 | render: 'dynamic', 13 | } as const; 14 | }; 15 | 16 | export default Bar; 17 | -------------------------------------------------------------------------------- /e2e/fixtures/custom-user-adapter/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | export default function Page() { 2 | return ( 3 |
4 |

5 | Hello from custom user adapter 6 |

7 |
8 | ); 9 | } 10 | 11 | export const getConfig = async () => ({ render: 'static' as const }); 12 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/foo/index.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from '../_components/Counter'; 2 | 3 | const Foo = () => ( 4 |
5 |

Foo

6 | 7 |
8 | ); 9 | 10 | export const getConfig = () => { 11 | return { 12 | render: 'dynamic', 13 | } as const; 14 | }; 15 | 16 | export default Foo; 17 | -------------------------------------------------------------------------------- /examples/51_spa/src/functions/greet.tsx: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | export async function greet() { 4 | const now = new Date().toISOString(); 5 | console.log('greet', now); 6 | return ( 7 |
8 |

Hello from server ({now})

9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /packages/waku/src/router/server.ts: -------------------------------------------------------------------------------- 1 | export { 2 | unstable_defineRouter, 3 | unstable_getRscPath, 4 | unstable_getRscParams, 5 | unstable_rerenderRoute, 6 | unstable_notFound, 7 | unstable_redirect, 8 | } from './define-router.js'; 9 | export { createPages } from './create-pages.js'; 10 | export { fsRouter } from './fs-router.js'; 11 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/foo/index.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from '../_components/Counter.js'; 2 | 3 | const Foo = () => ( 4 |
5 |

Foo

6 | 7 |
8 | ); 9 | 10 | export const getConfig = () => { 11 | return { 12 | render: 'dynamic', 13 | } as const; 14 | }; 15 | 16 | export default Foo; 17 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/context-library/src/context-provider.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { createContext, createElement } from 'react'; 4 | 5 | export const Context = createContext('original'); 6 | 7 | export const ContextProvider = ({ children }) => { 8 | return createElement(Context, { value: 'provider value' }, children); 9 | }; 10 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/components/footer.module.css: -------------------------------------------------------------------------------- 1 | .footer { 2 | padding: 1.5rem; 3 | } 4 | 5 | @media (min-width: 1024px) { 6 | .footer { 7 | position: fixed; 8 | bottom: 0px; 9 | left: 0px; 10 | } 11 | } 12 | 13 | .a { 14 | margin-top: 1rem; 15 | display: inline-block; 16 | text-decoration-line: underline; 17 | } 18 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/debug.tsx: -------------------------------------------------------------------------------- 1 | import { getRouterConfigs } from '../waku.server.js'; 2 | 3 | export default async function Debug() { 4 | const configs = await getRouterConfigs(); 5 | return ( 6 |
7 |

Route inspection

8 |
{JSON.stringify(configs, null, 2)}
9 |
10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "allowJs": true 6 | }, 7 | "include": [ 8 | "eslint.config.ts", 9 | "packages/", 10 | "examples/", 11 | "e2e/", 12 | "playwright.config.ts" 13 | ], 14 | "exclude": ["**/node_modules", "**/dist"] 15 | } 16 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/src/build/dynamic.tsx: -------------------------------------------------------------------------------- 1 | export default async function Dynamic() { 2 | return ( 3 |
4 | [dynamic] 5 |
6 | phase = 7 | 8 | {String((globalThis as any).__WAKU_IS_BUILD__ === true)} 9 | 10 |
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/src/components/test-client.tsx: -------------------------------------------------------------------------------- 1 | // https://github.com/wakujs/waku/pull/1539 2 | 3 | 'use client'; 4 | 5 | import { use } from 'react'; 6 | 7 | const promise = Promise.resolve('test'); 8 | 9 | export function TestClient() { 10 | const data = use(promise); 11 | return
{data}
; 12 | } 13 | -------------------------------------------------------------------------------- /e2e/fixtures/wildcard-api-routes/src/pages/_root.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | export default function Root({ children }: { children: ReactNode }) { 4 | return ( 5 | 6 | 7 | Wildcard API Routes 8 | 9 | {children} 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { fsRouter } from 'waku'; 2 | import adapter from 'waku/adapters/default'; 3 | 4 | const router = fsRouter( 5 | import.meta.glob('./**/*.{tsx,ts}', { base: './pages' }), 6 | ); 7 | 8 | export const getRouterConfigs = () => router.unstable_getRouterConfigs(); 9 | 10 | export default adapter(router); 11 | -------------------------------------------------------------------------------- /packages/website/src/lib/shiki.ts: -------------------------------------------------------------------------------- 1 | import { createHighlighter } from 'shiki'; 2 | import theme from '../theme.json'; 3 | 4 | const highlighter = createHighlighter({ 5 | langs: ['tsx'], 6 | themes: [theme as any], 7 | }); 8 | 9 | export const codeToHtml = async (code: string, options: any) => 10 | (await highlighter).codeToHtml(code, options); 11 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/src/components/counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | 5 | export const Counter = () => { 6 | const [count, setCount] = useState(0); 7 | 8 | return ( 9 | 12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/src/build/static.tsx: -------------------------------------------------------------------------------- 1 | export default async function Static() { 2 | return ( 3 |
4 | [static] 5 |
6 | phase ={' '} 7 | 8 | {String((globalThis as any).__WAKU_IS_BUILD__ === true)} 9 | 10 |
11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-target-bundle/README.md: -------------------------------------------------------------------------------- 1 | # SSR Bundling for NPM packages with environment depended code parts 2 | 3 | Choosing the right code based on the `export` section of the `react-textarea-autosize` module based on the backend server deployment target ('node' | 'webworker') and the client browser. No browser only code should be bundled with server only code. 4 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | import styles from './header.module.css'; 3 | 4 | export const Header = () => { 5 | return ( 6 |
7 |

8 | Waku starter 9 |

10 |
11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /examples/04_cssmodules/waku.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'waku/config'; 3 | 4 | export default defineConfig({ 5 | vite: { 6 | plugins: [ 7 | react({ 8 | babel: { 9 | plugins: ['babel-plugin-react-compiler'], 10 | }, 11 | }), 12 | ], 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /packages/waku/.swcrc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://swc.rs/schema.json", 3 | "jsc": { 4 | "parser": { 5 | "syntax": "typescript" 6 | }, 7 | "transform": { 8 | "react": { 9 | "runtime": "automatic" 10 | } 11 | }, 12 | "target": "esnext" 13 | }, 14 | "sourceMaps": true, 15 | "exclude": [".*\\.d\\.ts$"] 16 | } 17 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/src/components/hydrated.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useSyncExternalStore } from 'react'; 4 | 5 | const noop = () => () => {}; 6 | 7 | export const Hydrated = () => { 8 | const ok = useSyncExternalStore( 9 | noop, 10 | () => true, 11 | () => false, 12 | ); 13 | return
Hydrated: {String(ok)}
; 14 | }; 15 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/src/components/ErrorBoundary.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { 4 | type ErrorBoundaryProps, 5 | ErrorBoundary as ReactErrorBoundary, 6 | } from 'react-error-boundary'; 7 | 8 | const ErrorBoundary = (props: ErrorBoundaryProps) => { 9 | return ; 10 | }; 11 | 12 | export default ErrorBoundary; 13 | -------------------------------------------------------------------------------- /e2e/fixtures/custom-library-adapter/modules/custom-adapter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "custom-waku-adapter", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "exports": { 7 | ".": "./src/index.js", 8 | "./build-enhancer": "./src/build-enhancer.js" 9 | }, 10 | "peerDependencies": { 11 | "waku": "*" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/dummy-library/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dummy-library", 3 | "type": "module", 4 | "version": "0.0.0", 5 | "description": "Dummy package for testing", 6 | "exports": { 7 | "./entry-point": { 8 | "types": "./src/index.d.ts", 9 | "import": "./src/index.js" 10 | } 11 | }, 12 | "private": true 13 | } 14 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/_slices/one.tsx: -------------------------------------------------------------------------------- 1 | export default function SliceOne() { 2 | return ( 3 |
4 |

5 | Slice One {new Date().toLocaleString()} 6 |

7 |
8 | ); 9 | } 10 | 11 | export const getConfig = () => { 12 | return { 13 | render: 'static', 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/_slices/two.tsx: -------------------------------------------------------------------------------- 1 | export default function SliceTwo() { 2 | return ( 3 |
4 |

5 | Slice Two {new Date().toLocaleString()} 6 |

7 |
8 | ); 9 | } 10 | 11 | export const getConfig = () => { 12 | return { 13 | render: 'dynamic', 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/src/components/ServerThrows/index.tsx: -------------------------------------------------------------------------------- 1 | import { ServerBox } from '../Box.js'; 2 | import { throws } from './actions.js'; 3 | import { Counter } from './Counter.js'; 4 | 5 | export function ServerThrows() { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /e2e/fixtures/wildcard-api-routes/src/pages/[...wildcard].tsx: -------------------------------------------------------------------------------- 1 | const Page = ({ wildcard }: { wildcard: string[] }) => ( 2 |
3 |

/{wildcard.join('/')}

4 |

Catch All Pages Route

5 |
6 | ); 7 | 8 | export const getConfig = async () => { 9 | return { 10 | render: 'dynamic', 11 | }; 12 | }; 13 | 14 | export default Page; 15 | -------------------------------------------------------------------------------- /examples/12_nossr/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export const Header = () => { 4 | return ( 5 |
6 |

7 | Waku starter 8 |

9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/nested/[name].tsx: -------------------------------------------------------------------------------- 1 | import type { PageProps } from 'waku/router'; 2 | 3 | const Page = ({ name }: PageProps<'/nested/[name]'>) => ( 4 |
5 |

Nested / {name}

6 |
7 | ); 8 | 9 | export const getConfig = () => { 10 | return { 11 | render: 'dynamic', 12 | } as const; 13 | }; 14 | 15 | export default Page; 16 | -------------------------------------------------------------------------------- /e2e/fixtures/ssg-wildcard/src/pages/[...wildcard].tsx: -------------------------------------------------------------------------------- 1 | const Page = ({ wildcard }: { wildcard: string[] }) => ( 2 |
3 |

/{wildcard.join('/')}

4 |
5 | ); 6 | 7 | export const getConfig = async () => { 8 | return { 9 | render: 'static', 10 | staticPaths: [[], 'foo', ['bar', 'baz']], 11 | }; 12 | }; 13 | 14 | export default Page; 15 | -------------------------------------------------------------------------------- /examples/01_template/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export const Header = () => { 4 | return ( 5 |
6 |

7 | Waku starter 8 |

9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /examples/02_template_js/src/components/header.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export const Header = () => { 4 | return ( 5 |
6 |

7 | Waku starter 8 |

9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /examples/07_cloudflare/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export const Header = () => { 4 | return ( 5 |
6 |

7 | Waku starter 8 |

9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /examples/08_jotai-demo/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export const Header = () => { 4 | return ( 5 |
6 |

7 | Waku starter 8 |

9 |
10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/nested/[name].tsx: -------------------------------------------------------------------------------- 1 | import type { PageProps } from 'waku/router'; 2 | 3 | const Page = ({ name }: PageProps<'/nested/[name]'>) => ( 4 |
5 |

Nested / {name}

6 |
7 | ); 8 | 9 | export const getConfig = () => { 10 | return { 11 | render: 'dynamic', 12 | } as const; 13 | }; 14 | 15 | export default Page; 16 | -------------------------------------------------------------------------------- /packages/website/waku.config.ts: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite'; 2 | import { defineConfig } from 'waku/config'; 3 | 4 | export default defineConfig({ 5 | vite: { 6 | plugins: [tailwindcss()], 7 | environments: { 8 | rsc: { 9 | resolve: { 10 | external: ['shiki'], 11 | }, 12 | }, 13 | }, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/src/components/ServerAction/Server.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | import { createAI } from 'ai/rsc'; 3 | 4 | const AI = createAI({ 5 | foo: async () => { 6 | 'use server'; 7 | return 0; 8 | }, 9 | }); 10 | 11 | export function ServerProvider({ children }: { children: ReactNode }) { 12 | return {children}; 13 | } 14 | -------------------------------------------------------------------------------- /examples/42_react-tweet/waku.config.ts: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite'; 2 | import { defineConfig } from 'waku/config'; 3 | 4 | export default defineConfig({ 5 | vite: { 6 | plugins: [tailwindcss()], 7 | optimizeDeps: { 8 | // https://github.com/vitejs/vite-plugin-react/issues/759 9 | exclude: ['react-tweet'], 10 | }, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from '../components/counter'; 2 | 3 | export default async function HomePage() { 4 | return ( 5 |
6 |

Home page

7 | 8 |
renderd at {new Date().toISOString()}
9 |
argv: {JSON.stringify(process.argv.slice(2))}
10 |
11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-asset/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | createRoot(document as any).render(rootElement); 14 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | createRoot(document as any).render(rootElement); 14 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-redirect/src/pages/sync.tsx: -------------------------------------------------------------------------------- 1 | import { unstable_redirect as redirect } from 'waku/router/server'; 2 | 3 | export default async function SyncPage() { 4 | await new Promise((resolve) => setTimeout(resolve, 100)); 5 | redirect('/destination'); 6 | } 7 | 8 | export const getConfig = async () => { 9 | return { 10 | render: 'dynamic', 11 | } as const; 12 | }; 13 | -------------------------------------------------------------------------------- /e2e/fixtures/broken-links/src/pages/dynamic-not-found/sync.tsx: -------------------------------------------------------------------------------- 1 | import { unstable_notFound as notFound } from 'waku/router/server'; 2 | 3 | export default async function SyncPage() { 4 | await new Promise((resolve) => setTimeout(resolve, 100)); 5 | notFound(); 6 | } 7 | 8 | export const getConfig = async () => { 9 | return { 10 | render: 'dynamic', 11 | } as const; 12 | }; 13 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-css-modules/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | createRoot(document as any).render(rootElement); 14 | -------------------------------------------------------------------------------- /e2e/fixtures/broken-links/src/pages/exists.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export default function Exists() { 4 | return ( 5 |
6 |

Existing page

7 |

8 | Back 9 |

10 |
11 | ); 12 | } 13 | 14 | export const getConfig = async () => { 15 | return { 16 | render: 'static', 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-context-provider/src/components/context-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { createContext } from 'react'; 4 | import type { ReactNode } from 'react'; 5 | 6 | export const Context = createContext('original'); 7 | 8 | export const ContextProvider = ({ children }: { children: ReactNode }) => { 9 | return {children}; 10 | }; 11 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-redirect/src/pages/async/index.tsx: -------------------------------------------------------------------------------- 1 | import { unstable_redirect as redirect } from 'waku/router/server'; 2 | 3 | export default async function AsyncPage() { 4 | await new Promise((resolve) => setTimeout(resolve, 100)); 5 | redirect('/destination'); 6 | } 7 | 8 | export const getConfig = async () => { 9 | return { 10 | render: 'dynamic', 11 | } as const; 12 | }; 13 | -------------------------------------------------------------------------------- /e2e/fixtures/broken-links/src/pages/dynamic-not-found/async/index.tsx: -------------------------------------------------------------------------------- 1 | import { unstable_notFound as notFound } from 'waku/router/server'; 2 | 3 | export default async function AsyncPage() { 4 | await new Promise((resolve) => setTimeout(resolve, 100)); 5 | notFound(); 6 | } 7 | 8 | export const getConfig = async () => { 9 | return { 10 | render: 'dynamic', 11 | } as const; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/38_cookies/private/items.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "id": 1, "name": "John" }, 3 | { "id": 2, "name": "Jane" }, 4 | { "id": 3, "name": "Bob" }, 5 | { "id": 4, "name": "Mary" }, 6 | { "id": 5, "name": "Peter" }, 7 | { "id": 6, "name": "Kate" }, 8 | { "id": 7, "name": "Mike" }, 9 | { "id": 8, "name": "Liz" }, 10 | { "id": 9, "name": "Steve" }, 11 | { "id": 10, "name": "Sue" } 12 | ] 13 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/src/components/ServerPing/index.tsx: -------------------------------------------------------------------------------- 1 | import { ServerBox } from '../Box.js'; 2 | import { increase, ping, wrap } from './actions.js'; 3 | import { Counter } from './Counter.js'; 4 | 5 | export function ServerPing() { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /examples/51_spa/src/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import adapter from 'waku/adapters/default'; 2 | 3 | export default adapter({ 4 | handleRequest: async (input, { renderRsc }) => { 5 | if (input.type === 'function') { 6 | const value = await input.fn(...input.args); 7 | return renderRsc({ _value: value }); 8 | } 9 | return 'fallback'; 10 | }, 11 | handleBuild: async () => {}, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/waku/src/lib/utils/create-pages.ts: -------------------------------------------------------------------------------- 1 | /** Remove (group)s from path. Like /(group)/foo => /foo */ 2 | export const getGrouplessPath = (path: string) => { 3 | if (path.includes('(')) { 4 | const withoutGroups = path 5 | .split('/') 6 | .filter((part) => !part.startsWith('(')); 7 | path = withoutGroups.length > 1 ? withoutGroups.join('/') : '/'; 8 | } 9 | return path; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/website/src/components/code.tsx: -------------------------------------------------------------------------------- 1 | import { codeToHtml } from '../lib/shiki'; 2 | 3 | type CodeProps = { 4 | code: string; 5 | }; 6 | 7 | export const Code = async ({ code, ...rest }: CodeProps) => { 8 | const html = await codeToHtml(code.trim(), { 9 | lang: 'tsx', 10 | theme: 'lucy', 11 | }); 12 | 13 | return
; 14 | }; 15 | -------------------------------------------------------------------------------- /e2e/fixtures/tailwindcss/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { TestClient } from '../components/client'; 2 | 3 | export default async function HomePage() { 4 | return ( 5 |
6 | 7 | 8 |
9 | ); 10 | } 11 | 12 | function TestServer() { 13 | return ( 14 |
test-server
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/_slices/one.tsx: -------------------------------------------------------------------------------- 1 | export default function Slice001() { 2 | // TODO is there a more reasonable way? 3 | // eslint-disable-next-line react-hooks/purity 4 | const rand = Math.random(); 5 | return

Slice 001 ({rand})

; 6 | } 7 | 8 | export const getConfig = () => { 9 | return { 10 | render: 'dynamic', 11 | id: 'slice001', 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/waku-project/src/components/header.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export const Header = () => { 4 | return ( 5 |
8 |

9 | Waku starter 10 |

11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /examples/37_css-vanilla-extract/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from '../components/counter'; 2 | import { serverStyle } from '../server.css'; 3 | 4 | export default async function HomePage() { 5 | return ( 6 |
7 | Waku 8 |
Server Style (green)
9 |
10 | 11 |
12 |
13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /examples/52_tanstack-router/src/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import adapter from 'waku/adapters/default'; 2 | 3 | export default adapter({ 4 | handleRequest: async (input, { renderRsc }) => { 5 | if (input.type === 'function') { 6 | const value = await input.fn(...input.args); 7 | return renderRsc({ _value: value }); 8 | } 9 | return 'fallback'; 10 | }, 11 | handleBuild: async () => {}, 12 | }); 13 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/src/pages/dynamic.tsx: -------------------------------------------------------------------------------- 1 | export default function DyanmicPage() { 2 | return ( 3 |
4 |

Dynamic page

5 |
renderd at {new Date().toISOString()}
6 |
argv: {JSON.stringify(process.argv.slice(2))}
7 |
8 | ); 9 | } 10 | 11 | export const getConfig = async () => { 12 | return { 13 | render: 'dynamic', 14 | } as const; 15 | }; 16 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/src/pages/about.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export default async function AboutPage() { 4 | return ( 5 |
6 |

About Page

7 | 8 | Return home 9 | 10 |
11 | ); 12 | } 13 | 14 | export const getConfig = async () => { 15 | return { 16 | render: 'static', 17 | } as const; 18 | }; 19 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/pages/_layout.module.css: -------------------------------------------------------------------------------- 1 | .div { 2 | font-family: 'Nunito'; 3 | } 4 | 5 | .main { 6 | margin: 1.5rem; 7 | display: flex; 8 | align-items: center; 9 | } 10 | 11 | .main > * { 12 | min-height: 16rem; 13 | min-width: 16rem; 14 | } 15 | 16 | @media (min-width: 1024px) { 17 | .main { 18 | margin: 0px; 19 | min-height: 100svh; 20 | justify-content: center; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/07_cloudflare/src/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { contextStorage } from 'hono/context-storage'; 2 | import { fsRouter } from 'waku'; 3 | import adapter from 'waku/adapters/cloudflare'; 4 | import cloudflareMiddleware from './middleware/cloudflare'; 5 | 6 | export default adapter( 7 | fsRouter(import.meta.glob('./**/*.tsx', { base: './pages' })), 8 | { middlewareFns: [contextStorage, cloudflareMiddleware] }, 9 | ); 10 | -------------------------------------------------------------------------------- /packages/website/src/lib/load-docs.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from 'node:fs'; 2 | 3 | export const loadReadme = (): string => { 4 | const content = readFileSync('../../README.md', 'utf8'); 5 | return content.replace(/\r\n?/g, '\n'); 6 | }; 7 | 8 | export const loadCreatePages = (): string => { 9 | const file = readFileSync('../../docs/create-pages.mdx', 'utf8'); 10 | return file.replace(/\r\n?/g, '\n'); 11 | }; 12 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-redirect/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export default async function HomePage() { 4 | return ( 5 |
6 |

Home Page

7 | Sync Page 8 | Async Page 9 |
10 | ); 11 | } 12 | 13 | export const getConfig = async () => { 14 | return { 15 | render: 'static', 16 | } as const; 17 | }; 18 | -------------------------------------------------------------------------------- /examples/03_demo/waku.config.ts: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite'; 2 | import react from '@vitejs/plugin-react'; 3 | import { defineConfig } from 'waku/config'; 4 | 5 | export default defineConfig({ 6 | vite: { 7 | plugins: [ 8 | tailwindcss(), 9 | react({ 10 | babel: { 11 | plugins: ['babel-plugin-react-compiler'], 12 | }, 13 | }), 14 | ], 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/slice-page.tsx: -------------------------------------------------------------------------------- 1 | import { Slice } from 'waku/router/client'; 2 | 3 | export default function SlicePage() { 4 | return ( 5 |
6 |

Slice Page

7 | 8 | 9 |
10 | ); 11 | } 12 | 13 | export const getConfig = () => { 14 | return { 15 | render: 'dynamic', 16 | slices: ['one', 'two'], 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/components/funcs.ts: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | import { unstable_rerenderRoute } from 'waku/router/server'; 4 | 5 | const PAGES = ['/bar', '/baz', '/nested/qux', '/nested/aaa', '/nested/bbb']; 6 | 7 | export const jump = async () => { 8 | const page = PAGES[Math.floor(Math.random() * PAGES.length)] as string; 9 | console.log(`Jumping to ${page}`); 10 | unstable_rerenderRoute(page); 11 | }; 12 | -------------------------------------------------------------------------------- /examples/37_css-vanilla-extract/src/components/counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | import { clientStyle } from '../client.css'; 5 | 6 | export const Counter = () => { 7 | const [count, setCount] = useState(0); 8 | 9 | return ( 10 | 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/01_template/waku.config.ts: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite'; 2 | import react from '@vitejs/plugin-react'; 3 | import { defineConfig } from 'waku/config'; 4 | 5 | export default defineConfig({ 6 | vite: { 7 | plugins: [ 8 | tailwindcss(), 9 | react({ 10 | babel: { 11 | plugins: ['babel-plugin-react-compiler'], 12 | }, 13 | }), 14 | ], 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /examples/02_template_js/waku.config.js: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite'; 2 | import react from '@vitejs/plugin-react'; 3 | import { defineConfig } from 'waku/config'; 4 | 5 | export default defineConfig({ 6 | vite: { 7 | plugins: [ 8 | tailwindcss(), 9 | react({ 10 | babel: { 11 | plugins: ['babel-plugin-react-compiler'], 12 | }, 13 | }), 14 | ], 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/components/header.module.css: -------------------------------------------------------------------------------- 1 | .header { 2 | display: flex; 3 | align-items: center; 4 | gap: 1rem; 5 | padding: 1.5rem; 6 | } 7 | 8 | @media (min-width: 1024px) { 9 | .header { 10 | position: fixed; 11 | left: 0px; 12 | top: 0px; 13 | } 14 | } 15 | 16 | .h2 { 17 | font-size: 1.125rem; 18 | line-height: 1.75rem; 19 | font-weight: 700; 20 | letter-spacing: -0.025em; 21 | } 22 | -------------------------------------------------------------------------------- /examples/06_form-demo/waku.config.ts: -------------------------------------------------------------------------------- 1 | import tailwindcss from '@tailwindcss/vite'; 2 | import react from '@vitejs/plugin-react'; 3 | import { defineConfig } from 'waku/config'; 4 | 5 | export default defineConfig({ 6 | vite: { 7 | plugins: [ 8 | tailwindcss(), 9 | react({ 10 | babel: { 11 | plugins: ['babel-plugin-react-compiler'], 12 | }, 13 | }), 14 | ], 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /packages/waku/tests/fixtures/plugin-fs-router-typegen-with-createpages/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { createPages } from 'waku'; 2 | import adapter from 'waku/adapters/default'; 3 | import HomePage from './pages/index.js'; 4 | 5 | const pages = createPages(async ({ createPage }) => [ 6 | createPage({ 7 | render: 'static', 8 | path: '/', 9 | component: HomePage, 10 | }), 11 | ]); 12 | 13 | export default adapter(pages); 14 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/context-library/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "context-library", 3 | "type": "module", 4 | "version": "0.0.0", 5 | "description": "A library with React Context", 6 | "exports": { 7 | "./entry-point": { 8 | "types": "./src/index.d.ts", 9 | "import": "./src/index.js" 10 | } 11 | }, 12 | "private": true, 13 | "peerDependencies": { 14 | "react": ">=18.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /e2e/fixtures/partial-build/src/pages/_root.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from 'react'; 2 | 3 | export default function Root({ children }: { children: ReactNode }) { 4 | return ( 5 | 6 | 7 | Waku 8 | 9 | {children} 10 | 11 | ); 12 | } 13 | 14 | export const getConfig = async () => { 15 | return { 16 | render: 'static', 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/src/components/ServerAction/Client.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useEffect } from 'react'; 4 | import { useActions } from 'ai/rsc'; 5 | 6 | export const ClientActionsConsumer = () => { 7 | const actions = useActions(); 8 | useEffect(() => { 9 | (globalThis as any).actions = actions; 10 | }, [actions]); 11 | return
globalThis.actions: {JSON.stringify(Object.keys(actions))}
; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/32_minimal_js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "32_minimal_js", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/src/pages/css-modules.tsx: -------------------------------------------------------------------------------- 1 | import styles from './css-modules.module.css'; 2 | 3 | export default async function CssModules() { 4 | return ( 5 |
6 |

7 | CSS Modules 8 |

9 |
10 | ); 11 | } 12 | 13 | export const getConfig = async () => { 14 | return { 15 | render: 'static', 16 | } as const; 17 | }; 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-redirect/src/pages/async/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | import type { ReactNode } from 'react'; 3 | 4 | export default async function AsyncLayout({ 5 | children, 6 | }: { 7 | children: ReactNode; 8 | }) { 9 | return {children}; 10 | } 11 | 12 | export const getConfig = async () => { 13 | return { 14 | render: 'static', 15 | } as const; 16 | }; 17 | -------------------------------------------------------------------------------- /e2e/fixtures/use-router/src/pages/static.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | import TestRouter from '../TestRouter.js'; 3 | 4 | const Page = () => ( 5 | <> 6 |

Static

7 |

8 | Go to dynamic 9 |

10 | 11 | 12 | ); 13 | 14 | export const getConfig = async () => { 15 | return { 16 | render: 'static', 17 | }; 18 | }; 19 | 20 | export default Page; 21 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | const Home = () => { 2 | // TODO is there a more reasonable way? 3 | // eslint-disable-next-line react-hooks/purity 4 | const now = Date.now(); 5 | return ( 6 |
7 |

Home

8 |

now: {now}

9 |
10 | ); 11 | }; 12 | 13 | export const getConfig = () => { 14 | return { 15 | render: 'dynamic', 16 | } as const; 17 | }; 18 | 19 | export default Home; 20 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/src/root.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | 3 | export default function Root() { 4 | return ( 5 |
    6 |
  • 7 | Build static 8 |
  • 9 |
  • 10 | Build dynamic 11 |
  • 12 |
  • 13 | /server/static 14 |
  • 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /examples/36_form/src/components/funcs.ts: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | import { rerender } from '../als'; 4 | 5 | // module state on server 6 | let message = ''; 7 | 8 | export const getMessage = async () => message; 9 | 10 | export const greet = async (formData: FormData) => { 11 | message = `Hello ${formData.get('name') || 'Anonymous'} from server!`; 12 | rerender(''); 13 | }; 14 | 15 | export const increment = async (count: number) => count + 1; 16 | -------------------------------------------------------------------------------- /packages/create-waku/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "ESNext", 5 | "rootDir": "./src", 6 | "outDir": "./dist", 7 | "lib": ["esnext"], 8 | "emitDeclarationOnly": false, 9 | "moduleResolution": "bundler" 10 | }, 11 | "include": ["./src"], 12 | "exclude": ["./template"], 13 | "references": [ 14 | { 15 | "path": "../waku" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /e2e/fixtures/broken-links/src/pages/dynamic-not-found/async/_layout.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | import type { ReactNode } from 'react'; 3 | 4 | export default async function AsyncLayout({ 5 | children, 6 | }: { 7 | children: ReactNode; 8 | }) { 9 | return {children}; 10 | } 11 | 12 | export const getConfig = async () => { 13 | return { 14 | render: 'static', 15 | } as const; 16 | }; 17 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/src/components/test-app.tsx: -------------------------------------------------------------------------------- 1 | // https://github.com/wakujs/waku/pull/1539 2 | 3 | import { TestClient } from './test-client.js'; 4 | 5 | const TestApp = () => { 6 | return ( 7 | 8 | 9 | Waku 10 | 11 | 12 |
13 | 14 |
15 | 16 | 17 | ); 18 | }; 19 | 20 | export default TestApp; 21 | -------------------------------------------------------------------------------- /examples/34_functions/src/components2/funcs2.ts: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | import { unstable_getContext as getContext } from 'waku/server'; 4 | 5 | export const greet = async (name: string) => { 6 | await Promise.resolve(); 7 | return `Hello ${name} from server!`; 8 | }; 9 | 10 | export const hello = async (name: string) => { 11 | await Promise.resolve(); 12 | console.log('Context:', getContext()); 13 | console.log('Hello', name, '!'); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/waku/src/lib/vite-entries/entry.server.tsx: -------------------------------------------------------------------------------- 1 | import serverEntry from 'virtual:vite-rsc-waku/server-entry'; 2 | import { INTERNAL_setAllEnv } from '../../server.js'; 3 | 4 | export { serverEntry as unstable_serverEntry }; 5 | 6 | export async function INTERNAL_runFetch( 7 | env: Readonly>, 8 | req: Request, 9 | ...args: any[] 10 | ) { 11 | INTERNAL_setAllEnv(env); 12 | return serverEntry.fetch(req, ...args); 13 | } 14 | -------------------------------------------------------------------------------- /packages/website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "./dist", 6 | "module": "esnext", 7 | "moduleResolution": "bundler", 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "types": ["node"] 11 | }, 12 | "include": ["src", "src/theme.json"], 13 | "references": [ 14 | { 15 | "path": "../waku" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Router } from 'waku/router/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | ); 10 | 11 | if ((globalThis as any).__WAKU_HYDRATE__) { 12 | hydrateRoot(document, rootElement); 13 | } else { 14 | createRoot(document as any).render(rootElement); 15 | } 16 | -------------------------------------------------------------------------------- /examples/21_create-pages/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Router } from 'waku/router/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | ); 10 | 11 | if ((globalThis as any).__WAKU_HYDRATE__) { 12 | hydrateRoot(document, rootElement); 13 | } else { 14 | createRoot(document as any).render(rootElement); 15 | } 16 | -------------------------------------------------------------------------------- /examples/34_functions/src/components2/funcs.ts: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | import { rerender } from '../als'; 4 | 5 | export const greet = async (name: string) => { 6 | await Promise.resolve(); 7 | return `Hello ${name} from server!`; 8 | }; 9 | 10 | // module state on server 11 | let counter = 0; 12 | 13 | export const getCounter = async () => counter; 14 | 15 | export const increment = async () => { 16 | counter += 1; 17 | rerender('Waku'); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/42_react-tweet/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Router } from 'waku/router/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | ); 10 | 11 | if ((globalThis as any).__WAKU_HYDRATE__) { 12 | hydrateRoot(document, rootElement); 13 | } else { 14 | createRoot(document as any).render(rootElement); 15 | } 16 | -------------------------------------------------------------------------------- /examples/43_weave-render/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Router } from 'waku/router/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | ); 10 | 11 | if ((globalThis as any).__WAKU_HYDRATE__) { 12 | hydrateRoot(document, rootElement); 13 | } else { 14 | createRoot(document as any).render(rootElement); 15 | } 16 | -------------------------------------------------------------------------------- /packages/website/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import slugify from '@sindresorhus/slugify'; 2 | 3 | export const getAnchor = (value: any) => { 4 | const isString = typeof value === 'string'; 5 | 6 | return isString ? slugify(value) : ''; 7 | }; 8 | 9 | export const scrollTo = (id: string) => { 10 | const element = document.getElementById(id); 11 | 12 | if (element) { 13 | element.scrollIntoView({ behavior: 'smooth', block: 'start' }); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/page-with-segment/(article)/[slug].tsx: -------------------------------------------------------------------------------- 1 | import type { PageProps } from 'waku/router'; 2 | 3 | // Create blog article pages 4 | export default async function BlogArticlePage({ 5 | slug, 6 | }: PageProps<'/page-with-segment/[slug]'>) { 7 | return

{slug}

; 8 | } 9 | 10 | export const getConfig = async () => { 11 | return { 12 | render: 'static', 13 | staticPaths: ['introducing-waku'], 14 | } as const; 15 | }; 16 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Router } from 'waku/router/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | ); 10 | 11 | if ((globalThis as any).__WAKU_HYDRATE__) { 12 | hydrateRoot(document.body, rootElement); 13 | } else { 14 | createRoot(document.body).render(rootElement); 15 | } 16 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/page-with-segment/article/[slug].tsx: -------------------------------------------------------------------------------- 1 | import type { PageProps } from 'waku/router'; 2 | 3 | // Create blog article pages 4 | export default async function BlogArticlePage({ 5 | slug, 6 | }: PageProps<'/page-with-segment/article/[slug]'>) { 7 | return

{slug}

; 8 | } 9 | 10 | export const getConfig = async () => { 11 | return { 12 | render: 'static', 13 | staticPaths: ['introducing-waku'], 14 | } as const; 15 | }; 16 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/subroute/[...catchAll].tsx: -------------------------------------------------------------------------------- 1 | import type { PageProps } from 'waku/router'; 2 | 3 | function SubrouteCatchAll({ catchAll }: PageProps<'/subroute/[...catchAll]'>) { 4 | return ( 5 |
6 |

Subroute Catch-All: {catchAll.join('/')}

7 |
8 | ); 9 | } 10 | 11 | export const getConfig = () => { 12 | return { 13 | render: 'dynamic', 14 | } as const; 15 | }; 16 | 17 | export default SubrouteCatchAll; 18 | -------------------------------------------------------------------------------- /examples/03_demo/src/components/reload.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | export const Reload = () => { 4 | const handleReload = () => { 5 | window.location.reload(); 6 | }; 7 | 8 | return ( 9 | 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /examples/36_form/src/als.ts: -------------------------------------------------------------------------------- 1 | import { AsyncLocalStorage } from 'node:async_hooks'; 2 | 3 | type Rerender = (rscPath: string) => void; 4 | 5 | const store = new AsyncLocalStorage(); 6 | 7 | export const runWithRerender = (rerender: Rerender, fn: () => T): T => { 8 | return store.run(rerender, fn); 9 | }; 10 | 11 | export const rerender = (rscPath: string) => { 12 | const fn = store.getStore(); 13 | if (fn) { 14 | fn(rscPath); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /examples/37_css/src/components/counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | 5 | export const Counter = () => { 6 | const [count, setCount] = useState(0); 7 | return ( 8 |
9 |

Count: {count}

10 | 11 |

This is a client component.

12 |
13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/pages/page-with-slices/index.tsx: -------------------------------------------------------------------------------- 1 | import { Slice } from 'waku/router/client'; 2 | 3 | const slices = ['slice001', 'two'] as const; 4 | 5 | export default function Slices() { 6 | return ( 7 | <> 8 |

Slices

9 | 10 | 11 | 12 | ); 13 | } 14 | 15 | export const getConfig = () => { 16 | return { 17 | render: 'dynamic', 18 | slices, 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /e2e/fixtures/waku-jotai-integration/src/pages/_layout.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | import { RouterProvider } from 'waku-jotai/router'; 3 | 4 | type RootLayoutProps = { children: ReactNode }; 5 | 6 | export default async function RootLayout({ children }: RootLayoutProps) { 7 | return {children}; 8 | } 9 | 10 | export const getConfig = async () => { 11 | return { 12 | render: 'dynamic', 13 | } as const; 14 | }; 15 | -------------------------------------------------------------------------------- /examples/31_minimal/src/components/Counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | 5 | export const Counter = () => { 6 | const [count, setCount] = useState(0); 7 | return ( 8 |
9 |

Count: {count}

10 | 11 |

This is a client component.

12 |
13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /examples/34_functions/src/als.ts: -------------------------------------------------------------------------------- 1 | import { AsyncLocalStorage } from 'node:async_hooks'; 2 | 3 | type Rerender = (rscPath: string) => void; 4 | 5 | const store = new AsyncLocalStorage(); 6 | 7 | export const runWithRerender = (rerender: Rerender, fn: () => T): T => { 8 | return store.run(rerender, fn); 9 | }; 10 | 11 | export const rerender = (rscPath: string) => { 12 | const fn = store.getStore(); 13 | if (fn) { 14 | fn(rscPath); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /examples/38_cookies/src/components/Counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | 5 | export const Counter = () => { 6 | const [count, setCount] = useState(0); 7 | return ( 8 |
9 |

Count: {count}

10 | 11 |

This is a client component.

12 |
13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-context-provider/src/components/app.tsx: -------------------------------------------------------------------------------- 1 | import { ContextConsumer } from './context-consumer.js'; 2 | import { ContextProvider } from './context-provider.js'; 3 | 4 | export default function App() { 5 | return ( 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 |
14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /examples/32_minimal_js/src/components/counter.jsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | 5 | export const Counter = () => { 6 | const [count, setCount] = useState(0); 7 | return ( 8 |
9 |

Count: {count}

10 | 11 |

This is a client component.

12 |
13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/src/routes/bar1/page.tsx: -------------------------------------------------------------------------------- 1 | import { Slice } from 'waku/router/client'; 2 | 3 | const Bar1 = () => { 4 | // TODO is there a more reasonable way? 5 | // eslint-disable-next-line react-hooks/purity 6 | const rand = Math.random(); 7 | return ( 8 |
9 |

Bar1

10 |

{rand}

11 | 12 |
13 | ); 14 | }; 15 | 16 | export default Bar1; 17 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/src/routes/bar2/page.tsx: -------------------------------------------------------------------------------- 1 | import { Slice } from 'waku/router/client'; 2 | 3 | const Bar2 = () => { 4 | // TODO is there a more reasonable way? 5 | // eslint-disable-next-line react-hooks/purity 6 | const rand = Math.random(); 7 | return ( 8 |
9 |

Bar2

10 |

{rand}

11 | 12 |
13 | ); 14 | }; 15 | 16 | export default Bar2; 17 | -------------------------------------------------------------------------------- /packages/create-waku/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig((options) => ({ 4 | entry: ['src/index.ts'], 5 | external: [/package\.json/], 6 | format: ['esm'], 7 | minify: !options.watch, 8 | clean: true, 9 | /** @see https://github.com/egoist/tsup/issues/927#issuecomment-2354939322 */ 10 | banner: { 11 | js: `import { createRequire } from 'module'; const require = createRequire(import.meta.url);`, 12 | }, 13 | })); 14 | -------------------------------------------------------------------------------- /packages/website/src/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import { fsRouter } from 'waku'; 2 | import nodeAdapter from 'waku/adapters/node'; 3 | import vercelAdapter from 'waku/adapters/vercel'; 4 | 5 | const adapter: typeof vercelAdapter = process.env.VERCEL 6 | ? vercelAdapter 7 | : nodeAdapter; 8 | 9 | const handler: ReturnType = adapter( 10 | fsRouter(import.meta.glob('./**/*.{tsx,ts}', { base: './pages' })), 11 | { static: true }, 12 | ); 13 | 14 | export default handler; 15 | -------------------------------------------------------------------------------- /examples/32_minimal_js/src/waku.client.jsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if (globalThis.__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /packages/waku/src/minimal/server.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Unstable_HandleBuild as HandleBuild, 3 | Unstable_HandleRequest as HandleRequest, 4 | Unstable_ServerEntry as ServerEntry, 5 | } from '../lib/types.js'; 6 | 7 | export function unstable_defineHandlers(handlers: { 8 | handleRequest: HandleRequest; 9 | handleBuild: HandleBuild; 10 | }) { 11 | return handlers; 12 | } 13 | 14 | export function unstable_defineServerEntry(fns: ServerEntry['default']) { 15 | return fns; 16 | } 17 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | import { Counter } from '../components/counter.js'; 3 | 4 | export default async function HomePage() { 5 | return ( 6 |
7 |

Home Page

8 | 9 | 10 | About 11 | 12 |
13 | ); 14 | } 15 | 16 | export const getConfig = async () => { 17 | return { 18 | render: 'static', 19 | } as const; 20 | }; 21 | -------------------------------------------------------------------------------- /packages/waku/src/lib/vite-entries/entry.browser.tsx: -------------------------------------------------------------------------------- 1 | import { setServerCallback } from '@vitejs/plugin-rsc/browser'; 2 | import { unstable_callServerRsc } from '../../minimal/client.js'; 3 | setServerCallback(unstable_callServerRsc); 4 | 5 | if (import.meta.hot) { 6 | import.meta.hot.on('rsc:update', (e) => { 7 | console.log('[rsc:update]', e); 8 | globalThis.__WAKU_RSC_RELOAD_LISTENERS__?.forEach((l) => l()); 9 | }); 10 | } 11 | 12 | import 'virtual:vite-rsc-waku/client-entry'; 13 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/waku.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'waku/config'; 2 | import type { VitePlugin } from 'waku/config'; 3 | 4 | function buildMode(): VitePlugin { 5 | return { 6 | name: 'build-mode', 7 | load() { 8 | // FIXME this hack seems fragile. 9 | (globalThis as any).__WAKU_IS_BUILD__ = this.environment.mode === 'build'; 10 | }, 11 | }; 12 | } 13 | 14 | export default defineConfig({ 15 | vite: { 16 | plugins: [buildMode()], 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /examples/03_demo/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | export const Footer = () => { 2 | return ( 3 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/12_nossr/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | export const Footer = () => { 2 | return ( 3 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/36_form/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/37_css/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/37_css/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/39_api/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/39_api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/42_react-tweet/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | export const Footer = () => { 2 | return ( 3 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/51_spa/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/54_jotai/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/src/ClientEcho.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useEffect, useState } from 'react'; 4 | import { Echo } from './Echo.js'; 5 | 6 | export function ClientEcho({ echo }: { echo: string }) { 7 | const [timeStamp, setTimestamp] = useState(() => Date.now()); 8 | useEffect(() => { 9 | const interval = setInterval(() => setTimestamp(Date.now()), 1000); 10 | return () => clearInterval(interval); 11 | }); 12 | return ; 13 | } 14 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-swr/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-swr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/01_template/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | export const Footer = () => { 2 | return ( 3 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/01_template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/02_template_js/src/components/footer.jsx: -------------------------------------------------------------------------------- 1 | export const Footer = () => { 2 | return ( 3 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/06_form-demo/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | export const Footer = () => { 2 | return ( 3 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/07_cloudflare/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | export const Footer = () => { 2 | return ( 3 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/08_jotai-demo/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | export const Footer = () => { 2 | return ( 3 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /examples/12_nossr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/31_minimal/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/31_minimal/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/33_promise/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/34_functions/src/components2/ButtonServer.tsx: -------------------------------------------------------------------------------- 1 | import ButtonClient from './ButtonClient'; 2 | 3 | let counter = 0; 4 | 5 | const ButtonServer = ({ name }: { name: string }) => { 6 | const now = Date.now(); 7 | async function handleClick() { 8 | 'use server'; 9 | console.log('Button clicked!', name, now, ++counter); 10 | } 11 | return ( 12 |
13 | {name} 14 |
15 | ); 16 | }; 17 | 18 | export default ButtonServer; 19 | -------------------------------------------------------------------------------- /examples/34_functions/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/35_nesting/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/38_cookies/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/41_path-alias/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/53_islands/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/53_islands/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/54_jotai/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/base-path/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/broken-links/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/create-pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-asset/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssg-wildcard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-redirect/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/tailwindcss/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/use-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/04_cssmodules/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/11_fs-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/21_create-pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/22_define-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/37_css-stylex/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/42_react-tweet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/43_weave-render/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/broken-links/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | import { ClientTitle } from '../components/ClientTitle.js'; 3 | 4 | export default function NotFound() { 5 | return ( 6 |
7 |

Custom not found

8 | Custom Not Found Title 9 |

10 | Back 11 |

12 |
13 | ); 14 | } 15 | 16 | export const getConfig = async () => { 17 | return { 18 | render: 'static', 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/partial-build/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/render-type/src/ServerEcho.tsx: -------------------------------------------------------------------------------- 1 | import { unstable_getContext as getContext } from 'waku/server'; 2 | import { Echo } from './Echo.js'; 3 | 4 | export function ServerEcho({ echo }: { echo: string }) { 5 | // TODO is there a more reasonable way? 6 | // eslint-disable-next-line react-hooks/purity 7 | const now = performance.now(); 8 | return ( 9 | <> 10 | 11 |

{getContext().req.url}

12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-css-modules/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssg-performance/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-catch-error/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-target-bundle/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-target-bundle/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/styled-components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/45_view-transitions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/52_tanstack-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/website/src/components/providers.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import type { ReactNode } from 'react'; 4 | import { Provider, createStore } from 'jotai'; 5 | import { menuAtom, scrolledAtom } from '../atoms'; 6 | 7 | type ProvidersProps = { children: ReactNode }; 8 | 9 | const store = createStore(); 10 | store.set(menuAtom, false); 11 | store.set(scrolledAtom, false); 12 | 13 | export const Providers = ({ children }: ProvidersProps) => { 14 | return {children}; 15 | }; 16 | -------------------------------------------------------------------------------- /e2e/fixtures/custom-library-adapter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/custom-user-adapter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-basic/src/components/test-env/server.tsx: -------------------------------------------------------------------------------- 1 | export function TestEnvServer() { 2 | const data = { 3 | 'import.meta.env.WAKU_PUBLIC_TEST': import.meta.env.WAKU_PUBLIC_TEST || '-', 4 | 'import.meta.env.WAKU_PRIVATE_TEST': 5 | import.meta.env.WAKU_PRIVATE_TEST || '-', 6 | 'process.env.WAKU_PUBLIC_TEST': process.env.WAKU_PUBLIC_TEST || '-', 7 | 'process.env.WAKU_PRIVATE_TEST': process.env.WAKU_PRIVATE_TEST || '-', 8 | }; 9 | return
{JSON.stringify(data, null, 2)}
; 10 | } 11 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-context-provider/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-context-provider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/waku-jotai-integration/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/wildcard-api-routes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | import styles from './footer.module.css'; 2 | 3 | export const Footer = () => { 4 | return ( 5 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /examples/37_css-vanilla-extract/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/53_islands/src/components/Dynamic.tsx: -------------------------------------------------------------------------------- 1 | import type { ReactNode } from 'react'; 2 | 3 | const Dynamic = async ({ children }: { children: ReactNode }) => { 4 | await new Promise((resolve) => setTimeout(resolve, 1000)); 5 | return ( 6 |
7 |

This is a dynamic server component.

8 | {children} 9 |
{new Date().toISOString()}
10 |
11 | ); 12 | }; 13 | 14 | export default Dynamic; 15 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'examples/*' 4 | - 'e2e/fixtures/*' 5 | # package.json in dist is generated by `waku build` 6 | - '!**/dist' 7 | preferWorkspacePackages: true 8 | saveWorkspaceProtocol: true 9 | linkWorkspacePackages: true 10 | minimumReleaseAge: 1440 11 | minimumReleaseAgeExclude: 12 | - '@hiogawa/node-loader-cloudflare' 13 | - '@vitejs/plugin-rsc' 14 | - 'react' 15 | - 'react-dom' 16 | - 'react-server-dom-webpack' 17 | - 'scheduler' 18 | - 'waku-jotai' 19 | -------------------------------------------------------------------------------- /e2e/fixtures/monorepo/packages/waku-project/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/src/components/ServerPing/actions.tsx: -------------------------------------------------------------------------------- 1 | 'use server'; 2 | 3 | import type { ReactNode } from 'react'; 4 | 5 | export const ping = async () => { 6 | return 'pong'; 7 | }; 8 | 9 | export const increase = async (value: number) => { 10 | return value + 1; 11 | }; 12 | 13 | export const wrap = async (node: ReactNode) => { 14 | return {node}; 15 | }; 16 | 17 | export const getData = async () => { 18 | return Server Data; 19 | }; 20 | -------------------------------------------------------------------------------- /e2e/fixtures/use-router/src/pages/dynamic.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'waku'; 2 | import { MyButton } from '../components/my-button.js'; 3 | import TestRouter from '../TestRouter.js'; 4 | 5 | const Page = () => ( 6 | <> 7 |

Dynamic

8 |

9 | Go to static 10 | 11 |

12 | 13 | 14 | ); 15 | 16 | export const getConfig = () => { 17 | return { 18 | render: 'dynamic', 19 | } as const; 20 | }; 21 | 22 | export default Page; 23 | -------------------------------------------------------------------------------- /examples/03_demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "types": ["node"], 16 | "jsx": "react-jsx" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/12_nossr/src/waku.server.ts: -------------------------------------------------------------------------------- 1 | import { fsRouter } from 'waku'; 2 | import adapter from 'waku/adapters/default'; 3 | 4 | const router = fsRouter(import.meta.glob('./**/*.tsx', { base: './pages' })); 5 | 6 | export default adapter({ 7 | handleRequest: async (input, utils) => { 8 | if (input.type === 'custom') { 9 | return 'fallback'; // no ssr 10 | } 11 | return router.handleRequest(input, utils); 12 | }, 13 | handleBuild: (utils) => { 14 | return router.handleBuild(utils); 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /examples/22_define-router/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { ErrorBoundary, Router } from 'waku/router/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 | 10 | 11 | ); 12 | 13 | if ((globalThis as any).__WAKU_HYDRATE__) { 14 | hydrateRoot(document, rootElement); 15 | } else { 16 | createRoot(document as any).render(rootElement); 17 | } 18 | -------------------------------------------------------------------------------- /examples/36_form/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "types": ["node"], 16 | "jsx": "react-jsx" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/45_view-transitions/src/components/Link.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import type { ComponentProps } from 'react'; 4 | import { Link as OrigLink } from 'waku/router/client'; 5 | 6 | const startViewTransition = 7 | typeof document !== 'undefined' 8 | ? (fn: () => void) => { 9 | document.startViewTransition(fn); 10 | } 11 | : undefined; 12 | 13 | export function Link(props: ComponentProps) { 14 | return ; 15 | } 16 | -------------------------------------------------------------------------------- /examples/06_form-demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "types": ["node"], 16 | "jsx": "react-jsx" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/34_functions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "types": ["node"], 16 | "jsx": "react-jsx" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/38_cookies/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "types": ["node"], 16 | "jsx": "react-jsx" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | types: [opened, synchronize] 8 | merge_group: 9 | 10 | jobs: 11 | lint: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v6 15 | - uses: pnpm/action-setup@v4 16 | - uses: actions/setup-node@v6 17 | with: 18 | node-version: 'lts/*' 19 | cache: 'pnpm' 20 | - run: pnpm install 21 | - run: pnpm run compile 22 | - run: pnpm test:lint 23 | -------------------------------------------------------------------------------- /packages/website/src/atoms/index.ts: -------------------------------------------------------------------------------- 1 | import { atom } from 'jotai'; 2 | import { atomWithStorage } from 'jotai/utils'; 3 | 4 | export const menuAtom = atom(false); 5 | 6 | export const scrolledAtom = atom(false); 7 | 8 | export const destinationAtom = atom(''); 9 | 10 | export type RoutingPreference = 'file-based' | 'config-based'; 11 | 12 | const ROUTING_PREFERENCE_KEY = 'waku-routing-preference'; 13 | 14 | export const routingTabAtom = atomWithStorage( 15 | ROUTING_PREFERENCE_KEY, 16 | 'file-based', 17 | ); 18 | -------------------------------------------------------------------------------- /examples/08_jotai-demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "types": ["react/experimental"], 16 | "jsx": "react-jsx" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-asset/src/waku.server.tsx: -------------------------------------------------------------------------------- 1 | import adapter from 'waku/adapters/default'; 2 | import App from './components/App.js'; 3 | 4 | export default adapter({ 5 | handleRequest: async (input, { renderRsc }) => { 6 | if (input.type === 'component') { 7 | return renderRsc({ App: }); 8 | } 9 | if (input.type === 'function') { 10 | const value = await input.fn(...input.args); 11 | return renderRsc({ _value: value }); 12 | } 13 | }, 14 | handleBuild: async () => {}, 15 | }); 16 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/modules/ai/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ai", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Vercel AI mockup", 6 | "exports": { 7 | "./rsc": { 8 | "types": "./src/index.d.ts", 9 | "react-server": "./src/server.js", 10 | "import": "./src/client.js" 11 | } 12 | }, 13 | "devDependencies": { 14 | "react-dom": "^18", 15 | "react-server-dom-webpack": "~19.2.3" 16 | }, 17 | "peerDependencies": { 18 | "react": "^18 || ^19" 19 | }, 20 | "private": true 21 | } 22 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-catch-error/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { ErrorBoundary } from 'react-error-boundary'; 2 | import ThrowsComponent from '../components/server/throws.js'; 3 | 4 | export default async function HomePage() { 5 | return ( 6 |
7 |

Home Page

8 | Something went wrong
}> 9 | 10 | 11 |
12 | ); 13 | } 14 | 15 | export const getConfig = async () => { 16 | return { 17 | render: 'static', 18 | } as const; 19 | }; 20 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-swr/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from './Counter.js'; 2 | 3 | const App = ({ name }: { name: string }) => { 4 | return ( 5 | 6 | 7 | Waku example 8 | 9 | 10 |
13 |

{name}

14 | 15 |
16 | 17 | 18 | ); 19 | }; 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /examples/04_cssmodules/src/components/counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | import styles from './counter.module.css'; 5 | 6 | export const Counter = () => { 7 | const [count, setCount] = useState(0); 8 | 9 | const handleIncrement = () => setCount((c) => c + 1); 10 | 11 | return ( 12 |
13 |
Count: {count}
14 | 17 |
18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /examples/07_cloudflare/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "types": ["./worker-configuration.d.ts"], 16 | "jsx": "react-jsx" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/33_promise/src/waku.client.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot, hydrateRoot } from 'react-dom/client'; 3 | import { Root, Slot } from 'waku/minimal/client'; 4 | 5 | const rootElement = ( 6 | 7 | 8 | 9 |

A client element

10 |
11 |
12 |
13 | ); 14 | 15 | if ((globalThis as any).__WAKU_HYDRATE__) { 16 | hydrateRoot(document, rootElement); 17 | } else { 18 | createRoot(document as any).render(rootElement); 19 | } 20 | -------------------------------------------------------------------------------- /examples/42_react-tweet/src/templates/home-page.tsx: -------------------------------------------------------------------------------- 1 | import { Tweet } from 'react-tweet'; 2 | 3 | export const HomePage = async () => { 4 | const data = await getData(); 5 | 6 | return ( 7 |
8 | {data.title} 9 |

{data.headline}

10 | 11 |
12 | ); 13 | }; 14 | 15 | const getData = async () => { 16 | const data = { 17 | title: 'Waku', 18 | headline: 'Waku', 19 | }; 20 | 21 | return data; 22 | }; 23 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-basic/modules/ai/src/shared.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { createContext, useContext } from 'react'; 3 | import { jsx } from 'react/jsx-runtime'; 4 | 5 | const ActionContext = createContext(null); 6 | 7 | export function useActions() { 8 | return useContext(ActionContext); 9 | } 10 | 11 | export function InternalProvider(props) { 12 | return jsx('div', { 13 | 'data-testid': 'ai-internal-provider', 14 | children: jsx(ActionContext, { 15 | value: props.actions, 16 | children: props.children, 17 | }), 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /examples/36_form/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "36_form", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/37_css/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "37_css", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "classnames": "2.3.2", 13 | "react": "~19.2.3", 14 | "react-dom": "~19.2.3", 15 | "react-server-dom-webpack": "~19.2.3", 16 | "waku": "0.27.5" 17 | }, 18 | "devDependencies": { 19 | "@types/react": "^19.2.7", 20 | "@types/react-dom": "^19.2.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/39_api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "39_api", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/51_spa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "51_spa", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /e2e/fixtures/styled-components/src/components/Counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | import styled from 'styled-components'; 5 | 6 | const Button = styled.button` 7 | border: 1px solid orange; 8 | padding: 0.5rem 1rem; 9 | background: transparent; 10 | cursor: pointer; 11 | &:hover { 12 | background: rgba(255, 165, 0, 0.1); 13 | } 14 | `; 15 | 16 | export const Counter = () => { 17 | const [count, setCount] = useState(0); 18 | return ; 19 | }; 20 | -------------------------------------------------------------------------------- /examples/41_path-alias/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "target": "esnext", 5 | "noEmit": true, 6 | "isolatedModules": true, 7 | "moduleDetection": "force", 8 | "downlevelIteration": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "skipLibCheck": true, 13 | "noUncheckedIndexedAccess": true, 14 | "exactOptionalPropertyTypes": true, 15 | "jsx": "react-jsx", 16 | "paths": { 17 | "@/*": ["./src/*"] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fs-router", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "latest" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /e2e/fixtures/fs-router/src/components/hello-client.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { Suspense, useEffect, useState } from 'react'; 4 | import { sayHello } from '../functions/say-hello.js'; 5 | 6 | export function HelloClient() { 7 | const [isClient, setIsClient] = useState(false); 8 | useEffect(() => { 9 | // FIXME what should be the best practice for this case? 10 | // eslint-disable-next-line react-hooks/set-state-in-effect 11 | setIsClient(true); 12 | }, []); 13 | return isClient && {sayHello()}; 14 | } 15 | -------------------------------------------------------------------------------- /e2e/fixtures/hot-reload/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hot-reload", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "latest" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /e2e/fixtures/rsc-asset/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rsc-asset", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "latest" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /e2e/fixtures/use-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "use-router", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "latest" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/11_fs-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "11_fs-router", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/11_fs-router/src/pages/_components/Counter.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useState } from 'react'; 4 | import { Link } from 'waku/router/client'; 5 | 6 | export const Counter = () => { 7 | const [count, setCount] = useState(0); 8 | return ( 9 |
10 |

Count: {count}

11 | 12 |

This is a client component.

13 | Go to Home 14 |
15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /examples/31_minimal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "31_minimal", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/33_promise/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "33_promise", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/35_nesting/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "35_nesting", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/53_islands/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "53_islands", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "0.27.5" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/waku/tests/config.test.ts: -------------------------------------------------------------------------------- 1 | import { expectType } from 'ts-expect'; 2 | import { expect, test } from 'vitest'; 3 | import { type Config, defineConfig } from '../src/config.js'; 4 | 5 | // Absolutely meaningless unit and type test examples. 6 | // Only exist to proof that the frameworks are set up correctly. 7 | test('defineConfig', async () => { 8 | expect(defineConfig({})).toEqual({}); 9 | }); 10 | 11 | expectType(defineConfig({})); 12 | 13 | // @ts-expect-error This is supposed to verify ts-expect works. 14 | expectType(defineConfig({})); 15 | -------------------------------------------------------------------------------- /e2e/fixtures/ssg-wildcard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ssg-wildcard", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "latest" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /e2e/fixtures/ssr-redirect/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ssr-redirect", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "latest" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/39_api/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { Counter } from './Counter'; 2 | 3 | const App = ({ name }: { name: string }) => { 4 | return ( 5 | 6 | 7 | Waku 8 | 9 | 10 |
13 |

Hello {name}!!

14 |

This is a server component.

15 | 16 |
17 | 18 | 19 | ); 20 | }; 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /packages/waku/src/lib/constants.ts: -------------------------------------------------------------------------------- 1 | export const EXTENSIONS = ['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs']; 2 | export const SRC_CLIENT_ENTRY = 'waku.client'; 3 | export const SRC_SERVER_ENTRY = 'waku.server'; 4 | export const SRC_PAGES = 'pages'; // only for managed mode 5 | export const SRC_MIDDLEWARE = 'middleware'; // only for managed mode 6 | 7 | // Some file and dir names for dist 8 | // We may change this in the future 9 | export const DIST_PUBLIC = 'public'; 10 | export const DIST_SERVER = 'server'; 11 | export const BUILD_METADATA_FILE = '__waku_build_metadata.js'; 12 | -------------------------------------------------------------------------------- /.github/workflows/pkg-pr-new.yml: -------------------------------------------------------------------------------- 1 | name: pkg-pr-new 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | types: [opened, synchronize] 8 | merge_group: 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v6 15 | - uses: pnpm/action-setup@v4 16 | - uses: actions/setup-node@v6 17 | with: 18 | node-version: 'lts/*' 19 | cache: 'pnpm' 20 | - run: pnpm install 21 | - run: pnpm run compile 22 | - run: pnpm dlx pkg-pr-new publish packages/waku 23 | -------------------------------------------------------------------------------- /e2e/fixtures/define-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "define-router", 3 | "version": "0.1.0", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "waku dev", 8 | "build": "waku build", 9 | "start": "waku start" 10 | }, 11 | "dependencies": { 12 | "react": "~19.2.3", 13 | "react-dom": "~19.2.3", 14 | "react-server-dom-webpack": "~19.2.3", 15 | "waku": "latest" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.2.7", 19 | "@types/react-dom": "^19.2.3", 20 | "typescript": "^5.9.3" 21 | } 22 | } 23 | --------------------------------------------------------------------------------