├── .gitignore
├── .eslintrc
├── public
└── favicon.ico
├── remix.env.d.ts
├── app
├── lib
│ └── test.server.ts
├── entry.client.tsx
├── services.server
│ └── service.ts
├── entry.server.tsx
├── root.tsx
└── routes
│ └── index.tsx
├── remix.config.js
├── tsconfig.json
├── README.md
├── package.json
└── patches
└── @remix-run+dev+1.6.5.patch
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | /.cache
4 | /build
5 | /public/build
6 | .env
7 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["@remix-run/eslint-config", "@remix-run/eslint-config/node"]
3 | }
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kiliman/remix-server-folders/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/app/lib/test.server.ts:
--------------------------------------------------------------------------------
1 | console.log("test.server.ts", "Only run on server");
2 |
3 | export function testServer() {
4 | return "test server";
5 | }
6 |
--------------------------------------------------------------------------------
/app/entry.client.tsx:
--------------------------------------------------------------------------------
1 | import { RemixBrowser } from "@remix-run/react";
2 | import { hydrate } from "react-dom";
3 |
4 | hydrate(, document);
5 |
--------------------------------------------------------------------------------
/app/services.server/service.ts:
--------------------------------------------------------------------------------
1 | console.log("service.ts", "Only run on server");
2 | export function serviceOnSever() {
3 | return "service on server";
4 | }
5 |
--------------------------------------------------------------------------------
/remix.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@remix-run/dev').AppConfig} */
2 | module.exports = {
3 | ignoredRouteFiles: ["**/.*"],
4 | // appDirectory: "app",
5 | // assetsBuildDirectory: "public/build",
6 | // serverBuildPath: "build/index.js",
7 | // publicPath: "/build/",
8 | };
9 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
3 | "compilerOptions": {
4 | "lib": ["DOM", "DOM.Iterable", "ES2019"],
5 | "isolatedModules": true,
6 | "esModuleInterop": true,
7 | "jsx": "react-jsx",
8 | "moduleResolution": "node",
9 | "resolveJsonModule": true,
10 | "target": "ES2019",
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 |
--------------------------------------------------------------------------------
/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 | let markup = renderToString(
12 |
13 | );
14 |
15 | responseHeaders.set("Content-Type", "text/html");
16 |
17 | return new Response("" + markup, {
18 | status: responseStatusCode,
19 | headers: responseHeaders,
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/app/root.tsx:
--------------------------------------------------------------------------------
1 | import type { MetaFunction } from "@remix-run/node";
2 | import {
3 | Links,
4 | LiveReload,
5 | Meta,
6 | Outlet,
7 | Scripts,
8 | ScrollRestoration,
9 | } from "@remix-run/react";
10 |
11 | export const meta: MetaFunction = () => ({
12 | charset: "utf-8",
13 | title: "New Remix App",
14 | viewport: "width=device-width,initial-scale=1",
15 | });
16 |
17 | export default function App() {
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 📦 remix-server-folders
2 |
3 | This patch updates the Remix compiler to treat all files in any folder named with `.server` extension as _server only_ files. In other words, it acts like you named all the files with `*.server.ts` extension.
4 |
5 | This just makes it easier to add files to the **server** folder without having to change the name.
6 |
7 | See example. Both methods work.
8 |
9 | ```
10 | ├── lib
11 | │ └── test.server.ts
12 | └── services.server
13 | └── service.ts
14 | ```
15 |
16 | To install, add `patch-package` to your project, then copy the _patch_ file for your specific Remix version to the `/patches` folder in your project. Also add `"postinstall": "patch-package"` to _package.json_
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "sideEffects": false,
4 | "scripts": {
5 | "postinstall": "patch-package",
6 | "build": "remix build",
7 | "dev": "remix dev",
8 | "start": "remix-serve build"
9 | },
10 | "dependencies": {
11 | "@remix-run/node": "^1.6.5",
12 | "@remix-run/react": "^1.6.5",
13 | "@remix-run/serve": "^1.6.5",
14 | "react": "^17.0.2",
15 | "react-dom": "^17.0.2"
16 | },
17 | "devDependencies": {
18 | "@remix-run/dev": "^1.6.5",
19 | "@remix-run/eslint-config": "^1.6.5",
20 | "@types/react": "^17.0.47",
21 | "@types/react-dom": "^17.0.17",
22 | "eslint": "^8.20.0",
23 | "patch-package": "^6.4.7",
24 | "typescript": "^4.7.4"
25 | },
26 | "engines": {
27 | "node": ">=14"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/routes/index.tsx:
--------------------------------------------------------------------------------
1 | import { json, type LoaderArgs } from "@remix-run/node";
2 | import { useLoaderData } from "@remix-run/react";
3 | import { testServer } from "~/lib/test.server";
4 | import { serviceOnSever } from "~/services.server/service";
5 |
6 | // uncomment this code and it'll break on client render
7 | //const test = testServer();
8 | //const service = serviceOnSever();
9 |
10 | export const loader = async ({ request }: LoaderArgs) => {
11 | const test = testServer();
12 | const service = serviceOnSever();
13 | return json({ test, service });
14 | };
15 |
16 | export default function Index() {
17 | const data = useLoaderData();
18 | return (
19 |
20 |
Welcome to Remix
21 |
{JSON.stringify(data, null, 2)}
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/patches/@remix-run+dev+1.6.5.patch:
--------------------------------------------------------------------------------
1 | diff --git a/node_modules/@remix-run/dev/dist/compiler.js b/node_modules/@remix-run/dev/dist/compiler.js
2 | index 9d39471..5c0783a 100644
3 | --- a/node_modules/@remix-run/dev/dist/compiler.js
4 | +++ b/node_modules/@remix-run/dev/dist/compiler.js
5 | @@ -314,7 +314,7 @@ async function createBrowserBuild(config, options) {
6 | entryPoints[id] = path__namespace.resolve(config.appDirectory, config.routes[id].file) + "?browser";
7 | }
8 |
9 | - let plugins = [urlImportsPlugin.urlImportsPlugin(), mdx.mdxPlugin(config), browserRouteModulesPlugin.browserRouteModulesPlugin(config, /\?browser$/), emptyModulesPlugin.emptyModulesPlugin(config, /\.server(\.[jt]sx?)?$/), nodeModulesPolyfill.NodeModulesPolyfillPlugin(), esbuildPluginPnp.pnpPlugin()];
10 | + let plugins = [urlImportsPlugin.urlImportsPlugin(), mdx.mdxPlugin(config), browserRouteModulesPlugin.browserRouteModulesPlugin(config, /\?browser$/), emptyModulesPlugin.emptyModulesPlugin(config, /(\.server(\.[jt]sx?)?$)|(\/\w*\.server\/)/), nodeModulesPolyfill.NodeModulesPolyfillPlugin(), esbuildPluginPnp.pnpPlugin()];
11 | return esbuild__namespace.build({
12 | entryPoints,
13 | outdir: config.assetsBuildDirectory,
14 |
--------------------------------------------------------------------------------