├── .changeset ├── README.md └── config.json ├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── close-v2-issues.yml │ ├── deduplicate-lock-file.yml │ ├── deployments.yml │ ├── format.yml │ ├── lint.yml │ ├── merged-pr.yml │ ├── nightly.yml │ ├── no-response.yml │ ├── release-comments.yml │ ├── release-experimental.yml │ ├── release.yml │ ├── shared-build.yml │ ├── shared-test-integration.yml │ ├── shared-test-unit.yml │ ├── stacks.yml │ ├── test-full.yml │ ├── test-pr-ubuntu.yml │ ├── test-pr-windows-macos.yml │ └── website.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .vscode ├── README.md ├── deno_resolve_npm_imports.json ├── extensions.json └── settings.json ├── CHANGELOG.md ├── CLA.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOPMENT.md ├── LICENSE.md ├── README.md ├── babel.config.js ├── contributors.yml ├── decisions ├── 0001-use-npm-to-manage-npm-dependencies-for-deno-projects.md ├── 0002-do-not-clone-request.md ├── 0003-infer-types-for-useloaderdata-and-useactiondata-from-loader-and-action-via-generics.md ├── 0004-streaming-apis.md ├── 0005-remixing-react-router.md ├── 0006-linear-workflow.md ├── 0007-remix-on-react-router-6-4-0.md ├── 0008-only-support-js-conversion-for-app-code.md ├── 0009-do-not-rely-on-treeshaking-for-correctness.md ├── 0010-splitting-up-client-and-server-code-in-vite.md └── template.md ├── docs ├── components │ ├── await.md │ ├── form.md │ ├── index.md │ ├── link.md │ ├── links.md │ ├── live-reload.md │ ├── meta.md │ ├── nav-link.md │ ├── outlet.md │ ├── prefetch-page-links.md │ ├── scripts.md │ └── scroll-restoration.md ├── discussion │ ├── component-data.md │ ├── concurrency.md │ ├── cookies-and-sessions.md │ ├── data-flow.md │ ├── error-handling.md │ ├── form-validation.md │ ├── form-vs-fetcher.md │ ├── formdata.md │ ├── hot-module-replacement.md │ ├── html-forms.md │ ├── index.md │ ├── introduction.md │ ├── multiple-forms.md │ ├── nested-routes.md │ ├── pending-ui.md │ ├── progressive-enhancement.md │ ├── react-router.md │ ├── resubmissions.md │ ├── routes.md │ ├── runtimes.md │ ├── server-vs-client.md │ ├── state-management.md │ └── testing.md ├── file-conventions │ ├── -client.md │ ├── -server.md │ ├── asset-imports.md │ ├── entry.client.md │ ├── entry.server.md │ ├── index.md │ ├── remix-config.md │ ├── root.md │ ├── routes.md │ └── vite-config.md ├── guides │ ├── accessibility.md │ ├── api-development-strategy.md │ ├── api-routes.md │ ├── authentication.md │ ├── bff.md │ ├── breadcrumbs.md │ ├── browser-support.md │ ├── cache-control.md │ ├── client-data.md │ ├── concurrent-submissions.md │ ├── constraints.md │ ├── contributing.md │ ├── css-files.md │ ├── data-loading.md │ ├── data-writes.md │ ├── debugging.md │ ├── dependency-optimization.md │ ├── deployment.md │ ├── disabling-javascript.md │ ├── envvars.md │ ├── errors.md │ ├── faq.md │ ├── file-uploads.md │ ├── form-validation.md │ ├── gotchas.md │ ├── images.md │ ├── index-query-param.md │ ├── index.md │ ├── lazy-route-discovery.md │ ├── local-tls.md │ ├── manual-mode.md │ ├── mdx.md │ ├── meta.md │ ├── migrating-react-router-app.md │ ├── not-found.md │ ├── performance.md │ ├── presets.md │ ├── progressive-enhancement.md │ ├── resource-routes.md │ ├── server-bundles.md │ ├── single-fetch.md │ ├── spa-mode.md │ ├── streaming.md │ ├── templates.md │ ├── typescript.md │ └── vite.md ├── hooks │ ├── index.md │ ├── use-action-data.md │ ├── use-async-error.md │ ├── use-async-value.md │ ├── use-before-unload.md │ ├── use-blocker.md │ ├── use-fetcher.md │ ├── use-fetchers.md │ ├── use-form-action.md │ ├── use-href.md │ ├── use-loader-data.md │ ├── use-location.md │ ├── use-matches.md │ ├── use-navigate.md │ ├── use-navigation-type.md │ ├── use-navigation.md │ ├── use-outlet-context.md │ ├── use-outlet.md │ ├── use-params.md │ ├── use-prompt.md │ ├── use-resolved-path.md │ ├── use-revalidator.md │ ├── use-route-error.md │ ├── use-route-loader-data.md │ ├── use-search-params.md │ ├── use-submit.md │ └── use-view-transition-state.md ├── index.md ├── other-api │ ├── adapter.md │ ├── create-remix.md │ ├── dev.md │ ├── index.md │ ├── node.md │ ├── serve.md │ └── testing.md ├── prettier.config.js ├── route │ ├── action.md │ ├── client-action.md │ ├── client-loader.md │ ├── component.md │ ├── error-boundary.md │ ├── handle.md │ ├── headers.md │ ├── hydrate-fallback.md │ ├── index.md │ ├── links.md │ ├── loader.md │ ├── meta.md │ └── should-revalidate.md ├── start │ ├── changelog.md │ ├── community.md │ ├── future-flags.md │ ├── index.md │ ├── quickstart.md │ ├── tutorial.md │ └── v2.md ├── styling │ ├── bundling.md │ ├── css-imports.md │ ├── css-in-js.md │ ├── css-modules.md │ ├── css.md │ ├── index.md │ ├── postcss.md │ ├── tailwind.md │ └── vanilla-extract.md ├── tutorials │ ├── blog.md │ ├── index.md │ └── jokes.md └── utils │ ├── cookies.md │ ├── create-remix-stub.md │ ├── data.md │ ├── defer.md │ ├── index.md │ ├── is-route-error-response.md │ ├── json.md │ ├── parse-multipart-form-data.md │ ├── redirect.md │ ├── redirectDocument.md │ ├── replace.md │ ├── sessions.md │ ├── unstable-create-file-upload-handler.md │ └── unstable-create-memory-upload-handler.md ├── examples └── README.md ├── integration ├── CHANGELOG.md ├── abort-signal-test.ts ├── action-test.ts ├── assets │ ├── toupload.txt │ └── touploadtoobig.txt ├── blocking-test.ts ├── browser-entry-test.ts ├── bug-report-test.ts ├── catch-boundary-data-test.ts ├── catch-boundary-test.ts ├── cf-compiler-test.ts ├── client-data-test.ts ├── compiler-mjs-cjs-output-test.ts ├── compiler-test.ts ├── css-modules-test.ts ├── css-side-effect-imports-test.ts ├── custom-entry-server-test.ts ├── defer-loader-test.ts ├── defer-test.ts ├── deno-compiler-test.ts ├── deterministic-build-output-test.ts ├── error-boundary-test.ts ├── error-boundary-v2-test.ts ├── error-data-request-test.ts ├── error-sanitization-test.ts ├── fetch-globals-test.ts ├── fetcher-layout-test.ts ├── fetcher-test.ts ├── file-uploads-test.ts ├── flat-routes-test.ts ├── fog-of-war-test.ts ├── form-data-test.ts ├── form-test.ts ├── headers-test.ts ├── helpers │ ├── cf-template │ │ ├── .gitignore │ │ ├── app │ │ │ ├── root.tsx │ │ │ └── routes │ │ │ │ └── _index.tsx │ │ ├── package.json │ │ ├── public │ │ │ └── favicon.ico │ │ ├── remix.config.js │ │ ├── remix.env.d.ts │ │ ├── server.ts │ │ ├── tsconfig.json │ │ └── wrangler.toml │ ├── cleanup.mjs │ ├── create-fixture.ts │ ├── deno-template │ │ ├── .gitignore │ │ ├── app │ │ │ ├── root.tsx │ │ │ └── routes │ │ │ │ └── _index.tsx │ │ ├── package.json │ │ ├── public │ │ │ └── favicon.ico │ │ ├── remix.config.js │ │ └── server.ts │ ├── killtree.ts │ ├── node-template │ │ ├── .gitignore │ │ ├── app │ │ │ ├── root.tsx │ │ │ └── routes │ │ │ │ └── _index.tsx │ │ ├── package.json │ │ ├── public │ │ │ └── favicon.ico │ │ ├── remix.config.js │ │ ├── remix.env.d.ts │ │ └── tsconfig.json │ ├── playwright-fixture.ts │ ├── vite-5-template │ │ ├── .gitignore │ │ ├── app │ │ │ ├── root.tsx │ │ │ └── routes │ │ │ │ └── _index.tsx │ │ ├── env.d.ts │ │ ├── package.json │ │ ├── public │ │ │ └── favicon.ico │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── vite-6-template │ │ ├── .gitignore │ │ ├── app │ │ │ ├── root.tsx │ │ │ └── routes │ │ │ │ └── _index.tsx │ │ ├── env.d.ts │ │ ├── package.json │ │ ├── public │ │ │ └── favicon.ico │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── vite-cloudflare-template │ │ ├── .gitignore │ │ ├── app │ │ │ ├── root.tsx │ │ │ └── routes │ │ │ │ └── _index.tsx │ │ ├── env.d.ts │ │ ├── package.json │ │ ├── public │ │ │ └── favicon.ico │ │ ├── tsconfig.json │ │ └── vite.config.ts │ └── vite.ts ├── hmr-test.ts ├── hook-useSubmit-test.ts ├── js-routes-test.ts ├── layout-route-test.ts ├── link-test.ts ├── loader-test.ts ├── matches-test.ts ├── mdx-test.ts ├── multiple-cookies-test.ts ├── navigation-state-test.ts ├── package.json ├── path-mapping-test.ts ├── playwright.config.ts ├── postcss-test.ts ├── prefetch-test.ts ├── redirects-test.ts ├── remix-serve-test.ts ├── rendering-test.ts ├── request-test.ts ├── resource-routes-test.ts ├── revalidate-test.ts ├── root-route-test.ts ├── route-collisions-test.ts ├── scroll-test.ts ├── server-code-in-browser-message-test.ts ├── server-entry-test.ts ├── server-source-maps-test.ts ├── set-cookie-revalidation-test.ts ├── shared-route-imports-test.ts ├── single-fetch-test.ts ├── splat-routes-test.ts ├── svg-in-node-modules-test.ts ├── tailwind-test.ts ├── transition-test.ts ├── tsconfig.json ├── upload-test.ts ├── vanilla-extract-test.ts ├── vite-absolute-base-test.ts ├── vite-basename-test.ts ├── vite-build-test.ts ├── vite-cloudflare-test.ts ├── vite-css-test.ts ├── vite-dev-custom-entry-test.ts ├── vite-dev-test.ts ├── vite-dot-client-test.ts ├── vite-dot-server-test.ts ├── vite-dotenv-test.ts ├── vite-fs-routes-test.ts ├── vite-hmr-hdr-test.ts ├── vite-loader-context-test.ts ├── vite-manifests-test.ts ├── vite-node-env-test.ts ├── vite-plugin-order-validation-test.ts ├── vite-presets-test.ts ├── vite-route-added-test.ts ├── vite-route-config-test.ts ├── vite-route-exports-modified-offscreen-test.ts ├── vite-server-bundles-test.ts ├── vite-server-fs-allow-test.ts ├── vite-spa-mode-test.ts └── vite-unused-route-exports-test.ts ├── jest.config.js ├── jest ├── buildRemix.js ├── jest.config.shared.js └── transform.js ├── package.json ├── packages ├── ADDING_A_PACKAGE.md ├── create-remix │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── create-remix-test.ts │ │ ├── fixtures │ │ │ ├── arc.tar.gz │ │ │ ├── arc.tgz │ │ │ ├── blank │ │ │ │ └── package.json │ │ │ ├── examples-main.tar.gz │ │ │ ├── failing-remix-init │ │ │ │ ├── package.json │ │ │ │ └── remix.init │ │ │ │ │ └── index.js │ │ │ ├── nested-dir-repo.tar.gz │ │ │ ├── remix-repo.tar.gz │ │ │ ├── stack.tar.gz │ │ │ ├── stack │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── app │ │ │ │ │ ├── entry.client.tsx │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ ├── root.tsx │ │ │ │ │ └── utils.ts │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ └── favicon.ico │ │ │ │ ├── remix.config.js │ │ │ │ ├── remix.env.d.ts │ │ │ │ ├── remix.init │ │ │ │ │ └── index.js │ │ │ │ └── tsconfig.json │ │ │ ├── successful-remix-init │ │ │ │ ├── package.json │ │ │ │ └── remix.init │ │ │ │ │ └── index.js │ │ │ ├── tar.js │ │ │ └── with-ignored-dir │ │ │ │ └── package.json │ │ ├── github-mocks.ts │ │ ├── msw-register.ts │ │ ├── msw.ts │ │ └── setupAfterEnv.ts │ ├── cli.ts │ ├── copy-template.ts │ ├── index.ts │ ├── jest.config.js │ ├── loading-indicator.ts │ ├── package.json │ ├── prompt.ts │ ├── prompts-confirm.ts │ ├── prompts-multi-select.ts │ ├── prompts-prompt-base.ts │ ├── prompts-select.ts │ ├── prompts-text.ts │ ├── rollup.config.js │ ├── tsconfig.json │ └── utils.ts ├── remix-architect │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── 554828.jpeg │ │ ├── binaryTypes-test.ts │ │ ├── server-test.ts │ │ └── setup.ts │ ├── binaryTypes.ts │ ├── index.ts │ ├── jest.config.js │ ├── package.json │ ├── rollup.config.js │ ├── server.ts │ ├── sessions │ │ └── arcTableSessionStorage.ts │ └── tsconfig.json ├── remix-cloudflare-pages │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── tsconfig.json │ └── worker.ts ├── remix-cloudflare-workers │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── tsconfig.json │ └── worker.ts ├── remix-cloudflare │ ├── CHANGELOG.md │ ├── crypto.ts │ ├── globals.ts │ ├── implementations.ts │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── sessions │ │ └── workersKVStorage.ts │ └── tsconfig.json ├── remix-css-bundle │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ └── tsconfig.json ├── remix-deno │ ├── .empty.js │ ├── CHANGELOG.md │ ├── README.md │ ├── crypto.ts │ ├── globals.ts │ ├── implementations.ts │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── server.ts │ └── sessions │ │ └── fileStorage.ts ├── remix-dev │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── cli-test.ts │ │ ├── cssSideEffectImports-test.ts │ │ ├── defineRoutes-test.ts │ │ ├── fixtures │ │ │ ├── cloudflare │ │ │ │ ├── .gitignore │ │ │ │ ├── .node-version │ │ │ │ ├── README.md │ │ │ │ ├── app │ │ │ │ │ ├── root.tsx │ │ │ │ │ └── routes │ │ │ │ │ │ └── _index.tsx │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ ├── _headers │ │ │ │ │ ├── _routes.json │ │ │ │ │ └── favicon.ico │ │ │ │ ├── remix.config.js │ │ │ │ ├── remix.env.d.ts │ │ │ │ ├── server.ts │ │ │ │ └── tsconfig.json │ │ │ ├── deno │ │ │ │ ├── .gitignore │ │ │ │ ├── .vscode │ │ │ │ │ ├── extensions.json │ │ │ │ │ ├── resolve_npm_imports.json │ │ │ │ │ └── settings.json │ │ │ │ ├── README.md │ │ │ │ ├── app │ │ │ │ │ ├── root.tsx │ │ │ │ │ └── routes │ │ │ │ │ │ └── _index.tsx │ │ │ │ ├── deno.json │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ └── favicon.ico │ │ │ │ ├── remix.config.js │ │ │ │ └── server.ts │ │ │ ├── examples-main.tar.gz │ │ │ ├── failing-remix-init │ │ │ │ ├── package.json │ │ │ │ └── remix.init │ │ │ │ │ └── index.js │ │ │ ├── nested-dir-repo.tar.gz │ │ │ ├── node │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── app │ │ │ │ │ ├── root.tsx │ │ │ │ │ └── routes │ │ │ │ │ │ └── _index.tsx │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ └── favicon.ico │ │ │ │ ├── remix.config.js │ │ │ │ ├── remix.env.d.ts │ │ │ │ └── tsconfig.json │ │ │ ├── remix-repo.tar.gz │ │ │ ├── stack.tar.gz │ │ │ ├── stack │ │ │ │ ├── .gitignore │ │ │ │ ├── README.md │ │ │ │ ├── app │ │ │ │ │ ├── entry.client.tsx │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ ├── root.tsx │ │ │ │ │ └── utils.ts │ │ │ │ ├── package.json │ │ │ │ ├── public │ │ │ │ │ └── favicon.ico │ │ │ │ ├── remix.config.js │ │ │ │ ├── remix.env.d.ts │ │ │ │ ├── remix.init │ │ │ │ │ └── index.js │ │ │ │ └── tsconfig.json │ │ │ ├── successful-remix-init │ │ │ │ ├── package.json │ │ │ │ └── remix.init │ │ │ │ │ └── index.js │ │ │ └── tar.js │ │ ├── flat-routes-test.ts │ │ ├── github-mocks.ts │ │ ├── init-test.ts │ │ ├── msw.ts │ │ ├── readConfig-test.ts │ │ ├── reveal-test.ts │ │ ├── routeManifestToRouteConfig-test.ts │ │ ├── setupAfterEnv.ts │ │ ├── styles-test.ts │ │ ├── utils │ │ │ ├── captureError.ts │ │ │ ├── cli.ts │ │ │ ├── eol.ts │ │ │ ├── git.ts │ │ │ └── withApp.ts │ │ └── validateRouteConfig-test.ts │ ├── assets-manifest.d.ts │ ├── cache.ts │ ├── channel.ts │ ├── cli.ts │ ├── cli │ │ ├── commands.ts │ │ ├── detectPackageManager.ts │ │ ├── index.ts │ │ ├── run.ts │ │ └── useJavascript.ts │ ├── colors.ts │ ├── compiler │ │ ├── analysis.ts │ │ ├── build.ts │ │ ├── cancel.ts │ │ ├── compiler.ts │ │ ├── context.ts │ │ ├── css │ │ │ ├── bundle.ts │ │ │ ├── compiler.ts │ │ │ ├── index.ts │ │ │ └── plugins │ │ │ │ └── bundleEntry.ts │ │ ├── fileWatchCache.ts │ │ ├── index.ts │ │ ├── js │ │ │ ├── compiler.ts │ │ │ ├── index.ts │ │ │ ├── plugins │ │ │ │ ├── browserNodeBuiltinsPolyfill.ts │ │ │ │ ├── hmr.ts │ │ │ │ └── routes.ts │ │ │ └── write.ts │ │ ├── lazyValue.ts │ │ ├── manifest.ts │ │ ├── options.ts │ │ ├── plugins │ │ │ ├── absoluteCssUrlsPlugin.ts │ │ │ ├── cssBundlePlugin.ts │ │ │ ├── cssImports.ts │ │ │ ├── cssModuleImports.ts │ │ │ ├── cssSideEffectImports.ts │ │ │ ├── emptyModules.ts │ │ │ ├── external.ts │ │ │ ├── mdx.ts │ │ │ └── vanillaExtract.ts │ │ ├── server │ │ │ ├── compiler.ts │ │ │ ├── index.ts │ │ │ ├── plugins │ │ │ │ ├── bareImports.ts │ │ │ │ ├── entry.ts │ │ │ │ ├── manifest.ts │ │ │ │ ├── routes.ts │ │ │ │ └── serverNodeBuiltinsPolyfill.ts │ │ │ ├── virtualModules.ts │ │ │ └── write.ts │ │ ├── utils │ │ │ ├── crypto.ts │ │ │ ├── loaders.ts │ │ │ ├── log.ts │ │ │ ├── postcss.ts │ │ │ ├── routeExports.ts │ │ │ └── tsconfig.ts │ │ └── watch.ts │ ├── config.ts │ ├── config │ │ ├── defaults │ │ │ ├── entry.client.tsx │ │ │ ├── entry.dev.ts │ │ │ ├── entry.server.cloudflare.tsx │ │ │ ├── entry.server.deno.tsx │ │ │ ├── entry.server.node.tsx │ │ │ └── entry.server.spa.tsx │ │ ├── flat-routes.ts │ │ ├── format.ts │ │ ├── routes.ts │ │ └── serverModes.ts │ ├── dependencies.ts │ ├── devServer │ │ ├── index.ts │ │ └── liveReload.ts │ ├── devServer_unstable │ │ ├── env.ts │ │ ├── hdr.ts │ │ ├── hmr.ts │ │ ├── index.ts │ │ ├── proc.ts │ │ └── socket.ts │ ├── index.ts │ ├── invariant.ts │ ├── jest.config.js │ ├── manifest.ts │ ├── modules.ts │ ├── package.json │ ├── result.ts │ ├── rollup.config.js │ ├── server-build.ts │ ├── tsconfig.json │ ├── tux │ │ ├── format.ts │ │ ├── index.ts │ │ └── logger.ts │ └── vite │ │ ├── babel.ts │ │ ├── build.ts │ │ ├── cloudflare-proxy-plugin.ts │ │ ├── combine-urls-test.ts │ │ ├── combine-urls.ts │ │ ├── dev.ts │ │ ├── index.ts │ │ ├── is-in-remix-monorepo.ts │ │ ├── node-adapter.ts │ │ ├── plugin.ts │ │ ├── profiler.ts │ │ ├── remove-exports-test.ts │ │ ├── remove-exports.ts │ │ ├── resolve-file-url.ts │ │ ├── ssr-externals.ts │ │ ├── static │ │ └── refresh-utils.cjs │ │ ├── styles.ts │ │ ├── vite-node.ts │ │ ├── vite.ts │ │ └── vmod.ts ├── remix-eslint-config │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ ├── internal.js │ ├── jest-testing-library.js │ ├── node.js │ ├── package.json │ ├── rules │ │ ├── core.js │ │ ├── import.js │ │ ├── jest-dom.js │ │ ├── jest.js │ │ ├── jsx-a11y.js │ │ ├── react.js │ │ ├── testing-library.js │ │ └── typescript.js │ └── settings │ │ ├── import.js │ │ └── react.js ├── remix-express │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── server-test.ts │ │ └── setup.ts │ ├── index.ts │ ├── jest.config.js │ ├── package.json │ ├── rollup.config.js │ ├── server.ts │ └── tsconfig.json ├── remix-fs-routes │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ └── tsconfig.json ├── remix-node │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── assets │ │ │ └── test.txt │ │ ├── fileUploadHandler-test.ts │ │ ├── sessions-test.ts │ │ ├── setup.ts │ │ └── utils.ts │ ├── crypto.ts │ ├── globals.ts │ ├── implementations.ts │ ├── index.ts │ ├── install.d.ts │ ├── install.js │ ├── jest.config.js │ ├── package.json │ ├── rollup.config.js │ ├── sessions │ │ └── fileStorage.ts │ ├── stream.ts │ ├── tsconfig.json │ └── upload │ │ └── fileUploadHandler.ts ├── remix-react │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── components-test.tsx │ │ ├── deferred-scripts-test.tsx │ │ ├── exports-test.tsx │ │ ├── integration │ │ │ └── meta-test.tsx │ │ ├── scroll-restoration-test.tsx │ │ └── setup.ts │ ├── browser.tsx │ ├── components.tsx │ ├── data.ts │ ├── entry.ts │ ├── errorBoundaries.tsx │ ├── errors.ts │ ├── fallback.tsx │ ├── fog-of-war.ts │ ├── index.tsx │ ├── invariant.ts │ ├── jest.config.js │ ├── links.ts │ ├── markup.ts │ ├── package.json │ ├── rollup.config.js │ ├── routeModules.ts │ ├── routes.tsx │ ├── scroll-restoration.tsx │ ├── server.tsx │ ├── single-fetch.tsx │ ├── tsconfig.json │ └── warnings.ts ├── remix-route-config │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ └── route-config-test.ts │ ├── index.ts │ ├── jest.config.js │ ├── package.json │ ├── rollup.config.js │ ├── routes.ts │ └── tsconfig.json ├── remix-routes-option-adapter │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ └── tsconfig.json ├── remix-serve │ ├── CHANGELOG.md │ ├── README.md │ ├── cli.ts │ ├── package.json │ ├── rollup.config.js │ └── tsconfig.json ├── remix-server-runtime │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── .eslintrc.js │ │ ├── cookies-test.ts │ │ ├── data-test.ts │ │ ├── formData-test.ts │ │ ├── handle-error-test.ts │ │ ├── handler-test.ts │ │ ├── markup-test.ts │ │ ├── responses-test.ts │ │ ├── serialize-test.ts │ │ ├── server-test.ts │ │ ├── sessions-test.ts │ │ ├── setup.ts │ │ └── utils.ts │ ├── build.ts │ ├── cookies.ts │ ├── crypto.ts │ ├── data.ts │ ├── deprecations.ts │ ├── dev.ts │ ├── entry.ts │ ├── errors.ts │ ├── formData.ts │ ├── future.ts │ ├── headers.ts │ ├── index.ts │ ├── interface.ts │ ├── invariant.ts │ ├── jest.config.js │ ├── jsonify.ts │ ├── links.ts │ ├── markup.ts │ ├── mode.ts │ ├── package.json │ ├── reexport.ts │ ├── responses.ts │ ├── rollup.config.js │ ├── routeMatching.ts │ ├── routeModules.ts │ ├── routes.ts │ ├── serialize.ts │ ├── server.ts │ ├── serverHandoff.ts │ ├── sessions.ts │ ├── sessions │ │ ├── cookieStorage.ts │ │ └── memoryStorage.ts │ ├── single-fetch.ts │ ├── tsconfig.json │ ├── typecheck.ts │ ├── upload │ │ ├── errors.ts │ │ └── memoryUploadHandler.ts │ └── warnings.ts ├── remix-testing │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ └── stub-test.tsx │ ├── create-remix-stub.tsx │ ├── index.ts │ ├── jest.config.js │ ├── jest.setup.js │ ├── package.json │ ├── rollup.config.js │ └── tsconfig.json └── remix │ ├── CHANGELOG.md │ ├── README.md │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ └── tsconfig.json ├── patches └── @changesets__assemble-release-plan@5.2.2.patch ├── playground └── README.md ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── prettier.config.js ├── rollup.config.js ├── rollup.utils.js ├── scripts ├── build.mjs ├── bump-fetch-versions.sh ├── bump-router-versions.sh ├── clean-build.mjs ├── close-v2-issues-comment.md ├── close-v2-issues.mjs ├── close-v2-prs-comment.md ├── compile-release-notes.mjs ├── copy-build-to-dist.mjs ├── copy-templates-to-fixtures.sh ├── deployment-test │ ├── _shared.mjs │ ├── arc.mjs │ ├── cf-pages.mjs │ ├── cf-workers.mjs │ ├── cypress.json │ ├── cypress │ │ ├── .eslintrc.js │ │ ├── e2e │ │ │ └── smoke.ts │ │ ├── fixtures │ │ │ └── example.json │ │ ├── plugins │ │ │ └── index.ts │ │ ├── support │ │ │ └── index.js │ │ └── tsconfig.json │ ├── deno-deploy.mjs │ ├── fly.mjs │ └── package.json ├── find-release-from-changeset.js ├── lint-templates.sh ├── markdown-references.mjs ├── patchup-version.mjs ├── playground │ ├── new.js │ └── template │ │ ├── .env │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── README.md │ │ ├── app │ │ ├── db.server.ts │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── models │ │ │ ├── note.server.ts │ │ │ └── user.server.ts │ │ ├── root.tsx │ │ ├── routes │ │ │ ├── index.tsx │ │ │ ├── join.tsx │ │ │ ├── login.tsx │ │ │ ├── logout.tsx │ │ │ ├── notes.tsx │ │ │ └── notes │ │ │ │ ├── $noteId.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── new.tsx │ │ ├── session.server.ts │ │ ├── styles │ │ │ └── tailwind.css │ │ └── utils.ts │ │ ├── package.json │ │ ├── prisma │ │ ├── migrations │ │ │ ├── 20220307190657_init │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ ├── schema.prisma │ │ └── seed.ts │ │ ├── public │ │ └── favicon.ico │ │ ├── remix.config.js │ │ ├── remix.env.d.ts │ │ ├── remix.init │ │ └── index.js │ │ ├── server.js │ │ ├── tailwind.config.js │ │ └── tsconfig.json ├── prompt-confirm.d.ts ├── publish-private.js ├── publish.js ├── release.js ├── remove-prerelease-changelogs.mjs ├── run-migration-on-examples.js ├── tsconfig.json ├── unist.d.ts ├── utils.js └── version.js └── templates ├── .eslintignore ├── .gitignore ├── classic-remix-compiler ├── arc │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── app.arc │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ └── routes │ │ │ └── _index.tsx │ ├── package.json │ ├── plugin-remix.js │ ├── public │ │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── server.ts │ └── tsconfig.json ├── cloudflare-pages │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .node-version │ ├── README.md │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ └── routes │ │ │ └── _index.tsx │ ├── package.json │ ├── public │ │ ├── _headers │ │ ├── _routes.json │ │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── server.ts │ └── tsconfig.json ├── cloudflare-workers │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ └── routes │ │ │ └── _index.tsx │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── server.ts │ ├── tsconfig.json │ └── wrangler.toml ├── deno │ ├── .gitignore │ ├── .vscode │ │ ├── extensions.json │ │ ├── resolve_npm_imports.json │ │ └── settings.json │ ├── README.md │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ └── routes │ │ │ └── _index.tsx │ ├── deno.json │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── remix.config.js │ └── server.ts ├── express │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ └── routes │ │ │ └── _index.tsx │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── server.js │ └── tsconfig.json ├── fly │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ └── routes │ │ │ └── _index.tsx │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ └── tsconfig.json ├── remix-javascript │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── entry.client.jsx │ │ ├── entry.server.jsx │ │ ├── root.jsx │ │ └── routes │ │ │ └── _index.jsx │ ├── package.json │ ├── public │ │ └── favicon.ico │ └── remix.config.js └── remix │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── README.md │ ├── app │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── root.tsx │ └── routes │ │ └── _index.tsx │ ├── package.json │ ├── public │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ └── tsconfig.json ├── cloudflare-workers ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── app │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── root.tsx │ ├── routes │ │ └── _index.tsx │ └── tailwind.css ├── load-context.ts ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ ├── logo-dark.png │ └── logo-light.png ├── server.ts ├── tailwind.config.ts ├── tsconfig.json ├── vite.config.ts ├── worker-configuration.d.ts └── wrangler.toml ├── cloudflare ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── app │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── root.tsx │ ├── routes │ │ └── _index.tsx │ └── tailwind.css ├── functions │ └── [[path]].ts ├── load-context.ts ├── package.json ├── postcss.config.js ├── public │ ├── _headers │ ├── _routes.json │ ├── favicon.ico │ ├── logo-dark.png │ └── logo-light.png ├── tailwind.config.ts ├── tsconfig.json └── vite.config.ts ├── express ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── app │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── root.tsx │ ├── routes │ │ └── _index.tsx │ └── tailwind.css ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ ├── logo-dark.png │ └── logo-light.png ├── server.js ├── tailwind.config.ts ├── tsconfig.json └── vite.config.ts ├── remix-javascript ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── app │ ├── entry.client.jsx │ ├── entry.server.jsx │ ├── root.jsx │ ├── routes │ │ └── _index.jsx │ └── tailwind.css ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ ├── logo-dark.png │ └── logo-light.png ├── tailwind.config.js └── vite.config.js ├── remix-tutorial ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── app │ ├── app.css │ ├── data.ts │ └── root.tsx ├── package.json ├── public │ └── favicon.ico ├── tsconfig.json └── vite.config.ts ├── remix ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── app │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── root.tsx │ ├── routes │ │ └── _index.tsx │ └── tailwind.css ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ ├── logo-dark.png │ └── logo-light.png ├── tailwind.config.ts ├── tsconfig.json └── vite.config.ts └── spa ├── .eslintrc.cjs ├── .gitignore ├── README.md ├── app ├── entry.client.tsx ├── root.tsx ├── routes │ └── _index.tsx └── tailwind.css ├── package.json ├── postcss.config.js ├── public ├── favicon.ico ├── logo-dark.png └── logo-light.png ├── tailwind.config.ts ├── tsconfig.json └── vite.config.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/build/ 2 | **/tests/__snapshots/ 3 | **/node_modules/ 4 | .tmp 5 | pnpm-lock.yaml 6 | /playground 7 | **/__tests__/fixtures 8 | **/__tests__/**/*/fixtures 9 | /packages/*/dist/ 10 | 11 | # Deno 12 | integration/helpers/deno-template 13 | packages/remix-deno 14 | templates/deno 15 | 16 | packages/remix-dev/config/defaults 17 | templates/remix-tutorial/app/data.ts 18 | templates/cloudflare-workers/worker-configuration.d.ts 19 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.github/workflows/merged-pr.yml: -------------------------------------------------------------------------------- 1 | name: 📦 Merged PR 2 | 3 | on: 4 | pull_request: 5 | types: [closed] 6 | branches: 7 | - dev 8 | paths: 9 | - "packages/**" 10 | 11 | permissions: 12 | pull-requests: write 13 | 14 | jobs: 15 | merged: 16 | name: Add label to merged PR 17 | if: github.event.pull_request.merged == true && github.repository == 'remix-run/remix' 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/github-script@v7 21 | with: 22 | retries: 3 23 | script: | 24 | await github.rest.issues.addLabels({ 25 | owner: context.repo.owner, 26 | repo: context.repo.repo, 27 | issue_number: context.issue.number, 28 | labels: ['awaiting release'], 29 | }) 30 | -------------------------------------------------------------------------------- /.github/workflows/release-comments.yml: -------------------------------------------------------------------------------- 1 | name: 📝 Comment on Release 2 | 3 | on: 4 | workflow_call: 5 | 6 | jobs: 7 | comment: 8 | name: 📝 Comment on related issues and pull requests 9 | if: github.repository == 'remix-run/remix' 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: ⬇️ Checkout repo 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | 17 | - name: 📝 Comment on related issues and pull requests 18 | uses: remix-run/release-comment-action@v0.4.1 19 | with: 20 | DIRECTORY_TO_CHECK: "./packages" 21 | PACKAGE_NAME: "remix" 22 | PR_LABELS_TO_REMOVE: "awaiting release" 23 | -------------------------------------------------------------------------------- /.github/workflows/website.yml: -------------------------------------------------------------------------------- 1 | name: 🌐 Website 2 | 3 | on: 4 | schedule: 5 | # every hour 6 | - cron: "0 * * * *" 7 | push: 8 | branches: [main, dev] 9 | paths: [docs/**] 10 | release: 11 | types: [published] 12 | 13 | jobs: 14 | website: 15 | if: github.repository == 'remix-run/remix' 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: 🔄 Refresh the docs 20 | uses: fjogeleit/http-request-action@v1 21 | with: 22 | url: "${{ secrets.DOCS_REFRESH_URL }}?ref=${{ github.ref }}" 23 | method: "POST" 24 | customHeaders: '{"Authorization": "${{ secrets.DOCS_REFRESH_TOKEN }}"}' 25 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | shell-emulator=true 3 | enable-pre-post-scripts=true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .changeset/*.md 2 | pnpm-lock.yaml 3 | -------------------------------------------------------------------------------- /.vscode/README.md: -------------------------------------------------------------------------------- 1 | A note on `deno_resolve_npm_imports.json` 2 | 3 | The `"imports"` field in `deno_resolve_npm_imports.json` is used to resolve NPM imports for `packages/remix-deno`. This import map is used solely for the d`enoland.vscode-deno` extension. 4 | 5 | Remix does not support import maps. Dependency management is done through `npm` and `node_modules/` instead. Deno-only dependencies may be imported via URL imports (without using import maps). 6 | -------------------------------------------------------------------------------- /.vscode/deno_resolve_npm_imports.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "@remix-run/server-runtime": "https://esm.sh/@remix-run/server-runtime@nightly", 4 | "mime": "https://esm.sh/mime@^3.0.0" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "denoland.vscode-deno", 5 | "esbenp.prettier-vscode" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "deno.enablePaths": ["./packages/remix-deno/"], 4 | "deno.importMap": "./.vscode/deno_resolve_npm_imports.json" 5 | } 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please see [our guide to contributing](docs/guides/contributing.md). 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | targets: { 7 | node: "18", 8 | }, 9 | }, 10 | ], 11 | "@babel/preset-react", 12 | "@babel/preset-typescript", 13 | ], 14 | plugins: [ 15 | "@babel/plugin-proposal-export-namespace-from", 16 | "@babel/plugin-proposal-optional-chaining", 17 | // Strip console.debug calls unless REMIX_DEBUG=true 18 | ...(process.env.REMIX_DEBUG === "true" 19 | ? [] 20 | : [ 21 | [ 22 | "transform-remove-console", 23 | { exclude: ["error", "warn", "log", "info"] }, 24 | ], 25 | ]), 26 | ], 27 | }; 28 | -------------------------------------------------------------------------------- /decisions/template.md: -------------------------------------------------------------------------------- 1 | # Title 2 | 3 | Date: YYYY-MM-DD 4 | 5 | Status: proposed | rejected | accepted | deprecated | … | superseded by [0005](0005-example.md) 6 | 7 | ## Context 8 | 9 | ## Decision 10 | 11 | ## Consequences 12 | -------------------------------------------------------------------------------- /docs/components/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Components 3 | order: 5 4 | --- 5 | -------------------------------------------------------------------------------- /docs/components/links.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Links 3 | toc: false 4 | --- 5 | 6 | # `` 7 | 8 | The `` component renders all of the [``][link_element] tags created by your route module [`links`][links] export. You should render it inside the [``][head_element] of your HTML, usually in `app/root.tsx`. 9 | 10 | ```tsx filename=app/root.tsx lines=[7] 11 | import { Links } from "@remix-run/react"; 12 | 13 | export default function Root() { 14 | return ( 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | ``` 24 | 25 | [link_element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link 26 | [head_element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head 27 | [links]: ../route/links 28 | -------------------------------------------------------------------------------- /docs/components/meta.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Meta 3 | toc: false 4 | --- 5 | 6 | # `` 7 | 8 | This component renders all of the [``][meta_element] tags created by your route module [`meta`][meta] export. You should render it inside the [``][head_element] of your HTML, usually in `app/root.tsx`. 9 | 10 | ```tsx filename=app/root.tsx lines=[7] 11 | import { Meta } from "@remix-run/react"; 12 | 13 | export default function Root() { 14 | return ( 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | ``` 24 | 25 | [meta_element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta 26 | [head_element]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head 27 | [meta]: ../route/meta 28 | -------------------------------------------------------------------------------- /docs/components/outlet.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Outlet 3 | --- 4 | 5 | # `` 6 | 7 | Renders the matching child route of a parent route. 8 | 9 | ```tsx 10 | import { Outlet } from "@remix-run/react"; 11 | 12 | export default function SomeParent() { 13 | return ( 14 |
15 |

Parent Content

16 | 17 | 18 |
19 | ); 20 | } 21 | ``` 22 | 23 | ## Props 24 | 25 | ### `context` 26 | 27 | Provides a context value to the element tree below the outlet. Use when the parent route needs to provide values to child routes. 28 | 29 | ```tsx 30 | 31 | ``` 32 | 33 | See also: [`useOutletContext`][use-outlet-context] 34 | 35 | [use-outlet-context]: ../hooks/use-outlet-context 36 | -------------------------------------------------------------------------------- /docs/components/prefetch-page-links.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: PrefetchPageLinks 3 | toc: false 4 | --- 5 | 6 | # `` 7 | 8 | This component enables prefetching of all assets for a page to enable an instant navigation to that page. It does this by rendering `` and `` tags for all the assets (data, modules, css) of a given page. 9 | 10 | `` uses this internally, but you can render it to prefetch a page for any other reason. 11 | 12 | ```tsx 13 | 14 | ``` 15 | 16 | **Note:** You need to use an absolute path. 17 | -------------------------------------------------------------------------------- /docs/discussion/component-data.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Component Data 3 | hidden: true 4 | --- 5 | 6 | # Component Data 7 | -------------------------------------------------------------------------------- /docs/discussion/cookies-and-sessions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cookies and Sessions 3 | hidden: true 4 | --- 5 | -------------------------------------------------------------------------------- /docs/discussion/error-handling.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Error Handling 3 | hidden: true 4 | --- 5 | 6 | # Error Handling 7 | 8 | - unexpected 9 | - automatically handled 10 | - granular w/ route boundaries 11 | - granular w/ `` boundaries 12 | - expected 13 | - 404s 14 | - 401s 15 | - 503s 16 | - can send data! 17 | -------------------------------------------------------------------------------- /docs/discussion/form-validation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Form Validation 3 | hidden: true 4 | --- 5 | 6 | # Form Validation 7 | -------------------------------------------------------------------------------- /docs/discussion/formdata.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Working with FormData 3 | hidden: true 4 | --- 5 | 6 | # Working with FormData 7 | -------------------------------------------------------------------------------- /docs/discussion/html-forms.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: HTML Form APIs 3 | hidden: true 4 | --- 5 | 6 | # HTML Form APIs 7 | -------------------------------------------------------------------------------- /docs/discussion/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Discussion Topics 3 | order: 2 4 | --- 5 | -------------------------------------------------------------------------------- /docs/discussion/multiple-forms.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Multiple Forms on a Page 3 | hidden: true 4 | --- 5 | 6 | # Multiple Forms on a Page 7 | -------------------------------------------------------------------------------- /docs/discussion/nested-routes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Layouts and Nested Routes 3 | hidden: true 4 | --- 5 | 6 | # Layouts and Nested Routes 7 | -------------------------------------------------------------------------------- /docs/discussion/testing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testing 3 | hidden: true 4 | --- 5 | 6 | # Testing 7 | -------------------------------------------------------------------------------- /docs/file-conventions/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: File Conventions 3 | order: 3 4 | --- 5 | -------------------------------------------------------------------------------- /docs/guides/authentication.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Authentication 3 | hidden: true 4 | --- 5 | -------------------------------------------------------------------------------- /docs/guides/concurrent-submissions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Concurrent Submissions 3 | hidden: true 4 | --- 5 | -------------------------------------------------------------------------------- /docs/guides/debugging.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Debugging 3 | hidden: true 4 | --- 5 | 6 | TODO 7 | -------------------------------------------------------------------------------- /docs/guides/images.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Handling Images 3 | hidden: true 4 | --- 5 | -------------------------------------------------------------------------------- /docs/guides/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Guides 3 | order: 10 4 | --- 5 | -------------------------------------------------------------------------------- /docs/guides/meta.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: SEO and Meta Tags 3 | hidden: true 4 | --- 5 | -------------------------------------------------------------------------------- /docs/guides/progressive-enhancement.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Progressive Enhancement 3 | hidden: true 4 | --- 5 | 6 | # Progressive Enhancement 7 | -------------------------------------------------------------------------------- /docs/hooks/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hooks 3 | order: 6 4 | --- 5 | -------------------------------------------------------------------------------- /docs/hooks/use-async-value.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useAsyncValue 3 | new: true 4 | --- 5 | 6 | # `useAsyncValue` 7 | 8 | Returns the resolved data from the closest [``][await_component] ancestor component. 9 | 10 | ```tsx 11 | function SomeDescendant() { 12 | const value = useAsyncValue(); 13 | // ... 14 | } 15 | ``` 16 | 17 | ```tsx 18 | 19 | 20 | 21 | ``` 22 | 23 | ## Additional Resources 24 | 25 | **Guides** 26 | 27 | - [Streaming][streaming_guide] 28 | 29 | **API** 30 | 31 | - [``][await_component] 32 | - [`useAsyncError`][use_async_error] 33 | 34 | [await_component]: ../components/await 35 | [streaming_guide]: ../guides/streaming 36 | [use_async_error]: ../hooks/use-async-error 37 | -------------------------------------------------------------------------------- /docs/hooks/use-matches.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useMatches 3 | toc: false 4 | --- 5 | 6 | # `useMatches` 7 | 8 | Returns the current route matches on the page. This is useful for creating layout abstractions with your current routes. 9 | 10 | ```tsx 11 | function SomeComponent() { 12 | const matches = useMatches(); 13 | 14 | // ... 15 | } 16 | ``` 17 | 18 | `matches` has the following shape: 19 | 20 | ```ts 21 | [ 22 | { id, pathname, data, params, handle }, // root route 23 | { id, pathname, data, params, handle }, // layout route 24 | { id, pathname, data, params, handle }, // child route 25 | // etc. 26 | ]; 27 | ``` 28 | 29 | ## Additional Resources 30 | 31 | - [Breadcrumbs Guide][breadcrumbs-guide] 32 | 33 | [breadcrumbs-guide]: ../guides/breadcrumbs 34 | -------------------------------------------------------------------------------- /docs/hooks/use-outlet-context.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useOutletContext 3 | --- 4 | 5 | # `useOutletContext` 6 | 7 | Convenience API over [React Context][react-context] that returns the context value from the closest parent [``][outlet-context] component. 8 | 9 | ```tsx 10 | import { useOutletContext } from "@remix-run/react"; 11 | 12 | function Child() { 13 | const myValue = useOutletContext(); 14 | // ... 15 | } 16 | ``` 17 | 18 | ## Additional Resources 19 | 20 | - [``][outlet-context] 21 | 22 | [react-context]: https://react.dev/learn/passing-data-deeply-with-context 23 | [outlet-context]: ../components/outlet#context 24 | -------------------------------------------------------------------------------- /docs/hooks/use-outlet.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useOutlet 3 | --- 4 | 5 | # `useOutlet` 6 | 7 | Returns the element for the child route at this level of the route hierarchy. This hook is used internally by [``][outlet-component] to render child routes. 8 | 9 | ```tsx 10 | import { useOutlet } from "@remix-run/react"; 11 | ``` 12 | 13 | [outlet-component]: ../components/outlet 14 | -------------------------------------------------------------------------------- /docs/hooks/use-params.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useParams 3 | --- 4 | 5 | # `useParams` 6 | 7 | Returns an object of key/value pairs of the dynamic params from the current URL that were matched by the routes. Child routes inherit all params from their parent routes. 8 | 9 | ```tsx 10 | import { useParams } from "@remix-run/react"; 11 | 12 | function SomeComponent() { 13 | const params = useParams(); 14 | // ... 15 | } 16 | ``` 17 | 18 | Assuming a route like `routes/posts/$postId.tsx` is matched by `/posts/123` then `params.postId` will be `"123"`. Params for [splat routes][splat-routes] are available as `params["*"]`. 19 | 20 | [splat-routes]: ../file-conventions/routes#splat-routes 21 | -------------------------------------------------------------------------------- /docs/hooks/use-route-error.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useRouteError 3 | new: true 4 | --- 5 | 6 | # `useRouteError` 7 | 8 | Accesses the error thrown during an [`action`][action], [`loader`][loader], or rendering to be used in an [`ErrorBoundary`][error-boundary]. 9 | 10 | ```jsx filename=routes/some-route.tsx 11 | export function ErrorBoundary() { 12 | const error = useRouteError(); 13 | return
{error.message}
; 14 | } 15 | ``` 16 | 17 | ## Additional Resources 18 | 19 | **Guides** 20 | 21 | - [Error Handling Guide][error-handling-guide] 22 | 23 | **API Reference** 24 | 25 | - [`ErrorBoundary`][error-boundary] 26 | 27 | [action]: ../route/action 28 | [loader]: ../route/loader 29 | [error-boundary]: ../route/error-boundary 30 | [error-handling-guide]: ../guides/errors 31 | -------------------------------------------------------------------------------- /docs/hooks/use-route-loader-data.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: useRouteLoaderData 3 | toc: false 4 | --- 5 | 6 | # `useRouteLoaderData` 7 | 8 | Returns the loader data for a given route by ID. 9 | 10 | ```tsx 11 | import { useRouteLoaderData } from "@remix-run/react"; 12 | 13 | function SomeComponent() { 14 | const { user } = useRouteLoaderData("root"); 15 | } 16 | ``` 17 | 18 | Remix creates the route IDs automatically. They are simply the path of the route file relative to the app folder without the extension. 19 | 20 | | Route Filename | Route ID | 21 | | -------------------------- | -------------------- | 22 | | `app/root.tsx` | `"root"` | 23 | | `app/routes/teams.tsx` | `"routes/teams"` | 24 | | `app/routes/teams.$id.tsx` | `"routes/teams.$id"` | 25 | -------------------------------------------------------------------------------- /docs/other-api/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Other API 3 | order: 9 4 | --- 5 | -------------------------------------------------------------------------------- /docs/prettier.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Options} */ 2 | module.exports = { 3 | ...require("../prettier.config"), 4 | printWidth: 60, 5 | }; 6 | -------------------------------------------------------------------------------- /docs/route/component.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Component 3 | --- 4 | 5 | # Route Component 6 | 7 | The default export of a route module defines the component that will render when the route matches. 8 | 9 | ```tsx filename=app/routes/my-route.tsx 10 | export default function MyRouteComponent() { 11 | return ( 12 |
13 |

Look ma!

14 |

I'm still using React after like 8 years.

15 |
16 | ); 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/route/handle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: handle 3 | --- 4 | 5 | # `handle` 6 | 7 | Exporting a handle allows you to create application conventions with the [`useMatches`][use-matches] hook. You can put whatever values you want on it: 8 | 9 | ```tsx 10 | export const handle = { 11 | its: "all yours", 12 | }; 13 | ``` 14 | 15 | This is almost always used in conjunction with `useMatches`. To see what kinds of things you can do with it, refer to [`useMatches`][use-matches] for more information. 16 | 17 | ## Additional Resources 18 | 19 | - [Breadcrumbs Guide][breadcrumbs-guide] 20 | - [`useMatches`][use-matches] 21 | 22 | [use-matches]: ../hooks/use-matches 23 | [breadcrumbs-guide]: ../guides/breadcrumbs 24 | -------------------------------------------------------------------------------- /docs/route/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Route Module 3 | order: 4 4 | --- 5 | -------------------------------------------------------------------------------- /docs/start/changelog.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Changelog 3 | --- 4 | 5 | # Changelog 6 | 7 | See the detailed changelog for each release on [GitHub][changelog]. 8 | 9 | [changelog]: https://github.com/remix-run/remix/blob/main/CHANGELOG.md 10 | -------------------------------------------------------------------------------- /docs/start/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting Started 3 | order: 1 4 | --- 5 | -------------------------------------------------------------------------------- /docs/styling/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Styling 3 | order: 7 4 | --- 5 | -------------------------------------------------------------------------------- /docs/tutorials/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tutorials 3 | hidden: true 4 | --- 5 | -------------------------------------------------------------------------------- /docs/utils/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Utilities 3 | order: 6 4 | --- 5 | -------------------------------------------------------------------------------- /docs/utils/is-route-error-response.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: isRouteErrorResponse 3 | toc: false 4 | --- 5 | 6 | # `isRouteErrorResponse` 7 | 8 | This util is simply a re-export of [React Router's `isRouteErrorResponse`][rr-isrouteerrorresponse]. 9 | 10 | [rr-isrouteerrorresponse]: https://reactrouter.com/v6/utils/is-route-error-response 11 | -------------------------------------------------------------------------------- /docs/utils/replace.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: replace 3 | toc: false 4 | --- 5 | 6 | # `replace` 7 | 8 | This is a small wrapper around [`redirect`][redirect] that will trigger a client-side redirect to the new location using `history.replaceState` instead of `history.pushState`. 9 | 10 | If JavaScript has not loaded, this will behave as a standard document-level redirect and will add a new entry to the history stack. 11 | 12 | Just like [`redirect`][redirect], it accepts a status code or a `ResponseInit` as the second parameter: 13 | 14 | ```ts 15 | replace(path, 301); 16 | replace(path, 303); 17 | ``` 18 | 19 | ```ts 20 | replace(path, { 21 | headers: { 22 | "Set-Cookie": await commitSession(session), 23 | }, 24 | }); 25 | ``` 26 | 27 | [redirect]: ./redirect 28 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | Remix examples have moved into a dedicated repository. [See `remix-run/examples`](https://github.com/remix-run/examples) to browse or contribute new example projects! 2 | -------------------------------------------------------------------------------- /integration/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # integration-tests 2 | 3 | ## 0.0.0 4 | 5 | ### Minor Changes 6 | 7 | - Unstable Vite support for Node-based Remix apps ([#7590](https://github.com/remix-run/remix/pull/7590)) 8 | 9 | - `remix build` 👉 `vite build && vite build --ssr` 10 | - `remix dev` 👉 `vite dev` 11 | 12 | Other runtimes (e.g. Deno, Cloudflare) not yet supported. 13 | Custom server (e.g. Express) not yet supported. 14 | 15 | See "Future > Vite" in the Remix Docs for details. 16 | -------------------------------------------------------------------------------- /integration/assets/toupload.txt: -------------------------------------------------------------------------------- 1 | Hello, World! -------------------------------------------------------------------------------- /integration/helpers/cf-template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /dist 6 | /public/build 7 | /.mf 8 | .env 9 | -------------------------------------------------------------------------------- /integration/helpers/cf-template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/integration/helpers/cf-template/public/favicon.ico -------------------------------------------------------------------------------- /integration/helpers/cf-template/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | declare module "__STATIC_CONTENT_MANIFEST" { 6 | const manifest: string; 7 | export default manifest; 8 | } 9 | -------------------------------------------------------------------------------- /integration/helpers/cf-template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "~/*": ["./app/*"] 17 | }, 18 | 19 | // Remix takes care of building everything in `remix build`. 20 | "noEmit": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /integration/helpers/cf-template/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "remix-cloudflare-workers" 2 | 3 | workers_dev = true 4 | main = "./build/index.js" 5 | # https://developers.cloudflare.com/workers/platform/compatibility-dates 6 | compatibility_date = "2023-04-20" 7 | 8 | [site] 9 | bucket = "./public" 10 | -------------------------------------------------------------------------------- /integration/helpers/cleanup.mjs: -------------------------------------------------------------------------------- 1 | import * as path from "node:path"; 2 | import spawn from "cross-spawn"; 3 | 4 | if (process.env.CI) { 5 | console.log("Skipping cleanup in CI"); 6 | process.exit(); 7 | } 8 | 9 | const pathsToRemove = [path.resolve(process.cwd(), ".tmp/integration")]; 10 | 11 | for (let pathToRemove of pathsToRemove) { 12 | console.log(`Removing ${path.relative(process.cwd(), pathToRemove)}`); 13 | let childProcess; 14 | if (process.platform === "win32") { 15 | childProcess = spawn("rmdir", ["/s", "/q", pathToRemove], { 16 | stdio: "inherit", 17 | }); 18 | } else { 19 | childProcess = spawn("rm", ["-rf", pathToRemove], { 20 | stdio: "inherit", 21 | }); 22 | } 23 | childProcess.on("error", (err) => { 24 | console.error(err); 25 | process.exit(1); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /integration/helpers/deno-template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /integration/helpers/deno-template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/integration/helpers/deno-template/public/favicon.ico -------------------------------------------------------------------------------- /integration/helpers/deno-template/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | server: "./server.ts", 4 | serverConditions: ["deno", "worker"], 5 | serverDependenciesToBundle: "all", 6 | serverMainFields: ["module", "main"], 7 | serverModuleFormat: "esm", 8 | serverPlatform: "neutral", 9 | // appDirectory: "app", 10 | // assetsBuildDirectory: "public/build", 11 | // publicPath: "/build/", 12 | // serverBuildPath: "build/index.js", 13 | 14 | // !!! Don't adjust this without changing the code that overwrites this 15 | // in createFixtureProject() 16 | ...globalThis.INJECTED_FIXTURE_REMIX_CONFIG, 17 | }; 18 | -------------------------------------------------------------------------------- /integration/helpers/deno-template/server.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "https://deno.land/std@0.128.0/http/server.ts"; 2 | import { createRequestHandlerWithStaticFiles } from "@remix-run/deno"; 3 | // Import path interpreted by the Remix compiler 4 | import * as build from "@remix-run/dev/server-build"; 5 | 6 | const remixHandler = createRequestHandlerWithStaticFiles({ 7 | build, 8 | getLoadContext: () => ({}), 9 | }); 10 | 11 | const port = Number(Deno.env.get("PORT")) || 8000; 12 | console.log(`Listening on http://localhost:${port}`); 13 | serve(remixHandler, { port }); 14 | -------------------------------------------------------------------------------- /integration/helpers/node-template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /integration/helpers/node-template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/integration/helpers/node-template/public/favicon.ico -------------------------------------------------------------------------------- /integration/helpers/node-template/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | // appDirectory: "app", 4 | // assetsBuildDirectory: "public/build", 5 | // publicPath: "/build/", 6 | // serverBuildPath: "build/index.js", 7 | 8 | // !!! Don't adjust this without changing the code that overwrites this 9 | // in createFixtureProject() 10 | ...global.INJECTED_FIXTURE_REMIX_CONFIG, 11 | }; 12 | -------------------------------------------------------------------------------- /integration/helpers/node-template/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /integration/helpers/node-template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "~/*": ["./app/*"] 17 | }, 18 | 19 | // Remix takes care of building everything in `remix build`. 20 | "noEmit": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /integration/helpers/vite-5-template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | -------------------------------------------------------------------------------- /integration/helpers/vite-5-template/app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | Meta, 4 | Outlet, 5 | Scripts, 6 | ScrollRestoration, 7 | } from "@remix-run/react"; 8 | 9 | export default function App() { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /integration/helpers/vite-5-template/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /integration/helpers/vite-5-template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/integration/helpers/vite-5-template/public/favicon.ico -------------------------------------------------------------------------------- /integration/helpers/vite-5-template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "module": "ESNext", 9 | "moduleResolution": "Bundler", 10 | "resolveJsonModule": true, 11 | "target": "ES2022", 12 | "strict": true, 13 | "allowJs": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | "noEmit": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /integration/helpers/vite-5-template/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | export default defineConfig({ 6 | plugins: [remix(), tsconfigPaths()], 7 | }); 8 | -------------------------------------------------------------------------------- /integration/helpers/vite-6-template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | -------------------------------------------------------------------------------- /integration/helpers/vite-6-template/app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | Meta, 4 | Outlet, 5 | Scripts, 6 | ScrollRestoration, 7 | } from "@remix-run/react"; 8 | 9 | export default function App() { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /integration/helpers/vite-6-template/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /integration/helpers/vite-6-template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/integration/helpers/vite-6-template/public/favicon.ico -------------------------------------------------------------------------------- /integration/helpers/vite-6-template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "module": "ESNext", 9 | "moduleResolution": "Bundler", 10 | "resolveJsonModule": true, 11 | "target": "ES2022", 12 | "strict": true, 13 | "allowJs": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | "noEmit": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /integration/helpers/vite-6-template/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | export default defineConfig({ 6 | plugins: [remix(), tsconfigPaths()], 7 | }); 8 | -------------------------------------------------------------------------------- /integration/helpers/vite-cloudflare-template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | -------------------------------------------------------------------------------- /integration/helpers/vite-cloudflare-template/app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | Meta, 4 | Outlet, 5 | Scripts, 6 | ScrollRestoration, 7 | } from "@remix-run/react"; 8 | 9 | export default function App() { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /integration/helpers/vite-cloudflare-template/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /integration/helpers/vite-cloudflare-template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/integration/helpers/vite-cloudflare-template/public/favicon.ico -------------------------------------------------------------------------------- /integration/helpers/vite-cloudflare-template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "module": "ESNext", 9 | "moduleResolution": "Bundler", 10 | "resolveJsonModule": true, 11 | "target": "ES2022", 12 | "strict": true, 13 | "allowJs": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | "noEmit": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /integration/helpers/vite-cloudflare-template/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | export default defineConfig({ 6 | plugins: [remix(), tsconfigPaths()], 7 | }); 8 | -------------------------------------------------------------------------------- /integration/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["helpers/*-template"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "moduleResolution": "Bundler", 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "resolveJsonModule": true, 14 | 15 | "noEmit": true, 16 | 17 | "rootDir": "." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /jest/buildRemix.js: -------------------------------------------------------------------------------- 1 | import * as path from "node:path"; 2 | import { spawn } from "cross-spawn"; 3 | 4 | function buildRemix(dir) { 5 | return new Promise((accept, reject) => { 6 | spawn("pnpm", ["build"], { 7 | stdio: "inherit", 8 | cwd: dir, 9 | }) 10 | .on("error", reject) 11 | .on("close", accept); 12 | }); 13 | } 14 | 15 | export default async function () { 16 | let rootDir = path.dirname(__dirname); 17 | await buildRemix(rootDir); 18 | } 19 | -------------------------------------------------------------------------------- /jest/transform.js: -------------------------------------------------------------------------------- 1 | let { default: babelJest } = require("babel-jest"); 2 | 3 | let baseConfig = require("../babel.config.js"); 4 | 5 | /** 6 | * Replace `import.meta` with `undefined` 7 | * 8 | * Needed to support server-side CJS in Jest 9 | * that access `@remix-run/react`, where `import.meta.hot` 10 | * is used for HMR. 11 | */ 12 | let metaPlugin = ({ types: t }) => ({ 13 | visitor: { 14 | MetaProperty: (path) => { 15 | path.replaceWith(t.identifier("undefined")); 16 | }, 17 | }, 18 | }); 19 | 20 | module.exports = babelJest.createTransformer({ 21 | babelrc: false, 22 | ...baseConfig, 23 | plugins: [...baseConfig.plugins, metaPlugin], 24 | }); 25 | -------------------------------------------------------------------------------- /packages/ADDING_A_PACKAGE.md: -------------------------------------------------------------------------------- 1 | # How to add a package 2 | 3 | - [ ] add folder and make sure it's a unique "name" field in `package.json` 4 | - [ ] add to root package.json `packages` array 5 | - [ ] update rollup config to build the package 6 | - [ ] add root `tsconfig.json` entry and make sure pkg tsconfig is proper output dir 7 | - [ ] add to publish scripts 8 | - [ ] update version script 9 | - [ ] update `.changeset/config.json` to include the package 10 | -------------------------------------------------------------------------------- /packages/create-remix/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: "../../.eslintrc.js", 3 | rules: { 4 | // we have an example where we need this 5 | "no-undef": 0, 6 | }, 7 | overrides: [ 8 | { 9 | files: ["rollup.config.js"], 10 | rules: { 11 | "no-undef": 2, 12 | }, 13 | }, 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /packages/create-remix/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/arc.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/create-remix/__tests__/fixtures/arc.tar.gz -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/arc.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/create-remix/__tests__/fixtures/arc.tgz -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/blank/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/examples-main.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/create-remix/__tests__/fixtures/examples-main.tar.gz -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/failing-remix-init/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/failing-remix-init/remix.init/index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | throw new Error("💣"); 3 | }; 4 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/nested-dir-repo.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/create-remix/__tests__/fixtures/nested-dir-repo.tar.gz -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/remix-repo.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/create-remix/__tests__/fixtures/remix-repo.tar.gz -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/create-remix/__tests__/fixtures/stack.tar.gz -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | From your terminal: 8 | 9 | ```sh 10 | npm run dev 11 | ``` 12 | 13 | This starts your app in development mode, rebuilding assets on file changes. 14 | 15 | ## Deployment 16 | 17 | First, build your app for production: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then run the app in production mode: 24 | 25 | ```sh 26 | npm start 27 | ``` 28 | 29 | Now you'll need to pick a host to deploy it to. 30 | 31 | ### DIY 32 | 33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready. 34 | 35 | Make sure to deploy the output of `remix build` 36 | 37 | - `build/` 38 | - `public/build/` 39 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | import { RemixBrowser } from "@remix-run/react"; 2 | import { hydrate } from "react-dom"; 3 | 4 | hydrate(, document); 5 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/app/entry.server.tsx: -------------------------------------------------------------------------------- 1 | import type { EntryContext } from "@remix-run/node"; 2 | import { RemixServer } from "@remix-run/react"; 3 | import { renderToString } from "react-dom/server"; 4 | 5 | export default function handleRequest( 6 | request: Request, 7 | responseStatusCode: number, 8 | responseHeaders: Headers, 9 | remixContext: EntryContext 10 | ) { 11 | // eslint-disable-next-line testing-library/render-result-naming-convention 12 | let markup = renderToString( 13 | 14 | ); 15 | 16 | responseHeaders.set("Content-Type", "text/html"); 17 | 18 | return new Response("" + markup, { 19 | status: responseStatusCode, 20 | headers: responseHeaders, 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | LiveReload, 4 | Meta, 5 | Outlet, 6 | Scripts, 7 | ScrollRestoration, 8 | } from "@remix-run/react"; 9 | 10 | export default function App() { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/app/utils.ts: -------------------------------------------------------------------------------- 1 | // this is a utility file 2 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix-template-remix", 3 | "private": true, 4 | "sideEffects": false, 5 | "scripts": { 6 | "build": "remix build", 7 | "dev": "remix dev", 8 | "start": "remix-serve build/index.js" 9 | }, 10 | "dependencies": { 11 | "@remix-run/react": "*", 12 | "not-remix": "*", 13 | "remix": "*" 14 | }, 15 | "devDependencies": {}, 16 | "engines": { 17 | "node": ">=18.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/create-remix/__tests__/fixtures/stack/public/favicon.ico -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | serverBuildTarget: "node-cjs", 4 | // appDirectory: "app", 5 | // assetsBuildDirectory: "public/build", 6 | // serverBuildPath: "build/index.js", 7 | // publicPath: "/build/", 8 | }; 9 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/remix.init/index.js: -------------------------------------------------------------------------------- 1 | // this is the init file 2 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/stack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 7 | "isolatedModules": true, 8 | "esModuleInterop": true, 9 | "jsx": "react-jsx", 10 | "moduleResolution": "Bundler", 11 | "resolveJsonModule": true, 12 | "target": "ES2022", 13 | "strict": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "~/*": ["./app/*"] 17 | }, 18 | 19 | // Remix takes care of building everything in `remix build`. 20 | "noEmit": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/successful-remix-init/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/successful-remix-init/remix.init/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("node:fs"); 2 | const path = require("node:path"); 3 | 4 | module.exports = ({ rootDirectory }) => { 5 | fs.writeFileSync( 6 | path.join(rootDirectory, "test.txt"), 7 | "added via remix.init" 8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/tar.js: -------------------------------------------------------------------------------- 1 | const tar = require("tar-fs"); 2 | const fs = require("node:fs"); 3 | const path = require("node:path"); 4 | 5 | let files = fs.readdirSync(__dirname); 6 | let dirs = files.filter((file) => 7 | fs.statSync(path.join(__dirname, file)).isDirectory() 8 | ); 9 | 10 | for (let dir of dirs) { 11 | let fullPath = path.join(__dirname, dir); 12 | console.log(`Creating archive for ${fullPath}`); 13 | tar 14 | .pack(fullPath, { 15 | map(header) { 16 | header.name = dir + "/" + header.name; 17 | return header; 18 | }, 19 | }) 20 | .pipe(fs.createWriteStream(path.join(__dirname, `${dir}.tar.gz`))); 21 | } 22 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/fixtures/with-ignored-dir/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/msw-register.ts: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | 3 | import { server } from "./msw"; 4 | 5 | server.listen({ onUnhandledRequest: "error" }); 6 | 7 | process.on("exit", () => { 8 | server.close(); 9 | }); 10 | -------------------------------------------------------------------------------- /packages/create-remix/__tests__/setupAfterEnv.ts: -------------------------------------------------------------------------------- 1 | export let jestTimeout = process.platform === "win32" ? 20_000 : 10_000; 2 | 3 | jest.setTimeout(jestTimeout); 4 | -------------------------------------------------------------------------------- /packages/create-remix/cli.ts: -------------------------------------------------------------------------------- 1 | import process from "node:process"; 2 | 3 | import { createRemix } from "./index"; 4 | 5 | process.on("SIGINT", () => process.exit(0)); 6 | process.on("SIGTERM", () => process.exit(0)); 7 | 8 | let argv = process.argv.slice(2).filter((arg) => arg !== "--"); 9 | 10 | createRemix(argv).then( 11 | () => process.exit(0), 12 | () => process.exit(1) 13 | ); 14 | -------------------------------------------------------------------------------- /packages/create-remix/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "create-remix", 5 | setupFilesAfterEnv: ["/__tests__/setupAfterEnv.ts"], 6 | setupFiles: [], 7 | }; 8 | -------------------------------------------------------------------------------- /packages/create-remix/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts", "./package.json"], 3 | "exclude": ["dist", "**/node_modules/**", "__tests__"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "moduleResolution": "Bundler", 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "resolveJsonModule": true, 14 | "declaration": true, 15 | "emitDeclarationOnly": true, 16 | "rootDir": ".", 17 | "outDir": "../../build/node_modules/create-remix/dist" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix-architect/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-architect/__tests__/554828.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-architect/__tests__/554828.jpeg -------------------------------------------------------------------------------- /packages/remix-architect/__tests__/binaryTypes-test.ts: -------------------------------------------------------------------------------- 1 | import { isBinaryType } from "../binaryTypes"; 2 | 3 | describe("architect isBinaryType", () => { 4 | it("should detect binary contentType correctly", () => { 5 | expect(isBinaryType(undefined)).toBe(false); 6 | expect(isBinaryType(null)).toBe(false); 7 | expect(isBinaryType("text/html; charset=utf-8")).toBe(false); 8 | expect(isBinaryType("application/octet-stream")).toBe(true); 9 | expect(isBinaryType("application/octet-stream; charset=test")).toBe(true); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/remix-architect/__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | import { installGlobals } from "@remix-run/node"; 2 | installGlobals({ nativeFetch: true }); 3 | -------------------------------------------------------------------------------- /packages/remix-architect/index.ts: -------------------------------------------------------------------------------- 1 | export { createArcTableSessionStorage } from "./sessions/arcTableSessionStorage"; 2 | 3 | export type { GetLoadContextFunction, RequestHandler } from "./server"; 4 | export { createRequestHandler } from "./server"; 5 | -------------------------------------------------------------------------------- /packages/remix-architect/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "architect", 5 | }; 6 | -------------------------------------------------------------------------------- /packages/remix-architect/rollup.config.js: -------------------------------------------------------------------------------- 1 | const { getAdapterConfig } = require("../../rollup.utils"); 2 | 3 | /** @returns {import("rollup").RollupOptions[]} */ 4 | module.exports = function rollup() { 5 | return [getAdapterConfig("architect")]; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/remix-architect/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "skipLibCheck": true, 8 | 9 | "moduleResolution": "Bundler", 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "declaration": true, 13 | "emitDeclarationOnly": true, 14 | "rootDir": ".", 15 | "outDir": "../../build/node_modules/@remix-run/architect/dist" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/remix-cloudflare-pages/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-cloudflare-pages/index.ts: -------------------------------------------------------------------------------- 1 | export type { 2 | createPagesFunctionHandlerParams, 3 | GetLoadContextFunction, 4 | RequestHandler, 5 | } from "./worker"; 6 | export { createPagesFunctionHandler, createRequestHandler } from "./worker"; 7 | -------------------------------------------------------------------------------- /packages/remix-cloudflare-pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["ES2022"], 6 | "target": "ES2022", 7 | "types": ["@cloudflare/workers-types"], 8 | 9 | "moduleResolution": "Bundler", 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "declaration": true, 13 | "emitDeclarationOnly": true, 14 | "rootDir": ".", 15 | "outDir": "../../build/node_modules/@remix-run/cloudflare-pages/dist", 16 | 17 | // Avoid naming conflicts between history and react-router-dom relying on 18 | // lib.dom.d.ts Window and this being a WebWorker env. 19 | "skipLibCheck": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/remix-cloudflare-workers/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-cloudflare-workers/index.ts: -------------------------------------------------------------------------------- 1 | export type { GetLoadContextFunction, RequestHandler } from "./worker"; 2 | export { 3 | createEventHandler, 4 | createRequestHandler, 5 | handleAsset, 6 | } from "./worker"; 7 | -------------------------------------------------------------------------------- /packages/remix-cloudflare-workers/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["ES2022"], 6 | "target": "ES2022", 7 | "types": ["@cloudflare/workers-types"], 8 | 9 | "moduleResolution": "Bundler", 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "declaration": true, 13 | "emitDeclarationOnly": true, 14 | "rootDir": ".", 15 | "outDir": "../../build/node_modules/@remix-run/cloudflare-workers/dist", 16 | 17 | // Avoid naming conflicts between history and react-router-dom relying on 18 | // lib.dom.d.ts Window and this being a WebWorker env. 19 | "skipLibCheck": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/remix-cloudflare/globals.ts: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/a/59499895 2 | export {}; 3 | 4 | declare global { 5 | interface ProcessEnv { 6 | NODE_ENV: "development" | "production" | "test"; 7 | } 8 | 9 | interface WorkerGlobalScope { 10 | process: { env: ProcessEnv }; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/remix-cloudflare/implementations.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createCookieFactory, 3 | createCookieSessionStorageFactory, 4 | createMemorySessionStorageFactory, 5 | createSessionStorageFactory, 6 | } from "@remix-run/server-runtime"; 7 | 8 | import { sign, unsign } from "./crypto"; 9 | 10 | export const createCookie = createCookieFactory({ sign, unsign }); 11 | export const createCookieSessionStorage = 12 | createCookieSessionStorageFactory(createCookie); 13 | export const createSessionStorage = createSessionStorageFactory(createCookie); 14 | export const createMemorySessionStorage = 15 | createMemorySessionStorageFactory(createSessionStorage); 16 | -------------------------------------------------------------------------------- /packages/remix-cloudflare/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["ES2022"], 6 | "target": "ES2022", 7 | "types": ["@cloudflare/workers-types"], 8 | 9 | "moduleResolution": "Bundler", 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "declaration": true, 13 | "emitDeclarationOnly": true, 14 | "rootDir": ".", 15 | "outDir": "../../build/node_modules/@remix-run/cloudflare/dist", 16 | 17 | // Avoid naming conflicts between history and react-router-dom relying on 18 | // lib.dom.d.ts Window and this being a WebWorker env. 19 | "skipLibCheck": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/remix-css-bundle/README.md: -------------------------------------------------------------------------------- 1 | # @remix-run/css-bundle 2 | 3 | This package provides access to the `href` of the generated CSS file when using CSS bundling features in [Remix](https://remix.run). 4 | 5 | ```sh 6 | npm install @remix-run/css-bundle 7 | ``` 8 | 9 | For more, see the [Remix docs](https://remix.run/docs). 10 | -------------------------------------------------------------------------------- /packages/remix-css-bundle/index.ts: -------------------------------------------------------------------------------- 1 | // This file's contents are replaced by `cssBundlePlugin`. This file only exists 2 | // to provide type definitions and a graceful fallback when importing this 3 | // package outside of the Remix compiler. 4 | export const cssBundleHref: string | undefined = undefined; 5 | -------------------------------------------------------------------------------- /packages/remix-css-bundle/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@remix-run/css-bundle", 3 | "version": "2.16.7", 4 | "description": "CSS bundle href when using CSS bundling features in Remix", 5 | "homepage": "https://remix.run", 6 | "bugs": { 7 | "url": "https://github.com/remix-run/remix/issues" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/remix-run/remix", 12 | "directory": "packages/remix-css-bundle" 13 | }, 14 | "license": "MIT", 15 | "main": "./dist/index.js", 16 | "module": "./dist/esm/index.js", 17 | "typings": "./dist/index.d.ts", 18 | "scripts": { 19 | "tsc": "tsc" 20 | }, 21 | "engines": { 22 | "node": ">=18.0.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/remix-css-bundle/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "moduleResolution": "Bundler", 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "declaration": true, 12 | "emitDeclarationOnly": true, 13 | "skipLibCheck": true, 14 | "resolveJsonModule": true, 15 | "outDir": "../../build/node_modules/@remix-run/css-bundle/dist", 16 | "rootDir": "." 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/remix-deno/.empty.js: -------------------------------------------------------------------------------- 1 | /* 2 | Intentionally left empty as a dummy input for Rollup. 3 | 4 | This package should not be bundled by Rollup as its source 5 | code is a Deno module, not an NPM package. 6 | */ 7 | -------------------------------------------------------------------------------- /packages/remix-deno/README.md: -------------------------------------------------------------------------------- 1 | # @remix-run/deno 2 | 3 | This package contains a Deno module that provides abstractions for Remix. 4 | 5 | For more, see the [Remix docs](https://remix.run/docs). 6 | 7 | ## Install 8 | 9 | Installation is done via `npm`, but the code itself is Deno source code. Read 10 | more about 11 | [why we use `npm` to manage dependencies for Deno projects](https://github.com/remix-run/remix/blob/main/decisions/0001-use-npm-to-manage-npm-dependencies-for-deno-projects.md) 12 | in Remix. 13 | 14 | ```sh 15 | npm install @remix-run/deno 16 | ``` 17 | -------------------------------------------------------------------------------- /packages/remix-deno/globals.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Remix provides `process.env.NODE_ENV` at compile time. 3 | Declare types for `process` here so that they are available in Deno. 4 | */ 5 | 6 | interface ProcessEnv { 7 | NODE_ENV: "development" | "production" | "test"; 8 | } 9 | interface Process { 10 | env: ProcessEnv; 11 | } 12 | // deno-lint-ignore no-unused-vars no-var 13 | var process: Process; 14 | -------------------------------------------------------------------------------- /packages/remix-deno/implementations.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createCookieFactory, 3 | createCookieSessionStorageFactory, 4 | createMemorySessionStorageFactory, 5 | createSessionStorageFactory, 6 | } from "@remix-run/server-runtime"; 7 | 8 | import { sign, unsign } from "./crypto.ts"; 9 | 10 | export const createCookie = createCookieFactory({ sign, unsign }); 11 | export const createCookieSessionStorage = createCookieSessionStorageFactory( 12 | createCookie, 13 | ); 14 | export const createSessionStorage = createSessionStorageFactory(createCookie); 15 | export const createMemorySessionStorage = createMemorySessionStorageFactory( 16 | createSessionStorage, 17 | ); 18 | -------------------------------------------------------------------------------- /packages/remix-dev/.gitignore: -------------------------------------------------------------------------------- 1 | server-build.js 2 | server-build.d.ts 3 | -------------------------------------------------------------------------------- /packages/remix-dev/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /functions/\[\[path\]\].js 5 | /functions/\[\[path\]\].js.map 6 | /public/build 7 | .dev.vars 8 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/.node-version: -------------------------------------------------------------------------------- 1 | 16.13.0 -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/public/_headers: -------------------------------------------------------------------------------- 1 | /favicon.ico 2 | Cache-Control: public, max-age=3600, s-maxage=3600 3 | /build/* 4 | Cache-Control: public, max-age=31536000, immutable 5 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/public/_routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "include": ["/*"], 4 | "exclude": ["/favicon.ico", "/build/*"] 5 | } 6 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-dev/__tests__/fixtures/cloudflare/public/favicon.ico -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | server: "./server.ts", 4 | serverBuildPath: "functions/[[path]].js", 5 | serverConditions: ["workerd", "worker", "browser"], 6 | serverDependenciesToBundle: "all", 7 | serverMainFields: ["browser", "module", "main"], 8 | serverMinify: true, 9 | serverModuleFormat: "esm", 10 | serverPlatform: "neutral", 11 | // appDirectory: "app", 12 | // assetsBuildDirectory: "public/build", 13 | // publicPath: "/build/", 14 | }; 15 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/server.ts: -------------------------------------------------------------------------------- 1 | import { logDevReady } from "@remix-run/cloudflare"; 2 | import { createPagesFunctionHandler } from "@remix-run/cloudflare-pages"; 3 | import * as build from "@remix-run/dev/server-build"; 4 | 5 | if (process.env.NODE_ENV === "development") { 6 | logDevReady(build); 7 | } 8 | 9 | export const onRequest = createPagesFunctionHandler({ build }); 10 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/cloudflare/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "~/*": ["./app/*"] 17 | }, 18 | 19 | // Remix takes care of building everything in `remix build`. 20 | "noEmit": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/deno/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/deno/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["denoland.vscode-deno"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/deno/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.lint": true 4 | } 5 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/deno/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "importMap": ".vscode/resolve_npm_imports.json", 3 | "compilerOptions": { 4 | "lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/deno/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-dev/__tests__/fixtures/deno/public/favicon.ico -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/deno/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | server: "./server.ts", 4 | serverConditions: ["deno", "worker"], 5 | serverDependenciesToBundle: "all", 6 | serverMainFields: ["module", "main"], 7 | serverModuleFormat: "esm", 8 | serverPlatform: "neutral", 9 | // appDirectory: "app", 10 | // assetsBuildDirectory: "public/build", 11 | // publicPath: "/build/", 12 | // serverBuildPath: "build/index.js", 13 | }; 14 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/deno/server.ts: -------------------------------------------------------------------------------- 1 | import { serve } from "https://deno.land/std@0.128.0/http/server.ts"; 2 | import { createRequestHandlerWithStaticFiles } from "@remix-run/deno"; 3 | // Import path interpreted by the Remix compiler 4 | import * as build from "@remix-run/dev/server-build"; 5 | 6 | const remixHandler = createRequestHandlerWithStaticFiles({ 7 | build, 8 | getLoadContext: () => ({}), 9 | }); 10 | 11 | const port = Number(Deno.env.get("PORT")) || 8000; 12 | console.log(`Listening on http://localhost:${port}`); 13 | serve(remixHandler, { port }); 14 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/examples-main.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-dev/__tests__/fixtures/examples-main.tar.gz -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/failing-remix-init/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/failing-remix-init/remix.init/index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | throw new Error("💣"); 3 | }; 4 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/nested-dir-repo.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-dev/__tests__/fixtures/nested-dir-repo.tar.gz -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/node/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/node/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | From your terminal: 8 | 9 | ```sh 10 | npm run dev 11 | ``` 12 | 13 | This starts your app in development mode, rebuilding assets on file changes. 14 | 15 | ## Deployment 16 | 17 | First, build your app for production: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then run the app in production mode: 24 | 25 | ```sh 26 | npm start 27 | ``` 28 | 29 | Now you'll need to pick a host to deploy it to. 30 | 31 | ### DIY 32 | 33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready. 34 | 35 | Make sure to deploy the output of `remix build` 36 | 37 | - `build/` 38 | - `public/build/` 39 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "sideEffects": false, 4 | "type": "module", 5 | "scripts": { 6 | "build": "remix build", 7 | "dev": "remix dev", 8 | "start": "remix-serve build/index.js", 9 | "typecheck": "tsc" 10 | }, 11 | "dependencies": { 12 | "@remix-run/css-bundle": "*", 13 | "@remix-run/node": "*", 14 | "@remix-run/react": "*", 15 | "@remix-run/serve": "*", 16 | "isbot": "^4.1.0", 17 | "react": "^18.2.0", 18 | "react-dom": "^18.2.0" 19 | }, 20 | "devDependencies": { 21 | "@remix-run/dev": "*", 22 | "@types/react": "^18.2.20", 23 | "@types/react-dom": "^18.2.7", 24 | "eslint": "^8.38.0", 25 | "typescript": "^5.1.6" 26 | }, 27 | "engines": { 28 | "node": ">=18.0.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/node/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-dev/__tests__/fixtures/node/public/favicon.ico -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/node/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | // appDirectory: "app", 4 | // assetsBuildDirectory: "public/build", 5 | // publicPath: "/build/", 6 | // serverBuildPath: "build/index.js", 7 | }; 8 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/node/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "~/*": ["./app/*"] 17 | }, 18 | 19 | // Remix takes care of building everything in `remix build`. 20 | "noEmit": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/remix-repo.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-dev/__tests__/fixtures/remix-repo.tar.gz -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-dev/__tests__/fixtures/stack.tar.gz -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | From your terminal: 8 | 9 | ```sh 10 | npm run dev 11 | ``` 12 | 13 | This starts your app in development mode, rebuilding assets on file changes. 14 | 15 | ## Deployment 16 | 17 | First, build your app for production: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then run the app in production mode: 24 | 25 | ```sh 26 | npm start 27 | ``` 28 | 29 | Now you'll need to pick a host to deploy it to. 30 | 31 | ### DIY 32 | 33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready. 34 | 35 | Make sure to deploy the output of `remix build` 36 | 37 | - `build/` 38 | - `public/build/` 39 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | import { RemixBrowser } from "@remix-run/react"; 2 | import { hydrate } from "react-dom"; 3 | 4 | hydrate(, document); 5 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | LiveReload, 4 | Meta, 5 | Outlet, 6 | Scripts, 7 | ScrollRestoration, 8 | } from "@remix-run/react"; 9 | 10 | export default function App() { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/app/utils.ts: -------------------------------------------------------------------------------- 1 | // this is a utility file 2 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix-template-remix", 3 | "private": true, 4 | "sideEffects": false, 5 | "scripts": { 6 | "build": "remix build", 7 | "dev": "remix dev", 8 | "start": "remix-serve build/index.js" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": {}, 12 | "engines": { 13 | "node": ">=18.0.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/packages/remix-dev/__tests__/fixtures/stack/public/favicon.ico -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | // appDirectory: "app", 4 | // assetsBuildDirectory: "public/build", 5 | // serverBuildPath: "build/index.js", 6 | // publicPath: "/build/", 7 | }; 8 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/remix.init/index.js: -------------------------------------------------------------------------------- 1 | // this is the init file 2 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/stack/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 7 | "isolatedModules": true, 8 | "esModuleInterop": true, 9 | "jsx": "react-jsx", 10 | "moduleResolution": "Bundler", 11 | "resolveJsonModule": true, 12 | "target": "ES2022", 13 | "strict": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "~/*": ["./app/*"] 17 | }, 18 | 19 | // Remix takes care of building everything in `remix build`. 20 | "noEmit": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/successful-remix-init/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/successful-remix-init/remix.init/index.js: -------------------------------------------------------------------------------- 1 | const fs = require("node:fs"); 2 | const path = require("node:path"); 3 | 4 | module.exports = ({ rootDirectory }) => { 5 | fs.writeFileSync( 6 | path.join(rootDirectory, "test.txt"), 7 | "added via remix.init" 8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/fixtures/tar.js: -------------------------------------------------------------------------------- 1 | const tar = require("tar-fs"); 2 | const fs = require("node:fs"); 3 | const path = require("node:path"); 4 | 5 | let files = fs.readdirSync(__dirname); 6 | let dirs = files.filter((file) => 7 | fs.statSync(path.join(__dirname, file)).isDirectory() 8 | ); 9 | 10 | for (let dir of dirs) { 11 | let fullPath = path.join(__dirname, dir); 12 | console.log(`Creating archive for ${fullPath}`); 13 | tar 14 | .pack(fullPath, { 15 | map(header) { 16 | header.name = dir + "/" + header.name; 17 | return header; 18 | }, 19 | }) 20 | .pipe(fs.createWriteStream(path.join(__dirname, `${dir}.tar.gz`))); 21 | } 22 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/setupAfterEnv.ts: -------------------------------------------------------------------------------- 1 | export let jestTimeout = process.platform === "win32" ? 20_000 : 10_000; 2 | 3 | jest.setTimeout(jestTimeout); 4 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/utils/captureError.ts: -------------------------------------------------------------------------------- 1 | class NoErrorThrownError extends Error {} 2 | 3 | export default async ( 4 | erroring: Promise | (() => Promise) 5 | ) => { 6 | try { 7 | let promise = typeof erroring === "function" ? erroring() : erroring; 8 | await promise; 9 | throw new NoErrorThrownError(); 10 | } catch (error: unknown) { 11 | if (error instanceof NoErrorThrownError) throw error; 12 | return error; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/utils/eol.ts: -------------------------------------------------------------------------------- 1 | export const normalize = (text: string, normalized = "\n") => 2 | text.replace(/\r?\n/g, normalized); 3 | -------------------------------------------------------------------------------- /packages/remix-dev/__tests__/utils/git.ts: -------------------------------------------------------------------------------- 1 | import execa from "execa"; 2 | 3 | export const initialCommit = async (projectDir: string) => { 4 | let run = (cmd: string, args: string[]) => 5 | execa(cmd, args, { cwd: projectDir }); 6 | let commands = [ 7 | ["init"], 8 | 9 | ["config", "user.name", '"github-actions[bot]"'], 10 | ["config", "user.email", '"github-actions[bot]@users.noreply.github.com"'], 11 | 12 | ["add", "."], 13 | ["commit", "--message", '"initial commit"'], 14 | ]; 15 | for (let command of commands) { 16 | await run("git", command); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /packages/remix-dev/assets-manifest.d.ts: -------------------------------------------------------------------------------- 1 | import type { AssetsManifest } from "@remix-run/dev"; 2 | 3 | declare const manifest: AssetsManifest; 4 | 5 | export type { AssetsManifest }; 6 | export default manifest; 7 | -------------------------------------------------------------------------------- /packages/remix-dev/cache.ts: -------------------------------------------------------------------------------- 1 | import { put, get } from "cacache"; 2 | 3 | export const putJson = async (cachePath: string, key: string, data: any) => 4 | put(cachePath, key, JSON.stringify(data)); 5 | 6 | export const getJson = async (cachePath: string, key: string) => 7 | get(cachePath, key).then((obj) => JSON.parse(obj.data.toString("utf-8"))); 8 | -------------------------------------------------------------------------------- /packages/remix-dev/cli.ts: -------------------------------------------------------------------------------- 1 | import { cli } from "./index"; 2 | 3 | cli.run().then( 4 | () => { 5 | process.exit(0); 6 | }, 7 | (error: unknown) => { 8 | if (error) console.error(error); 9 | process.exit(1); 10 | } 11 | ); 12 | -------------------------------------------------------------------------------- /packages/remix-dev/cli/index.ts: -------------------------------------------------------------------------------- 1 | export { run } from "./run"; 2 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/analysis.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | import path from "node:path"; 3 | import type { Metafile } from "esbuild"; 4 | 5 | import type { Context } from "./context"; 6 | 7 | export let writeMetafile = ( 8 | ctx: Context, 9 | filename: string, 10 | metafile: Metafile 11 | ) => { 12 | let buildDir = path.dirname(ctx.config.serverBuildPath); 13 | fs.outputFileSync(path.join(buildDir, filename), JSON.stringify(metafile)); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/build.ts: -------------------------------------------------------------------------------- 1 | import * as Compiler from "./compiler"; 2 | import type { Context } from "./context"; 3 | 4 | export async function build(ctx: Context): Promise { 5 | let compiler = await Compiler.create(ctx); 6 | await compiler.compile(); 7 | } 8 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/cancel.ts: -------------------------------------------------------------------------------- 1 | export const CANCEL_PREFIX = "remix-compile-cancel"; 2 | 3 | export class Cancel extends Error { 4 | constructor(message: string) { 5 | super(`${CANCEL_PREFIX}: ${message}`); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/context.ts: -------------------------------------------------------------------------------- 1 | import type { RemixConfig } from "../config"; 2 | import type { Logger } from "../tux"; 3 | import type { FileWatchCache } from "./fileWatchCache"; 4 | import type { Options } from "./options"; 5 | 6 | export type Context = { 7 | config: RemixConfig; 8 | options: Options; 9 | fileWatchCache: FileWatchCache; 10 | logger: Logger; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/css/index.ts: -------------------------------------------------------------------------------- 1 | export { create as createCompiler } from "./compiler"; 2 | export { write as writeBundle } from "./bundle"; 3 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/index.ts: -------------------------------------------------------------------------------- 1 | export { build } from "./build"; 2 | export { type WatchOptions, watch } from "./watch"; 3 | 4 | export { type Options as CompileOptions } from "./options"; 5 | export { logThrown } from "./utils/log"; 6 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/js/index.ts: -------------------------------------------------------------------------------- 1 | export { create as createCompiler } from "./compiler"; 2 | export { write } from "./write"; 3 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/js/write.ts: -------------------------------------------------------------------------------- 1 | import * as path from "node:path"; 2 | import type { OutputFile } from "esbuild"; 3 | import fse from "fs-extra"; 4 | 5 | import type { RemixConfig } from "../../config"; 6 | 7 | export async function write(config: RemixConfig, outputFiles: OutputFile[]) { 8 | await fse.ensureDir(path.dirname(config.assetsBuildDirectory)); 9 | 10 | for (let file of outputFiles) { 11 | await fse.ensureDir(path.dirname(file.path)); 12 | await fse.writeFile(file.path, file.contents); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/options.ts: -------------------------------------------------------------------------------- 1 | type Mode = "development" | "production" | "test"; 2 | 3 | export type Options = { 4 | mode: Mode | Omit; 5 | sourcemap: boolean; 6 | 7 | REMIX_DEV_ORIGIN?: URL; // TODO: required in v2 8 | }; 9 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/plugins/absoluteCssUrlsPlugin.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import type { Plugin, PluginBuild } from "esbuild"; 3 | 4 | /** 5 | * This plugin treats absolute paths in 'url()' css rules as external to prevent 6 | * breaking changes 7 | */ 8 | export const absoluteCssUrlsPlugin = (): Plugin => { 9 | return { 10 | name: "absolute-css-urls-plugin", 11 | setup: async (build: PluginBuild) => { 12 | build.onResolve({ filter: /.*/ }, async (args) => { 13 | let { kind, path: resolvePath } = args; 14 | if (kind === "url-token" && path.isAbsolute(resolvePath)) { 15 | return { 16 | path: resolvePath, 17 | external: true, 18 | }; 19 | } 20 | }); 21 | }, 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/plugins/external.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from "esbuild"; 2 | 3 | export const externalPlugin = ( 4 | filter: RegExp, 5 | options: { 6 | sideEffects?: boolean; 7 | } = {} 8 | ): Plugin => { 9 | return { 10 | name: "external", 11 | setup(build) { 12 | build.onResolve({ filter }, () => { 13 | return { external: true, sideEffects: options.sideEffects }; 14 | }); 15 | }, 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/server/index.ts: -------------------------------------------------------------------------------- 1 | export { create as createCompiler } from "./compiler"; 2 | export { write } from "./write"; 3 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/server/virtualModules.ts: -------------------------------------------------------------------------------- 1 | interface VirtualModule { 2 | id: string; 3 | filter: RegExp; 4 | } 5 | 6 | export const serverBuildVirtualModule: VirtualModule = { 7 | id: "@remix-run/dev/server-build", 8 | filter: /^@remix-run\/dev\/server-build$/, 9 | }; 10 | 11 | export const assetsManifestVirtualModule: VirtualModule = { 12 | id: "@remix-run/dev/assets-manifest", 13 | filter: /^@remix-run\/dev\/assets-manifest$/, 14 | }; 15 | -------------------------------------------------------------------------------- /packages/remix-dev/compiler/utils/crypto.ts: -------------------------------------------------------------------------------- 1 | import * as fs from "node:fs"; 2 | import type { BinaryLike } from "node:crypto"; 3 | import { createHash } from "node:crypto"; 4 | 5 | export function getHash(source: BinaryLike): string { 6 | return createHash("sha256").update(source).digest("hex"); 7 | } 8 | 9 | export async function getFileHash(file: string): Promise { 10 | return new Promise((accept, reject) => { 11 | let hash = createHash("sha256"); 12 | fs.createReadStream(file) 13 | .on("error", (error) => reject(error)) 14 | .on("data", (data) => hash.update(data)) 15 | .on("close", () => { 16 | accept(hash.digest("hex")); 17 | }); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix-dev/config/defaults/entry.client.tsx: -------------------------------------------------------------------------------- 1 | import { RemixBrowser } from "@remix-run/react"; 2 | import { startTransition, StrictMode } from "react"; 3 | import { hydrateRoot } from "react-dom/client"; 4 | 5 | startTransition(() => { 6 | hydrateRoot( 7 | document, 8 | 9 | 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /packages/remix-dev/config/defaults/entry.dev.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | /* eslint-disable */ 3 | 4 | export default () => { 5 | import("react"); 6 | import("react/jsx-dev-runtime"); 7 | import("react/jsx-runtime"); 8 | import("react-dom"); 9 | import("react-dom/client"); 10 | import("react-refresh/runtime"); 11 | import("@remix-run/react"); 12 | import("remix:hmr"); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/remix-dev/config/defaults/entry.server.spa.tsx: -------------------------------------------------------------------------------- 1 | import type { EntryContext } from "@remix-run/node"; 2 | import { RemixServer } from "@remix-run/react"; 3 | import * as React from "react"; 4 | import { renderToString } from "react-dom/server"; 5 | 6 | export default function handleRequest( 7 | request: Request, 8 | responseStatusCode: number, 9 | responseHeaders: Headers, 10 | remixContext: EntryContext 11 | ) { 12 | let html = renderToString( 13 | 14 | ); 15 | html = "\n" + html; 16 | return new Response(html, { 17 | headers: { "Content-Type": "text/html" }, 18 | status: responseStatusCode, 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /packages/remix-dev/config/serverModes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The mode to use when running the server. 3 | */ 4 | export enum ServerMode { 5 | Development = "development", 6 | Production = "production", 7 | Test = "test", 8 | } 9 | 10 | export function isValidServerMode(mode: string): mode is ServerMode { 11 | return ( 12 | mode === ServerMode.Development || 13 | mode === ServerMode.Production || 14 | mode === ServerMode.Test 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /packages/remix-dev/devServer/index.ts: -------------------------------------------------------------------------------- 1 | export { liveReload } from "./liveReload"; 2 | -------------------------------------------------------------------------------- /packages/remix-dev/devServer_unstable/env.ts: -------------------------------------------------------------------------------- 1 | import fse from "fs-extra"; 2 | import * as path from "node:path"; 3 | 4 | // Import environment variables from: .env, failing gracefully if it doesn't exist 5 | export async function loadEnv(rootDirectory: string): Promise { 6 | let envPath = path.join(rootDirectory, ".env"); 7 | if (!fse.existsSync(envPath)) return; 8 | 9 | let result = require("dotenv").config({ path: envPath }); 10 | if (result.error) throw result.error; 11 | } 12 | -------------------------------------------------------------------------------- /packages/remix-dev/invariant.ts: -------------------------------------------------------------------------------- 1 | export default function invariant( 2 | value: boolean, 3 | message?: string 4 | ): asserts value; 5 | 6 | export default function invariant( 7 | value: T | null | undefined, 8 | message?: string 9 | ): asserts value is T; 10 | 11 | export default function invariant(value: any, message?: string) { 12 | if (value === false || value === null || typeof value === "undefined") { 13 | console.error( 14 | "The following error is a bug in Remix; please open an issue! https://github.com/remix-run/remix/issues/new" 15 | ); 16 | throw new Error(message); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/remix-dev/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "dev", 5 | setupFilesAfterEnv: ["/__tests__/setupAfterEnv.ts"], 6 | setupFiles: [], 7 | }; 8 | -------------------------------------------------------------------------------- /packages/remix-dev/manifest.ts: -------------------------------------------------------------------------------- 1 | export type Manifest = { 2 | version: string; 3 | url?: string; 4 | entry: { 5 | module: string; 6 | imports: string[]; 7 | }; 8 | routes: { 9 | [routeId: string]: { 10 | id: string; 11 | parentId?: string; 12 | path?: string; 13 | index?: boolean; 14 | caseSensitive?: boolean; 15 | module: string; 16 | imports?: string[]; 17 | hasAction: boolean; 18 | hasLoader: boolean; 19 | hasClientAction: boolean; 20 | hasClientLoader: boolean; 21 | hasErrorBoundary: boolean; 22 | }; 23 | }; 24 | hmr?: { 25 | timestamp?: number; 26 | runtime: string; 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /packages/remix-dev/result.ts: -------------------------------------------------------------------------------- 1 | type Ok = { ok: true; value: V }; 2 | type Err = { ok: false; error: E }; 3 | 4 | export type Result = Ok | Err; 5 | 6 | export let ok = (value: V): Ok => ({ ok: true, value }); 7 | export let err = (error: E): Err => ({ ok: false, error }); 8 | -------------------------------------------------------------------------------- /packages/remix-dev/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts", "package.json"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "skipLibCheck": true, 13 | "declaration": true, 14 | "emitDeclarationOnly": true, 15 | "rootDir": ".", 16 | "outDir": "../../build/node_modules/@remix-run/dev/dist" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/remix-dev/tux/format.ts: -------------------------------------------------------------------------------- 1 | import pc from "picocolors"; 2 | import type { Formatter } from "picocolors/types"; 3 | 4 | type FormatArgs = { 5 | label: string; 6 | color: Formatter; 7 | }; 8 | 9 | export let format = 10 | ({ label, color }: FormatArgs) => 11 | (message: string, details: string[] = []) => { 12 | let lines = []; 13 | lines.push( 14 | (pc.isColorSupported ? pc.inverse(color(` ${label} `)) : `[${label}]`) + 15 | " " + 16 | message 17 | ); 18 | if (details.length > 0) { 19 | for (let detail of details) { 20 | lines.push(color("┃") + " " + pc.gray(detail)); 21 | } 22 | lines.push(color("┗")); 23 | } 24 | return lines.join("\n"); 25 | }; 26 | -------------------------------------------------------------------------------- /packages/remix-dev/tux/index.ts: -------------------------------------------------------------------------------- 1 | export { logger, type Logger } from "./logger"; 2 | -------------------------------------------------------------------------------- /packages/remix-dev/vite/babel.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/consistent-type-imports */ 2 | import type { NodePath } from "@babel/traverse"; 3 | import type { types as BabelTypes } from "@babel/core"; 4 | import { parse } from "@babel/parser"; 5 | import * as t from "@babel/types"; 6 | 7 | // These `require`s were needed to support building within vite-ecosystem-ci, 8 | // otherwise we get errors that `traverse` and `generate` are not functions. 9 | const traverse = require("@babel/traverse") 10 | .default as typeof import("@babel/traverse").default; 11 | const generate = require("@babel/generator") 12 | .default as typeof import("@babel/generator").default; 13 | 14 | export { traverse, generate, parse, t }; 15 | export type { BabelTypes, NodePath }; 16 | -------------------------------------------------------------------------------- /packages/remix-dev/vite/combine-urls.ts: -------------------------------------------------------------------------------- 1 | // Borrowed from axios: https://github.com/axios/axios/blob/0e4f9fa29077ebee4499facea6be1492b42e8a26/lib/helpers/combineURLs.js#L11-L15 2 | export function combineURLs(baseURL: string, relativeURL: string) { 3 | return relativeURL 4 | ? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "") 5 | : baseURL; 6 | } 7 | -------------------------------------------------------------------------------- /packages/remix-dev/vite/index.ts: -------------------------------------------------------------------------------- 1 | // This file allows us to dynamically require the plugin so non-Vite consumers 2 | // don't need to have Vite installed as a peer dependency. Only types should 3 | // be imported at the top level, or code that doesn't import Vite. 4 | import type { RemixVitePlugin } from "./plugin"; 5 | export type { 6 | BuildManifest, 7 | Preset, 8 | VitePluginConfig, 9 | ServerBundlesFunction, 10 | } from "./plugin"; 11 | 12 | export const vitePlugin: RemixVitePlugin = (...args) => { 13 | // eslint-disable-next-line @typescript-eslint/consistent-type-imports 14 | let { remixVitePlugin } = require("./plugin") as typeof import("./plugin"); 15 | return remixVitePlugin(...args); 16 | }; 17 | 18 | export { cloudflareDevProxyVitePlugin } from "./cloudflare-proxy-plugin"; 19 | -------------------------------------------------------------------------------- /packages/remix-dev/vite/is-in-remix-monorepo.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | 3 | export function isInRemixMonorepo() { 4 | try { 5 | let devPath = path.dirname(require.resolve("@remix-run/node/package.json")); 6 | let devParentDir = path.basename(path.resolve(devPath, "..")); 7 | return devParentDir === "packages"; 8 | } catch { 9 | return false; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/remix-dev/vite/resolve-file-url.ts: -------------------------------------------------------------------------------- 1 | import * as path from "node:path"; 2 | 3 | import { getVite } from "./vite"; 4 | 5 | export const resolveFileUrl = ( 6 | { rootDirectory }: { rootDirectory: string }, 7 | filePath: string 8 | ) => { 9 | let vite = getVite(); 10 | let relativePath = path.relative(rootDirectory, filePath); 11 | let isWithinRoot = 12 | !relativePath.startsWith("..") && !path.isAbsolute(relativePath); 13 | 14 | if (!isWithinRoot) { 15 | // Vite will prevent serving files outside of the workspace 16 | // unless user explicitly opts in with `server.fs.allow` 17 | // https://vitejs.dev/config/server-options.html#server-fs-allow 18 | return path.posix.join("/@fs", vite.normalizePath(filePath)); 19 | } 20 | 21 | return "/" + vite.normalizePath(relativePath); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/remix-dev/vite/ssr-externals.ts: -------------------------------------------------------------------------------- 1 | import { isInRemixMonorepo } from "./is-in-remix-monorepo"; 2 | 3 | export const ssrExternals = isInRemixMonorepo() 4 | ? [ 5 | // This is only needed within the Remix repo because these 6 | // packages are linked to a directory outside of node_modules 7 | // so Vite treats them as internal code by default. 8 | "@remix-run/architect", 9 | "@remix-run/cloudflare-pages", 10 | "@remix-run/cloudflare-workers", 11 | "@remix-run/cloudflare", 12 | "@remix-run/css-bundle", 13 | "@remix-run/deno", 14 | "@remix-run/dev", 15 | "@remix-run/express", 16 | "@remix-run/netlify", 17 | "@remix-run/node", 18 | "@remix-run/react", 19 | "@remix-run/serve", 20 | "@remix-run/server-runtime", 21 | ] 22 | : undefined; 23 | -------------------------------------------------------------------------------- /packages/remix-dev/vite/vmod.ts: -------------------------------------------------------------------------------- 1 | export let id = (name: string) => `virtual:remix/${name}`; 2 | export let resolve = (id: string) => `\0${id}`; 3 | export let url = (id: string) => `/@id/__x00__${id}`; 4 | -------------------------------------------------------------------------------- /packages/remix-eslint-config/node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @see https://github.com/eslint/eslint/issues/3458 3 | * @see https://www.npmjs.com/package/@rushstack/eslint-patch 4 | */ 5 | require("@rushstack/eslint-patch/modern-module-resolution"); 6 | 7 | module.exports = { 8 | plugins: ["node"], 9 | env: { 10 | node: true, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/remix-eslint-config/rules/import.js: -------------------------------------------------------------------------------- 1 | // const OFF = 0; 2 | // const WARN = 1; 3 | const ERROR = 2; 4 | 5 | module.exports = { 6 | "import/first": ERROR, 7 | "import/no-amd": ERROR, 8 | "import/no-duplicates": ERROR, 9 | "import/no-webpack-loader-syntax": ERROR, 10 | }; 11 | -------------------------------------------------------------------------------- /packages/remix-eslint-config/rules/jest-dom.js: -------------------------------------------------------------------------------- 1 | // const OFF = 0; 2 | const WARN = 1; 3 | // const ERROR = 2; 4 | 5 | module.exports = { 6 | "jest-dom/prefer-checked": WARN, 7 | "jest-dom/prefer-empty": WARN, 8 | "jest-dom/prefer-enabled-disabled": WARN, 9 | "jest-dom/prefer-focus": WARN, 10 | "jest-dom/prefer-in-document": WARN, 11 | "jest-dom/prefer-required": WARN, 12 | "jest-dom/prefer-to-have-attribute": WARN, 13 | "jest-dom/prefer-to-have-class": WARN, 14 | "jest-dom/prefer-to-have-style": WARN, 15 | "jest-dom/prefer-to-have-text-content": WARN, 16 | "jest-dom/prefer-to-have-value": WARN, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/remix-eslint-config/rules/jest.js: -------------------------------------------------------------------------------- 1 | // const OFF = 0; 2 | const WARN = 1; 3 | const ERROR = 2; 4 | 5 | module.exports = { 6 | "jest/no-conditional-expect": WARN, 7 | "jest/no-deprecated-functions": WARN, 8 | "jest/no-disabled-tests": WARN, 9 | "jest/no-export": ERROR, 10 | "jest/no-focused-tests": WARN, 11 | "jest/no-identical-title": WARN, 12 | "jest/no-interpolation-in-snapshots": WARN, 13 | "jest/no-jasmine-globals": ERROR, 14 | "jest/no-jest-import": WARN, 15 | "jest/no-mocks-import": WARN, 16 | "jest/valid-describe-callback": ERROR, 17 | "jest/valid-expect": ERROR, 18 | "jest/valid-expect-in-promise": ERROR, 19 | }; 20 | -------------------------------------------------------------------------------- /packages/remix-eslint-config/settings/import.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "import/ignore": ["node_modules", "\\.(css|md|svg|json)$"], 3 | "import/parsers": { 4 | [require.resolve("@typescript-eslint/parser")]: [".ts", ".tsx", ".d.ts"], 5 | }, 6 | "import/resolver": { 7 | [require.resolve("eslint-import-resolver-node")]: { 8 | extensions: [".js", ".jsx", ".ts", ".tsx"], 9 | }, 10 | [require.resolve("eslint-import-resolver-typescript")]: { 11 | alwaysTryTypes: true, 12 | }, 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /packages/remix-eslint-config/settings/react.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | react: { 3 | version: "detect", 4 | formComponents: ["Form"], 5 | linkComponents: [ 6 | { 7 | name: "Link", 8 | linkAttribute: "to", 9 | }, 10 | { 11 | name: "NavLink", 12 | linkAttribute: "to", 13 | }, 14 | ], 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/remix-express/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-express/__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | import { installGlobals } from "@remix-run/node"; 2 | installGlobals({ nativeFetch: true }); 3 | -------------------------------------------------------------------------------- /packages/remix-express/index.ts: -------------------------------------------------------------------------------- 1 | export type { GetLoadContextFunction, RequestHandler } from "./server"; 2 | export { createRequestHandler } from "./server"; 3 | -------------------------------------------------------------------------------- /packages/remix-express/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "express", 5 | }; 6 | -------------------------------------------------------------------------------- /packages/remix-express/rollup.config.js: -------------------------------------------------------------------------------- 1 | const { getAdapterConfig } = require("../../rollup.utils"); 2 | 3 | /** @returns {import("rollup").RollupOptions[]} */ 4 | module.exports = function rollup() { 5 | return [getAdapterConfig("express")]; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/remix-express/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "skipLibCheck": true, 8 | 9 | "moduleResolution": "Bundler", 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "declaration": true, 13 | "emitDeclarationOnly": true, 14 | "rootDir": ".", 15 | "outDir": "../../build/node_modules/@remix-run/express/dist" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/remix-fs-routes/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-fs-routes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "moduleResolution": "Bundler", 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "jsx": "react", 14 | "declaration": true, 15 | "emitDeclarationOnly": true, 16 | "rootDir": ".", 17 | "outDir": "../../build/node_modules/@remix-run/fs-routes/dist" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix-node/.gitignore: -------------------------------------------------------------------------------- 1 | # TODO: Remove in v2 2 | globals.d.ts -------------------------------------------------------------------------------- /packages/remix-node/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-node/__tests__/assets/test.txt: -------------------------------------------------------------------------------- 1 | hello, world! -------------------------------------------------------------------------------- /packages/remix-node/__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | import { installGlobals } from "@remix-run/node"; 2 | installGlobals({ nativeFetch: true }); 3 | -------------------------------------------------------------------------------- /packages/remix-node/__tests__/utils.ts: -------------------------------------------------------------------------------- 1 | import prettier from "prettier"; 2 | 3 | export function prettyHtml(source: string): string { 4 | return prettier.format(source, { parser: "html" }); 5 | } 6 | -------------------------------------------------------------------------------- /packages/remix-node/crypto.ts: -------------------------------------------------------------------------------- 1 | import cookieSignature from "cookie-signature"; 2 | import type { SignFunction, UnsignFunction } from "@remix-run/server-runtime"; 3 | 4 | export const sign: SignFunction = async (value, secret) => { 5 | return cookieSignature.sign(value, secret); 6 | }; 7 | 8 | export const unsign: UnsignFunction = async ( 9 | signed: string, 10 | secret: string 11 | ) => { 12 | return cookieSignature.unsign(signed, secret); 13 | }; 14 | -------------------------------------------------------------------------------- /packages/remix-node/implementations.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createCookieFactory, 3 | createCookieSessionStorageFactory, 4 | createMemorySessionStorageFactory, 5 | createSessionStorageFactory, 6 | } from "@remix-run/server-runtime"; 7 | 8 | import { sign, unsign } from "./crypto"; 9 | 10 | export const createCookie = createCookieFactory({ sign, unsign }); 11 | export const createCookieSessionStorage = 12 | createCookieSessionStorageFactory(createCookie); 13 | export const createSessionStorage = createSessionStorageFactory(createCookie); 14 | export const createMemorySessionStorage = 15 | createMemorySessionStorageFactory(createSessionStorage); 16 | -------------------------------------------------------------------------------- /packages/remix-node/install.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /packages/remix-node/install.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | "use strict"; 3 | 4 | var globals = require("./dist/globals.js"); 5 | 6 | Object.defineProperty(exports, "__esModule", { value: true }); 7 | 8 | globals.installGlobals(); 9 | -------------------------------------------------------------------------------- /packages/remix-node/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /packages/remix-node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | 9 | "moduleResolution": "Bundler", 10 | "allowSyntheticDefaultImports": true, 11 | "strict": true, 12 | "declaration": true, 13 | "emitDeclarationOnly": true, 14 | "rootDir": ".", 15 | "outDir": "../../build/node_modules/@remix-run/node/dist", 16 | 17 | // Avoid naming conflicts between lib.dom.d.ts and globals.ts 18 | "skipLibCheck": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/remix-react/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-react/__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | const JSDOMFormData = global.FormData; 2 | global.TextDecoder = require("util").TextDecoder; 3 | global.TextEncoder = require("util").TextEncoder; 4 | global.ReadableStream = require("stream/web").ReadableStream; 5 | global.WritableStream = require("stream/web").WritableStream; 6 | 7 | require("@remix-run/node").installGlobals({ nativeFetch: true }); 8 | global.FormData = JSDOMFormData; 9 | -------------------------------------------------------------------------------- /packages/remix-react/invariant.ts: -------------------------------------------------------------------------------- 1 | export default function invariant( 2 | value: boolean, 3 | message?: string 4 | ): asserts value; 5 | export default function invariant( 6 | value: T | null | undefined, 7 | message?: string 8 | ): asserts value is T; 9 | export default function invariant(value: any, message?: string) { 10 | if (value === false || value === null || typeof value === "undefined") { 11 | throw new Error(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/remix-react/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "react", 5 | testEnvironment: "jsdom", 6 | }; 7 | -------------------------------------------------------------------------------- /packages/remix-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts", "**/*.tsx"], 3 | "exclude": ["future/*.d.ts", "dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "moduleResolution": "Bundler", 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "jsx": "react", 14 | "declaration": true, 15 | "emitDeclarationOnly": true, 16 | "rootDir": ".", 17 | "outDir": "../../build/node_modules/@remix-run/react/dist" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix-react/warnings.ts: -------------------------------------------------------------------------------- 1 | const alreadyWarned: { [message: string]: boolean } = {}; 2 | 3 | export function warnOnce(condition: boolean, message: string): void { 4 | if (!condition && !alreadyWarned[message]) { 5 | alreadyWarned[message] = true; 6 | console.warn(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/remix-route-config/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-route-config/index.ts: -------------------------------------------------------------------------------- 1 | export type { 2 | UNSAFE_RouteConfig as RouteConfig, 3 | UNSAFE_RouteConfigEntry as RouteConfigEntry, 4 | } from "@remix-run/dev"; 5 | 6 | export { 7 | route, 8 | index, 9 | layout, 10 | prefix, 11 | relative, 12 | getAppDirectory, 13 | } from "./routes"; 14 | -------------------------------------------------------------------------------- /packages/remix-route-config/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "route-config", 5 | setupFiles: [], 6 | }; 7 | -------------------------------------------------------------------------------- /packages/remix-route-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "moduleResolution": "Bundler", 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "jsx": "react", 14 | "declaration": true, 15 | "emitDeclarationOnly": true, 16 | "rootDir": ".", 17 | "outDir": "../../build/node_modules/@remix-run/route-config/dist" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix-routes-option-adapter/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-routes-option-adapter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "moduleResolution": "Bundler", 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "jsx": "react", 14 | "declaration": true, 15 | "emitDeclarationOnly": true, 16 | "rootDir": ".", 17 | "outDir": "../../build/node_modules/@remix-run/routes-option-adapter/dist" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix-serve/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-serve/rollup.config.js: -------------------------------------------------------------------------------- 1 | const { getCliConfig } = require("../../rollup.utils"); 2 | const { name: packageName, version } = require("./package.json"); 3 | 4 | /** @returns {import("rollup").RollupOptions[]} */ 5 | module.exports = function rollup() { 6 | return [getCliConfig({ packageName, version })]; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/remix-serve/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "moduleResolution": "Bundler", 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "declaration": true, 14 | "emitDeclarationOnly": true, 15 | "rootDir": ".", 16 | "outDir": "../../build/node_modules/@remix-run/serve/dist" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/.eslintrc.js: -------------------------------------------------------------------------------- 1 | let restrictedGlobalsError = `Node globals are not allowed in this package.`; 2 | 3 | module.exports = { 4 | extends: "../../.eslintrc.js", 5 | rules: { 6 | "no-restricted-globals": [ 7 | "error", 8 | { name: "__dirname", message: restrictedGlobalsError }, 9 | { name: "__filename", message: restrictedGlobalsError }, 10 | { name: "Buffer", message: restrictedGlobalsError }, 11 | ], 12 | "import/no-nodejs-modules": "error", 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/__tests__/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | rules: { 4 | "no-restricted-globals": "off", 5 | "import/no-nodejs-modules": "off", 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/__tests__/setup.ts: -------------------------------------------------------------------------------- 1 | import { installGlobals } from "@remix-run/node"; 2 | 3 | installGlobals({ nativeFetch: true }); 4 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/deprecations.ts: -------------------------------------------------------------------------------- 1 | export function resourceRouteJsonWarning( 2 | type: "loader" | "action", 3 | routeId: string 4 | ) { 5 | return ( 6 | "⚠️ REMIX FUTURE CHANGE: Externally-accessed resource routes will no longer be " + 7 | "able to return raw JavaScript objects or `null` in React Router v7 when " + 8 | "Single Fetch becomes the default. You can prepare for this change at your " + 9 | `convenience by wrapping the data returned from your \`${type}\` function in ` + 10 | `the \`${routeId}\` route with \`json()\`. For instructions on making this ` + 11 | "change, see https://remix.run/docs/en/v2.13.1/guides/single-fetch#resource-routes" 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/future.ts: -------------------------------------------------------------------------------- 1 | export interface Future {} 2 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/interface.ts: -------------------------------------------------------------------------------- 1 | export type { CreateCookieFunction, IsCookieFunction } from "./cookies"; 2 | export type { JsonFunction, RedirectFunction } from "./responses"; 3 | export type { CreateRequestHandlerFunction } from "./server"; 4 | export type { 5 | CreateSessionFunction, 6 | CreateSessionStorageFunction, 7 | IsSessionFunction, 8 | } from "./sessions"; 9 | export type { CreateCookieSessionStorageFunction } from "./sessions/cookieStorage"; 10 | export type { CreateMemorySessionStorageFunction } from "./sessions/memoryStorage"; 11 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/invariant.ts: -------------------------------------------------------------------------------- 1 | export default function invariant( 2 | value: boolean, 3 | message?: string 4 | ): asserts value; 5 | export default function invariant( 6 | value: T | null | undefined, 7 | message?: string 8 | ): asserts value is T; 9 | export default function invariant(value: any, message?: string) { 10 | if (value === false || value === null || typeof value === "undefined") { 11 | console.error( 12 | "The following error is a bug in Remix; please open an issue! https://github.com/remix-run/remix/issues/new" 13 | ); 14 | throw new Error(message); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "server-runtime", 5 | }; 6 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/markup.ts: -------------------------------------------------------------------------------- 1 | // This escapeHtml utility is based on https://github.com/zertosh/htmlescape 2 | // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE 3 | 4 | // We've chosen to inline the utility here to reduce the number of npm dependencies we have, 5 | // slightly decrease the code size compared the original package and make it esm compatible. 6 | 7 | const ESCAPE_LOOKUP: { [match: string]: string } = { 8 | "&": "\\u0026", 9 | ">": "\\u003e", 10 | "<": "\\u003c", 11 | "\u2028": "\\u2028", 12 | "\u2029": "\\u2029", 13 | }; 14 | 15 | const ESCAPE_REGEX = /[&><\u2028\u2029]/g; 16 | 17 | export function escapeHtml(html: string) { 18 | return html.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]); 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/mode.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The mode to use when running the server. 3 | */ 4 | export enum ServerMode { 5 | Development = "development", 6 | Production = "production", 7 | Test = "test", 8 | } 9 | 10 | export function isServerMode(value: any): value is ServerMode { 11 | return ( 12 | value === ServerMode.Development || 13 | value === ServerMode.Production || 14 | value === ServerMode.Test 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | 8 | "moduleResolution": "Bundler", 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "declaration": true, 12 | "emitDeclarationOnly": true, 13 | "rootDir": ".", 14 | "outDir": "../../build/node_modules/@remix-run/server-runtime/dist", 15 | 16 | // Avoid naming conflicts between lib.dom.d.ts and globals.ts 17 | "skipLibCheck": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/typecheck.ts: -------------------------------------------------------------------------------- 1 | // typecheck that expression is assignable to type 2 | export function expectType(_expression: T) {} 3 | 4 | // prettier-ignore 5 | // adapted from https://github.com/type-challenges/type-challenges/blob/main/utils/index.d.ts 6 | export type Equal = 7 | (() => T extends X ? 1 : 2) extends 8 | (() => T extends Y ? 1 : 2) ? true : false 9 | 10 | // adapted from https://github.com/type-challenges/type-challenges/blob/main/utils/index.d.ts 11 | export type Expect = T; 12 | 13 | // looser, lazy equality check for recursive types 14 | // prettier-ignore 15 | export type MutualExtends = [A] extends [B] ? [B] extends [A] ? true : false : false 16 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/upload/errors.ts: -------------------------------------------------------------------------------- 1 | export class MaxPartSizeExceededError extends Error { 2 | constructor(public field: string, public maxBytes: number) { 3 | super(`Field "${field}" exceeded upload size of ${maxBytes} bytes.`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/remix-server-runtime/warnings.ts: -------------------------------------------------------------------------------- 1 | const alreadyWarned: { [message: string]: boolean } = {}; 2 | 3 | export function warnOnce(condition: boolean, message: string): void { 4 | if (!condition && !alreadyWarned[message]) { 5 | alreadyWarned[message] = true; 6 | console.warn(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/remix-testing/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | [Remix](https://remix.run) is a web framework that helps you build better websites with React. 4 | 5 | To get started, open a new shell and run: 6 | 7 | ```sh 8 | npx create-remix@latest 9 | ``` 10 | 11 | Then follow the prompts you see in your terminal. 12 | 13 | For more information about Remix, [visit remix.run](https://remix.run)! 14 | -------------------------------------------------------------------------------- /packages/remix-testing/index.ts: -------------------------------------------------------------------------------- 1 | export type { RemixStubProps } from "./create-remix-stub"; 2 | export { createRemixStub } from "./create-remix-stub"; 3 | -------------------------------------------------------------------------------- /packages/remix-testing/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('jest').Config} */ 2 | module.exports = { 3 | ...require("../../jest/jest.config.shared"), 4 | displayName: "testing", 5 | setupFiles: [], 6 | testEnvironment: "jsdom", 7 | setupFilesAfterEnv: ["./jest.setup.js", "@testing-library/jest-dom"], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/remix-testing/jest.setup.js: -------------------------------------------------------------------------------- 1 | const JSDOMFormData = global.FormData; 2 | global.TextDecoder = require("util").TextDecoder; 3 | global.TextEncoder = require("util").TextEncoder; 4 | global.ReadableStream = require("stream/web").ReadableStream; 5 | global.WritableStream = require("stream/web").WritableStream; 6 | 7 | require("@remix-run/node").installGlobals({ nativeFetch: true }); 8 | global.FormData = JSDOMFormData; 9 | -------------------------------------------------------------------------------- /packages/remix-testing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts", "**/*.tsx"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "moduleResolution": "Bundler", 11 | "allowSyntheticDefaultImports": true, 12 | "strict": true, 13 | "jsx": "react", 14 | "declaration": true, 15 | "emitDeclarationOnly": true, 16 | "rootDir": ".", 17 | "outDir": "../../build/node_modules/@remix-run/testing/dist" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/remix/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # `remix` 2 | 3 | See the `CHANGELOG.md` in individual Remix packages for all changes. 4 | -------------------------------------------------------------------------------- /packages/remix/index.ts: -------------------------------------------------------------------------------- 1 | // This class exists to prevent https://github.com/remix-run/remix/issues/2031 from occurring 2 | export class RemixPackageNotUsedError extends Error { 3 | constructor() { 4 | super( 5 | "The `remix` package is no longer used for Remix modules and should be removed " + 6 | "from your project dependencies. See " + 7 | "https://github.com/remix-run/remix/releases/tag/remix%402.0.0" + 8 | " for more information." 9 | ); 10 | } 11 | } 12 | 13 | throw new RemixPackageNotUsedError(); 14 | -------------------------------------------------------------------------------- /packages/remix/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix", 3 | "version": "2.16.7", 4 | "description": "A framework for building better websites", 5 | "homepage": "https://remix.run", 6 | "bugs": { 7 | "url": "https://github.com/remix-run/remix/issues" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/remix-run/remix", 12 | "directory": "packages/remix" 13 | }, 14 | "license": "MIT", 15 | "sideEffects": false, 16 | "main": "dist/index.js", 17 | "typings": "dist/index.d.ts", 18 | "module": "dist/esm/index.js", 19 | "scripts": { 20 | "tsc": "tsc" 21 | }, 22 | "engines": { 23 | "node": ">=18.0.0" 24 | }, 25 | "files": [ 26 | "dist/", 27 | "CHANGELOG.md", 28 | "LICENSE.md", 29 | "README.md" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /packages/remix/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "exclude": ["dist", "__tests__", "node_modules"], 4 | "compilerOptions": { 5 | "lib": ["ES2022"], 6 | "target": "ES2022", 7 | "module": "ES2022", 8 | "skipLibCheck": true, 9 | 10 | "jsx": "react", 11 | "moduleResolution": "Bundler", 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "declaration": true, 15 | "emitDeclarationOnly": true, 16 | "rootDir": ".", 17 | "outDir": "../../build/node_modules/remix/dist" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /playground/README.md: -------------------------------------------------------------------------------- 1 | # Playground 2 | 3 | This is where you can put Remix projects that use a local version of Remix. Learn more in [the contributing docs](https://remix.run/pages/contributing) 4 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "integration" 3 | - "integration/helpers/*" 4 | - "packages/*" 5 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('prettier').Options} */ 2 | module.exports = {}; 3 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | const fs = require("node:fs"); 2 | const path = require("node:path"); 3 | 4 | module.exports = function rollup(options) { 5 | return fs.readdirSync("packages").flatMap((dir) => { 6 | let configPath = path.join("packages", dir, "rollup.config.js"); 7 | try { 8 | fs.readFileSync(configPath); 9 | } catch { 10 | return []; 11 | } 12 | let packageBuild = require(`.${path.sep}${configPath}`); 13 | return packageBuild(options); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /scripts/bump-fetch-versions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION="${1}" 4 | 5 | if [ "${VERSION}" == "" ]; then 6 | VERSION="latest" 7 | fi 8 | 9 | 10 | echo "Updating the undici dependencies to version '${VERSION}'" 11 | echo "" 12 | 13 | if [ ! -d "packages/remix-node" ]; then 14 | echo "Must be run from the remix repository" 15 | exit 1 16 | fi 17 | 18 | set -x 19 | 20 | cd packages/remix-node 21 | pnpm add undici@${VERSION} 22 | cd ../.. 23 | 24 | set +x -------------------------------------------------------------------------------- /scripts/copy-templates-to-fixtures.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | cp -r templates/cloudflare-pages/* packages/remix-dev/__tests__/fixtures/cloudflare/ 6 | rm -f packages/remix-dev/__tests__/fixtures/cloudflare/app/entry.client.tsx 7 | rm -f packages/remix-dev/__tests__/fixtures/cloudflare/app/entry.server.tsx 8 | 9 | cp -r templates/deno/* packages/remix-dev/__tests__/fixtures/deno/ 10 | rm -f packages/remix-dev/__tests__/fixtures/deno/app/entry.client.tsx 11 | rm -f packages/remix-dev/__tests__/fixtures/deno/app/entry.server.tsx 12 | 13 | cp -r templates/remix/* packages/remix-dev/__tests__/fixtures/node/ 14 | rm -f packages/remix-dev/__tests__/fixtures/node/app/entry.client.tsx 15 | rm -f packages/remix-dev/__tests__/fixtures/node/app/entry.server.tsx 16 | 17 | set +x 18 | -------------------------------------------------------------------------------- /scripts/deployment-test/cypress.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /scripts/deployment-test/cypress/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parserOptions: { 3 | tsconfigRootDir: __dirname, 4 | project: "./tsconfig.json", 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /scripts/deployment-test/cypress/e2e/smoke.ts: -------------------------------------------------------------------------------- 1 | describe("smoke", () => { 2 | it("should work", () => { 3 | cy.visit("/"); 4 | cy.contains("a", "15m Quickstart Blog Tutorial"); 5 | }); 6 | }); 7 | -------------------------------------------------------------------------------- /scripts/deployment-test/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /scripts/deployment-test/cypress/plugins/index.ts: -------------------------------------------------------------------------------- 1 | module.exports = ( 2 | on: Cypress.PluginEvents, 3 | config: Cypress.PluginConfigOptions 4 | ) => { 5 | let configOverrides: Partial = { 6 | viewportWidth: 1030, 7 | viewportHeight: 800, 8 | integrationFolder: "cypress/e2e", 9 | video: !process.env.CI, 10 | screenshotOnRunFailure: !process.env.CI, 11 | }; 12 | Object.assign(config, configOverrides); 13 | 14 | on("task", { 15 | log(message) { 16 | console.log(message); 17 | return null; 18 | }, 19 | }); 20 | 21 | return config; 22 | }; 23 | -------------------------------------------------------------------------------- /scripts/deployment-test/cypress/support/index.js: -------------------------------------------------------------------------------- 1 | import "@testing-library/cypress/add-commands"; 2 | -------------------------------------------------------------------------------- /scripts/deployment-test/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": [ 3 | "../node_modules/@types/jest", 4 | "../node_modules/@testing-library/jest-dom" 5 | ], 6 | "include": [ 7 | "./index.ts", 8 | "e2e/**/*", 9 | "plugins/**/*", 10 | "support/**/*", 11 | "../node_modules/cypress", 12 | "../node_modules/@testing-library/cypress" 13 | ], 14 | "compilerOptions": { 15 | "baseUrl": ".", 16 | "noEmit": true, 17 | "types": ["node", "cypress", "@testing-library/cypress"], 18 | "esModuleInterop": true, 19 | "jsx": "react", 20 | "moduleResolution": "Bundler", 21 | "target": "ES2022", 22 | "strict": true, 23 | "skipLibCheck": true, 24 | "resolveJsonModule": true, 25 | "typeRoots": ["../types", "../node_modules/@types"] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /scripts/deployment-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deployment-test", 3 | "description": "deps needed for testing remix deployments", 4 | "private": true, 5 | "scripts": {}, 6 | "dependencies": { 7 | "@architect/destroy": "^3.0.3", 8 | "@architect/parser": "^5.0.2", 9 | "@architect/utils": "^3.0.4", 10 | "@aws-sdk/client-apigatewayv2": "^3.310.0", 11 | "@iarna/toml": "^2.2.5", 12 | "@npmcli/package-json": "^4.0.1", 13 | "@testing-library/cypress": "^8.0.2", 14 | "cypress": "^9.2.0", 15 | "fetch-retry": "^5.0.2", 16 | "fs-extra": "^10.0.0", 17 | "semver": "^7.3.7", 18 | "start-server-and-test": "^1.14.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /scripts/playground/template/.env: -------------------------------------------------------------------------------- 1 | DATABASE_URL="file:./data.db?connection_limit=1" 2 | SESSION_SECRET="super-duper-s3cret" 3 | -------------------------------------------------------------------------------- /scripts/playground/template/.gitignore: -------------------------------------------------------------------------------- 1 | **/public/build 2 | 3 | **/prisma/data.db 4 | **/prisma/data.db-journal 5 | -------------------------------------------------------------------------------- /scripts/playground/template/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | 7 | /app/styles/tailwind.css 8 | -------------------------------------------------------------------------------- /scripts/playground/template/README.md: -------------------------------------------------------------------------------- 1 | # Remix Playground 2 | 3 | This project has everything set up for you to play around with the local Remix packages in a real app environment. 4 | 5 | To create a new project within the `playground` directory (which is ignored by `.gitignore`), execute the command `pnpm playground:new `. For more details, please refer to [the contributing guidelines](https://remix.run/pages/contributing). 6 | -------------------------------------------------------------------------------- /scripts/playground/template/app/db.server.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | let prisma: PrismaClient; 4 | 5 | declare global { 6 | // eslint-disable-next-line prefer-let/prefer-let 7 | var __db__: PrismaClient; 8 | } 9 | 10 | // this is needed because in development we don't want to restart 11 | // the server with every change, but we want to make sure we don't 12 | // create a new connection to the DB with every change either. 13 | // in production we'll have a single connection to the DB. 14 | if (process.env.NODE_ENV === "production") { 15 | prisma = new PrismaClient(); 16 | } else { 17 | if (!global.__db__) { 18 | global.__db__ = new PrismaClient(); 19 | } 20 | prisma = global.__db__; 21 | prisma.$connect(); 22 | } 23 | 24 | export { prisma }; 25 | -------------------------------------------------------------------------------- /scripts/playground/template/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | import { RemixBrowser } from "@remix-run/react"; 2 | import { startTransition, StrictMode } from "react"; 3 | import { hydrateRoot } from "react-dom/client"; 4 | 5 | const hydrate = () => { 6 | startTransition(() => { 7 | hydrateRoot( 8 | document, 9 | 10 | 11 | 12 | ); 13 | }); 14 | }; 15 | 16 | if (typeof requestIdleCallback === "function") { 17 | requestIdleCallback(hydrate); 18 | } else { 19 | // Safari doesn't support requestIdleCallback 20 | // https://caniuse.com/requestidlecallback 21 | setTimeout(hydrate, 1); 22 | } 23 | -------------------------------------------------------------------------------- /scripts/playground/template/app/routes/logout.tsx: -------------------------------------------------------------------------------- 1 | import type { ActionFunctionArgs } from "@remix-run/node"; 2 | import { redirect } from "@remix-run/node"; 3 | 4 | import { logout } from "~/session.server"; 5 | 6 | export async function action({ request }: ActionFunctionArgs) { 7 | return logout(request); 8 | } 9 | 10 | export async function loader() { 11 | return redirect("/"); 12 | } 13 | -------------------------------------------------------------------------------- /scripts/playground/template/app/routes/notes/index.tsx: -------------------------------------------------------------------------------- 1 | import type { MetaFunction } from "@remix-run/node"; 2 | import { Link } from "@remix-run/react"; 3 | 4 | export const meta: MetaFunction = () => { 5 | return [{ title: "Remix Notes" }]; 6 | }; 7 | 8 | export default function NoteIndexPage() { 9 | return ( 10 |

11 | No note selected. Select a note on the left, or{" "} 12 | 13 | create a new note. 14 | 15 |

16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /scripts/playground/template/app/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /scripts/playground/template/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /scripts/playground/template/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/scripts/playground/template/public/favicon.ico -------------------------------------------------------------------------------- /scripts/playground/template/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | cacheDirectory: "./node_modules/.cache/remix", 4 | ignoredRouteFiles: ["**/*.css", "**/*.test.{js,jsx,ts,tsx}"], 5 | }; 6 | -------------------------------------------------------------------------------- /scripts/playground/template/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /scripts/playground/template/remix.init/index.js: -------------------------------------------------------------------------------- 1 | const { execSync } = require("node:child_process"); 2 | 3 | const main = async ({ rootDirectory }) => { 4 | execSync(`npm run build`, { stdio: "inherit", cwd: rootDirectory }); 5 | execSync(`npm run setup`, { stdio: "inherit", cwd: rootDirectory }); 6 | 7 | console.log( 8 | `Setup is complete. You're now ready to rock and roll 🤘 9 | 10 | Start development with \`npm run dev\` 11 | `.trim() 12 | ); 13 | }; 14 | 15 | module.exports = main; 16 | -------------------------------------------------------------------------------- /scripts/playground/template/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /scripts/playground/template/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": [], 3 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 4 | "compilerOptions": { 5 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 6 | "types": ["vitest/globals"], 7 | "isolatedModules": true, 8 | "esModuleInterop": true, 9 | "jsx": "react-jsx", 10 | "module": "ES2022", 11 | "moduleResolution": "Bundler", 12 | "resolveJsonModule": true, 13 | "target": "ES2022", 14 | "strict": true, 15 | "allowJs": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "~/*": ["./app/*"] 20 | }, 21 | "skipLibCheck": true, 22 | 23 | // Remix takes care of building everything in `remix build`. 24 | "noEmit": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/prompt-confirm.d.ts: -------------------------------------------------------------------------------- 1 | declare module "prompt-confirm" { 2 | class Confirm { 3 | constructor(question: string, answers?: any, rl?: any); 4 | run(): Promise; 5 | } 6 | export = Confirm; 7 | } 8 | -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["."], 3 | "exclude": ["./deployment-test", "./playground/template/**/*"], 4 | "compilerOptions": { 5 | "allowJs": true, 6 | "checkJs": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "allowSyntheticDefaultImports": true, 9 | "moduleResolution": "Bundler", 10 | "module": "ES2022", 11 | "noEmit": true, 12 | "strict": true, 13 | "target": "ES2022" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /templates/.eslintignore: -------------------------------------------------------------------------------- 1 | deno 2 | -------------------------------------------------------------------------------- /templates/.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | yarn.lock 3 | pnpm-lock.yaml 4 | pnpm-lock.yml 5 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/arc/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /public/build 5 | /server/index.mjs 6 | /server/index.mjs.map 7 | /server/metafile.* 8 | /server/version.txt 9 | preferences.arc 10 | sam.json 11 | sam.yaml 12 | .env 13 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/arc/app.arc: -------------------------------------------------------------------------------- 1 | @app 2 | remix-architect-app 3 | 4 | @aws 5 | runtime nodejs18.x 6 | # concurrency 1 7 | # memory 1152 8 | # profile default 9 | # region us-west-1 10 | # timeout 30 11 | 12 | @http 13 | /* 14 | method any 15 | src server 16 | 17 | @plugins 18 | plugin-remix 19 | src plugin-remix.js 20 | 21 | @static 22 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/arc/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/arc/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/classic-remix-compiler/arc/public/favicon.ico -------------------------------------------------------------------------------- /templates/classic-remix-compiler/arc/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | ignoredRouteFiles: ["**/*.css"], 4 | publicPath: "/_static/build/", 5 | server: "server.ts", 6 | serverBuildPath: "server/index.mjs", 7 | // appDirectory: "app", 8 | // assetsBuildDirectory: "public/build", 9 | serverModuleFormat: "esm", 10 | }; 11 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/arc/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/arc/server.ts: -------------------------------------------------------------------------------- 1 | import { createRequestHandler } from "@remix-run/architect"; 2 | import * as build from "@remix-run/dev/server-build"; 3 | import { installGlobals } from "@remix-run/node"; 4 | import sourceMapSupport from "source-map-support"; 5 | 6 | sourceMapSupport.install(); 7 | installGlobals({ nativeFetch: true }); 8 | 9 | export const handler = createRequestHandler({ build }); 10 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/arc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "skipLibCheck": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | 20 | // Remix takes care of building everything in `remix build`. 21 | "noEmit": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /functions/\[\[path\]\].js 5 | /functions/\[\[path\]\].js.map 6 | /functions/metafile.* 7 | /functions/version.txt 8 | /public/build 9 | .dev.vars 10 | .wrangler 11 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/.node-version: -------------------------------------------------------------------------------- 1 | 18.0.0 2 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/public/_headers: -------------------------------------------------------------------------------- 1 | /favicon.ico 2 | Cache-Control: public, max-age=3600, s-maxage=3600 3 | /build/* 4 | Cache-Control: public, max-age=31536000, immutable 5 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/public/_routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "include": ["/*"], 4 | "exclude": ["/favicon.ico", "/build/*"] 5 | } 6 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/classic-remix-compiler/cloudflare-pages/public/favicon.ico -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | ignoredRouteFiles: ["**/*.css"], 4 | server: "./server.ts", 5 | serverBuildPath: "functions/[[path]].js", 6 | serverConditions: ["workerd", "worker", "browser"], 7 | serverDependenciesToBundle: "all", 8 | serverMainFields: ["browser", "module", "main"], 9 | serverMinify: true, 10 | serverModuleFormat: "esm", 11 | serverPlatform: "neutral", 12 | // appDirectory: "app", 13 | // assetsBuildDirectory: "public/build", 14 | // publicPath: "/build/", 15 | }; 16 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/server.ts: -------------------------------------------------------------------------------- 1 | import { logDevReady } from "@remix-run/cloudflare"; 2 | import { createPagesFunctionHandler } from "@remix-run/cloudflare-pages"; 3 | import * as build from "@remix-run/dev/server-build"; 4 | 5 | if (process.env.NODE_ENV === "development") { 6 | logDevReady(build); 7 | } 8 | 9 | export const onRequest = createPagesFunctionHandler({ build }); 10 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-pages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "skipLibCheck": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | 20 | // Remix takes care of building everything in `remix build`. 21 | "noEmit": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-workers/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /.wrangler 5 | /build 6 | /public/build 7 | .env 8 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-workers/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-workers/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/classic-remix-compiler/cloudflare-workers/public/favicon.ico -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-workers/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | ignoredRouteFiles: ["**/*.css"], 4 | server: "./server.ts", 5 | serverConditions: ["workerd", "worker", "browser"], 6 | serverDependenciesToBundle: [ 7 | // bundle everything except the virtual module for the static content manifest provided by wrangler 8 | /^(?!.*\b__STATIC_CONTENT_MANIFEST\b).*$/, 9 | ], 10 | serverMainFields: ["browser", "module", "main"], 11 | serverMinify: true, 12 | serverModuleFormat: "esm", 13 | serverPlatform: "neutral", 14 | // appDirectory: "app", 15 | // assetsBuildDirectory: "public/build", 16 | // publicPath: "/build/", 17 | // serverBuildPath: "build/index.js", 18 | }; 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-workers/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | declare module "__STATIC_CONTENT_MANIFEST" { 6 | const manifest: string; 7 | export default manifest; 8 | } 9 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-workers/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "skipLibCheck": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | 20 | // Remix takes care of building everything in `remix build`. 21 | "noEmit": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/cloudflare-workers/wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "remix-cloudflare-workers" 2 | 3 | workers_dev = true 4 | main = "./build/index.js" 5 | # https://developers.cloudflare.com/workers/platform/compatibility-dates 6 | compatibility_date = "2023-04-20" 7 | 8 | [site] 9 | bucket = "./public" 10 | 11 | [build] 12 | command = "npm run build" 13 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/deno/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/deno/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["denoland.vscode-deno"] 3 | } 4 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/deno/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.lint": true 4 | } 5 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/deno/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/deno/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "importMap": ".vscode/resolve_npm_imports.json", 3 | "compilerOptions": { 4 | "lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/deno/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/classic-remix-compiler/deno/public/favicon.ico -------------------------------------------------------------------------------- /templates/classic-remix-compiler/deno/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | module.exports = { 3 | ignoredRouteFiles: ["**/*.css"], 4 | server: "./server.ts", 5 | serverConditions: ["deno", "worker"], 6 | serverDependenciesToBundle: "all", 7 | serverMainFields: ["module", "main"], 8 | serverModuleFormat: "esm", 9 | serverPlatform: "neutral", 10 | // appDirectory: "app", 11 | // assetsBuildDirectory: "public/build", 12 | // publicPath: "/build/", 13 | // serverBuildPath: "build/index.js", 14 | }; 15 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/deno/server.ts: -------------------------------------------------------------------------------- 1 | import { createRequestHandlerWithStaticFiles } from "@remix-run/deno"; 2 | // Import path interpreted by the Remix compiler 3 | import * as build from "@remix-run/dev/server-build"; 4 | 5 | const remixHandler = createRequestHandlerWithStaticFiles({ 6 | build, 7 | getLoadContext: () => ({}), 8 | }); 9 | 10 | const port = Number(Deno.env.get("PORT")) || 8000; 11 | Deno.serve({ port }, remixHandler); 12 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/express/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/express/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/express/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/classic-remix-compiler/express/public/favicon.ico -------------------------------------------------------------------------------- /templates/classic-remix-compiler/express/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | ignoredRouteFiles: ["**/*.css"], 4 | serverModuleFormat: "esm", 5 | // appDirectory: "app", 6 | // assetsBuildDirectory: "public/build", 7 | // publicPath: "/build/", 8 | // serverBuildPath: "build/index.js", 9 | }; 10 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/express/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/express/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "skipLibCheck": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | 20 | // Remix takes care of building everything in `remix build`. 21 | "noEmit": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/fly/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/fly/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/fly/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/classic-remix-compiler/fly/public/favicon.ico -------------------------------------------------------------------------------- /templates/classic-remix-compiler/fly/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | ignoredRouteFiles: ["**/*.css"], 4 | // appDirectory: "app", 5 | // assetsBuildDirectory: "public/build", 6 | // publicPath: "/build/", 7 | // serverBuildPath: "build/index.js", 8 | }; 9 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/fly/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/fly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "skipLibCheck": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | 20 | // Remix takes care of building everything in `remix build`. 21 | "noEmit": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix-javascript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix-javascript/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | From your terminal: 8 | 9 | ```sh 10 | npm run dev 11 | ``` 12 | 13 | This starts your app in development mode, rebuilding assets on file changes. 14 | 15 | ## Deployment 16 | 17 | First, build your app for production: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then run the app in production mode: 24 | 25 | ```sh 26 | npm start 27 | ``` 28 | 29 | Now you'll need to pick a host to deploy it to. 30 | 31 | ### DIY 32 | 33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready. 34 | 35 | Make sure to deploy the output of `remix build` 36 | 37 | - `build/` 38 | - `public/build/` 39 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix-javascript/app/entry.client.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix-javascript/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/classic-remix-compiler/remix-javascript/public/favicon.ico -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix-javascript/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | ignoredRouteFiles: ["**/*.css"], 4 | // appDirectory: "app", 5 | // assetsBuildDirectory: "public/build", 6 | // publicPath: "/build/", 7 | // serverBuildPath: "build/index.js", 8 | }; 9 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | From your terminal: 8 | 9 | ```sh 10 | npm run dev 11 | ``` 12 | 13 | This starts your app in development mode, rebuilding assets on file changes. 14 | 15 | ## Deployment 16 | 17 | First, build your app for production: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then run the app in production mode: 24 | 25 | ```sh 26 | npm start 27 | ``` 28 | 29 | Now you'll need to pick a host to deploy it to. 30 | 31 | ### DIY 32 | 33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready. 34 | 35 | Make sure to deploy the output of `remix build` 36 | 37 | - `build/` 38 | - `public/build/` 39 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/classic-remix-compiler/remix/public/favicon.ico -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix/remix.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@remix-run/dev').AppConfig} */ 2 | export default { 3 | ignoredRouteFiles: ["**/*.css"], 4 | // appDirectory: "app", 5 | // assetsBuildDirectory: "public/build", 6 | // publicPath: "/build/", 7 | // serverBuildPath: "build/index.js", 8 | }; 9 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix/remix.env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /templates/classic-remix-compiler/remix/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "moduleResolution": "Bundler", 9 | "resolveJsonModule": true, 10 | "target": "ES2022", 11 | "strict": true, 12 | "allowJs": true, 13 | "skipLibCheck": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "baseUrl": ".", 16 | "paths": { 17 | "~/*": ["./app/*"] 18 | }, 19 | 20 | // Remix takes care of building everything in `remix build`. 21 | "noEmit": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /templates/cloudflare-workers/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.wrangler 4 | /build 5 | .env 6 | .dev.vars 7 | -------------------------------------------------------------------------------- /templates/cloudflare-workers/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/cloudflare-workers/app/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | @apply bg-white dark:bg-gray-950; 8 | 9 | @media (prefers-color-scheme: dark) { 10 | color-scheme: dark; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/cloudflare-workers/load-context.ts: -------------------------------------------------------------------------------- 1 | import { type PlatformProxy } from "wrangler"; 2 | 3 | type GetLoadContextArgs = { 4 | request: Request; 5 | context: { 6 | cloudflare: Omit, "dispose" | "caches" | "cf"> & { 7 | caches: PlatformProxy["caches"] | CacheStorage; 8 | cf: Request["cf"]; 9 | }; 10 | }; 11 | }; 12 | 13 | declare module "@remix-run/cloudflare" { 14 | // eslint-disable-next-line @typescript-eslint/no-empty-interface 15 | interface AppLoadContext extends ReturnType { 16 | // This will merge the result of `getLoadContext` into the `AppLoadContext` 17 | } 18 | } 19 | 20 | export function getLoadContext({ context }: GetLoadContextArgs) { 21 | return context; 22 | } 23 | -------------------------------------------------------------------------------- /templates/cloudflare-workers/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /templates/cloudflare-workers/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/cloudflare-workers/public/favicon.ico -------------------------------------------------------------------------------- /templates/cloudflare-workers/public/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/cloudflare-workers/public/logo-dark.png -------------------------------------------------------------------------------- /templates/cloudflare-workers/public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/cloudflare-workers/public/logo-light.png -------------------------------------------------------------------------------- /templates/cloudflare-workers/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: [ 9 | "Inter", 10 | "ui-sans-serif", 11 | "system-ui", 12 | "sans-serif", 13 | "Apple Color Emoji", 14 | "Segoe UI Emoji", 15 | "Segoe UI Symbol", 16 | "Noto Color Emoji", 17 | ], 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } satisfies Config; 23 | -------------------------------------------------------------------------------- /templates/cloudflare-workers/worker-configuration.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by Wrangler by running `wrangler types` 2 | 3 | interface Env {} 4 | -------------------------------------------------------------------------------- /templates/cloudflare-workers/wrangler.toml: -------------------------------------------------------------------------------- 1 | #:schema node_modules/wrangler/config-schema.json 2 | name = "remix-cloudflare-workers-template" 3 | 4 | main = "./server.ts" 5 | workers_dev = true 6 | # https://developers.cloudflare.com/workers/platform/compatibility-dates 7 | compatibility_date = "2024-09-26" 8 | 9 | [assets] 10 | # https://developers.cloudflare.com/workers/static-assets/binding/ 11 | directory = "./build/client" 12 | 13 | [build] 14 | command = "npm run build" 15 | -------------------------------------------------------------------------------- /templates/cloudflare/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | .dev.vars 7 | 8 | .wrangler 9 | -------------------------------------------------------------------------------- /templates/cloudflare/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/cloudflare/app/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | @apply bg-white dark:bg-gray-950; 8 | 9 | @media (prefers-color-scheme: dark) { 10 | color-scheme: dark; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/cloudflare/functions/[[path]].ts: -------------------------------------------------------------------------------- 1 | import { createPagesFunctionHandler } from "@remix-run/cloudflare-pages"; 2 | 3 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 4 | // @ts-ignore - the server build file is generated by `remix vite:build` 5 | // eslint-disable-next-line import/no-unresolved 6 | import * as build from "../build/server"; 7 | 8 | export const onRequest = createPagesFunctionHandler({ build }); 9 | -------------------------------------------------------------------------------- /templates/cloudflare/load-context.ts: -------------------------------------------------------------------------------- 1 | import { type PlatformProxy } from "wrangler"; 2 | 3 | // When using `wrangler.toml` to configure bindings, 4 | // `wrangler types` will generate types for those bindings 5 | // into the global `Env` interface. 6 | // Need this empty interface so that typechecking passes 7 | // even if no `wrangler.toml` exists. 8 | // eslint-disable-next-line @typescript-eslint/no-empty-interface 9 | interface Env {} 10 | 11 | type Cloudflare = Omit, "dispose">; 12 | 13 | declare module "@remix-run/cloudflare" { 14 | interface AppLoadContext { 15 | cloudflare: Cloudflare; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /templates/cloudflare/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /templates/cloudflare/public/_headers: -------------------------------------------------------------------------------- 1 | /favicon.ico 2 | Cache-Control: public, max-age=3600, s-maxage=3600 3 | /assets/* 4 | Cache-Control: public, max-age=31536000, immutable 5 | -------------------------------------------------------------------------------- /templates/cloudflare/public/_routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "include": ["/*"], 4 | "exclude": ["/favicon.ico", "/assets/*"] 5 | } 6 | -------------------------------------------------------------------------------- /templates/cloudflare/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/cloudflare/public/favicon.ico -------------------------------------------------------------------------------- /templates/cloudflare/public/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/cloudflare/public/logo-dark.png -------------------------------------------------------------------------------- /templates/cloudflare/public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/cloudflare/public/logo-light.png -------------------------------------------------------------------------------- /templates/cloudflare/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: [ 9 | "Inter", 10 | "ui-sans-serif", 11 | "system-ui", 12 | "sans-serif", 13 | "Apple Color Emoji", 14 | "Segoe UI Emoji", 15 | "Segoe UI Symbol", 16 | "Noto Color Emoji", 17 | ], 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } satisfies Config; 23 | -------------------------------------------------------------------------------- /templates/cloudflare/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { 2 | vitePlugin as remix, 3 | cloudflareDevProxyVitePlugin as remixCloudflareDevProxy, 4 | } from "@remix-run/dev"; 5 | import { defineConfig } from "vite"; 6 | import tsconfigPaths from "vite-tsconfig-paths"; 7 | 8 | declare module "@remix-run/cloudflare" { 9 | interface Future { 10 | v3_singleFetch: true; 11 | } 12 | } 13 | 14 | export default defineConfig({ 15 | plugins: [ 16 | remixCloudflareDevProxy(), 17 | remix({ 18 | future: { 19 | v3_fetcherPersist: true, 20 | v3_relativeSplatPath: true, 21 | v3_throwAbortReason: true, 22 | v3_singleFetch: true, 23 | v3_lazyRouteDiscovery: true, 24 | }, 25 | }), 26 | tsconfigPaths(), 27 | ], 28 | }); 29 | -------------------------------------------------------------------------------- /templates/express/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | -------------------------------------------------------------------------------- /templates/express/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/express/app/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | @apply bg-white dark:bg-gray-950; 8 | 9 | @media (prefers-color-scheme: dark) { 10 | color-scheme: dark; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/express/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /templates/express/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/express/public/favicon.ico -------------------------------------------------------------------------------- /templates/express/public/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/express/public/logo-dark.png -------------------------------------------------------------------------------- /templates/express/public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/express/public/logo-light.png -------------------------------------------------------------------------------- /templates/express/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: [ 9 | "Inter", 10 | "ui-sans-serif", 11 | "system-ui", 12 | "sans-serif", 13 | "Apple Color Emoji", 14 | "Segoe UI Emoji", 15 | "Segoe UI Symbol", 16 | "Noto Color Emoji", 17 | ], 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } satisfies Config; 23 | -------------------------------------------------------------------------------- /templates/express/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | declare module "@remix-run/node" { 6 | interface Future { 7 | v3_singleFetch: true; 8 | } 9 | } 10 | 11 | export default defineConfig({ 12 | plugins: [ 13 | remix({ 14 | future: { 15 | v3_fetcherPersist: true, 16 | v3_relativeSplatPath: true, 17 | v3_throwAbortReason: true, 18 | v3_singleFetch: true, 19 | v3_lazyRouteDiscovery: true, 20 | }, 21 | }), 22 | tsconfigPaths(), 23 | ], 24 | }); 25 | -------------------------------------------------------------------------------- /templates/remix-javascript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | -------------------------------------------------------------------------------- /templates/remix-javascript/app/entry.client.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/remix-javascript/app/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | @apply bg-white dark:bg-gray-950; 8 | 9 | @media (prefers-color-scheme: dark) { 10 | color-scheme: dark; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/remix-javascript/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /templates/remix-javascript/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/remix-javascript/public/favicon.ico -------------------------------------------------------------------------------- /templates/remix-javascript/public/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/remix-javascript/public/logo-dark.png -------------------------------------------------------------------------------- /templates/remix-javascript/public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/remix-javascript/public/logo-light.png -------------------------------------------------------------------------------- /templates/remix-javascript/tailwind.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 3 | theme: { 4 | extend: { 5 | fontFamily: { 6 | sans: [ 7 | "Inter", 8 | "ui-sans-serif", 9 | "system-ui", 10 | "sans-serif", 11 | "Apple Color Emoji", 12 | "Segoe UI Emoji", 13 | "Segoe UI Symbol", 14 | "Noto Color Emoji", 15 | ], 16 | }, 17 | }, 18 | }, 19 | plugins: [], 20 | }; 21 | -------------------------------------------------------------------------------- /templates/remix-javascript/vite.config.js: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | 4 | export default defineConfig({ 5 | plugins: [ 6 | remix({ 7 | future: { 8 | v3_fetcherPersist: true, 9 | v3_relativeSplatPath: true, 10 | v3_throwAbortReason: true, 11 | v3_singleFetch: true, 12 | v3_lazyRouteDiscovery: true, 13 | }, 14 | }), 15 | ], 16 | }); 17 | -------------------------------------------------------------------------------- /templates/remix-tutorial/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | -------------------------------------------------------------------------------- /templates/remix-tutorial/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | 5 | ## Development 6 | 7 | From your terminal: 8 | 9 | ```sh 10 | npm run dev 11 | ``` 12 | 13 | This starts your app in development mode, rebuilding assets on file changes. 14 | 15 | ## Deployment 16 | 17 | First, build your app for production: 18 | 19 | ```sh 20 | npm run build 21 | ``` 22 | 23 | Then run the app in production mode: 24 | 25 | ```sh 26 | npm start 27 | ``` 28 | 29 | Now you'll need to pick a host to deploy it to. 30 | 31 | ### DIY 32 | 33 | If you're familiar with deploying node applications, the built-in Remix app server is production-ready. 34 | 35 | Make sure to deploy the output of `remix build` 36 | 37 | - `build/server` 38 | - `build/client` 39 | -------------------------------------------------------------------------------- /templates/remix-tutorial/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/remix-tutorial/public/favicon.ico -------------------------------------------------------------------------------- /templates/remix-tutorial/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | remix({ 8 | ignoredRouteFiles: ["**/*.css"], 9 | }), 10 | tsconfigPaths(), 11 | ], 12 | }); 13 | -------------------------------------------------------------------------------- /templates/remix/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | -------------------------------------------------------------------------------- /templates/remix/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/remix/app/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | @apply bg-white dark:bg-gray-950; 8 | 9 | @media (prefers-color-scheme: dark) { 10 | color-scheme: dark; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/remix/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /templates/remix/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/remix/public/favicon.ico -------------------------------------------------------------------------------- /templates/remix/public/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/remix/public/logo-dark.png -------------------------------------------------------------------------------- /templates/remix/public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/remix/public/logo-light.png -------------------------------------------------------------------------------- /templates/remix/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: [ 9 | "Inter", 10 | "ui-sans-serif", 11 | "system-ui", 12 | "sans-serif", 13 | "Apple Color Emoji", 14 | "Segoe UI Emoji", 15 | "Segoe UI Symbol", 16 | "Noto Color Emoji", 17 | ], 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } satisfies Config; 23 | -------------------------------------------------------------------------------- /templates/remix/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | declare module "@remix-run/node" { 6 | interface Future { 7 | v3_singleFetch: true; 8 | } 9 | } 10 | 11 | export default defineConfig({ 12 | plugins: [ 13 | remix({ 14 | future: { 15 | v3_fetcherPersist: true, 16 | v3_relativeSplatPath: true, 17 | v3_throwAbortReason: true, 18 | v3_singleFetch: true, 19 | v3_lazyRouteDiscovery: true, 20 | }, 21 | }), 22 | tsconfigPaths(), 23 | ], 24 | }); 25 | -------------------------------------------------------------------------------- /templates/spa/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /public/build 6 | .env 7 | -------------------------------------------------------------------------------- /templates/spa/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /templates/spa/app/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | @apply bg-white dark:bg-gray-950; 8 | 9 | @media (prefers-color-scheme: dark) { 10 | color-scheme: dark; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /templates/spa/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /templates/spa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/spa/public/favicon.ico -------------------------------------------------------------------------------- /templates/spa/public/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/spa/public/logo-dark.png -------------------------------------------------------------------------------- /templates/spa/public/logo-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remix-run/remix/2e74a9f4b9ced338100e3f6d18fe1d72f36418cd/templates/spa/public/logo-light.png -------------------------------------------------------------------------------- /templates/spa/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 5 | theme: { 6 | extend: { 7 | fontFamily: { 8 | sans: [ 9 | "Inter", 10 | "ui-sans-serif", 11 | "system-ui", 12 | "sans-serif", 13 | "Apple Color Emoji", 14 | "Segoe UI Emoji", 15 | "Segoe UI Symbol", 16 | "Noto Color Emoji", 17 | ], 18 | }, 19 | }, 20 | }, 21 | plugins: [], 22 | } satisfies Config; 23 | -------------------------------------------------------------------------------- /templates/spa/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["env.d.ts", "**/*.ts", "**/*.tsx"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "types": ["@remix-run/node", "vite/client"], 6 | "isolatedModules": true, 7 | "esModuleInterop": true, 8 | "jsx": "react-jsx", 9 | "module": "ESNext", 10 | "moduleResolution": "Bundler", 11 | "resolveJsonModule": true, 12 | "target": "ES2022", 13 | "strict": true, 14 | "allowJs": true, 15 | "skipLibCheck": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "~/*": ["./app/*"] 20 | }, 21 | 22 | // Remix takes care of building everything in `remix build`. 23 | "noEmit": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /templates/spa/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | 5 | declare module "@remix-run/node" { 6 | interface Future { 7 | v3_singleFetch: true; 8 | } 9 | } 10 | 11 | export default defineConfig({ 12 | plugins: [ 13 | remix({ 14 | ssr: false, 15 | future: { 16 | v3_fetcherPersist: true, 17 | v3_relativeSplatPath: true, 18 | v3_throwAbortReason: true, 19 | v3_singleFetch: true, 20 | v3_lazyRouteDiscovery: true, 21 | }, 22 | }), 23 | tsconfigPaths(), 24 | ], 25 | }); 26 | --------------------------------------------------------------------------------