diff --git a/examples/yarn-pnp/.eslintrc.js b/examples/yarn-pnp/.eslintrc.js new file mode 100644 index 00000000000..ced78085f86 --- /dev/null +++ b/examples/yarn-pnp/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"], +}; diff --git a/examples/yarn-pnp/.gitignore b/examples/yarn-pnp/.gitignore new file mode 100644 index 00000000000..61ea1d3ccea --- /dev/null +++ b/examples/yarn-pnp/.gitignore @@ -0,0 +1,19 @@ +node_modules + +/.cache +/build +/public/build +/package-lock.json + +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Swap the comments on the following lines if you wish to use zero-installs +# See https://yarnpkg.com/features/zero-installs and +# https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored +.pnp.* +# !.yarn/cache diff --git a/examples/yarn-pnp/README.md b/examples/yarn-pnp/README.md new file mode 100644 index 00000000000..dec12bce575 --- /dev/null +++ b/examples/yarn-pnp/README.md @@ -0,0 +1,54 @@ +# Welcome to Remix! + +This is a very basic example of a Remix app, using the Remix App Server and Yarn PnP. + +- [Remix Docs](https://remix.run/docs) +- [Yarn Plug'n'Play](https://next.yarnpkg.com/features/pnp) + +## Development + +From your terminal + +```sh +yarn install +yarn dev +``` + +This starts your app in development mode, rebuilding assets on file changes. + +## Deployment + +First, build your app for production: + +```sh +yarn build +``` + +Then run the app in production mode: + +```sh +yarn start +``` + +## Notes for Using Yarn PnP + +- You'll need to use Yarn ≥ v3.2.0. Older versions don't work because of [an issue with Yarn](https://github.com/yarnpkg/berry/issues/3687). +- For editor support of PnP, refer to [Editor SDKs](https://yarnpkg.com/getting-started/editor-sdks). +- When using TypeScript, consider installing the [Yarn TypeScript plugin](https://github.com/yarnpkg/berry/tree/master/packages/plugin-typescript). +- For the `~/*` alias to work for imports relative to `app/*`, you have to add this to your `package.json`: + ```json + "dependencies": { + /* ... */ + "~": "link:app/" + } + ``` + You can then also remove the `~` alias from your `tsconfig.json`. +- For only installing non-dev dependencies in production, you can use [`yarn workspaces focus`](https://yarnpkg.com/cli/workspaces/focus) after removing the `.yarn/cache` directory: + ```sh + yarn install + yarn build + rm -r .yarn/cache + yarn workspaces focus --production + yarn start + ``` + Or check out [plugin-installs](https://gitlab.com/Larry1123/yarn-contrib/-/blob/master/packages/plugin-production-install/README.md) by [Larry1123](https://gitlab.com/Larry1123). diff --git a/examples/yarn-pnp/app/entry.client.tsx b/examples/yarn-pnp/app/entry.client.tsx new file mode 100644 index 00000000000..3eec1fd0a02 --- /dev/null +++ b/examples/yarn-pnp/app/entry.client.tsx @@ -0,0 +1,4 @@ +import { RemixBrowser } from "@remix-run/react"; +import { hydrate } from "react-dom"; + +hydrate(, document); diff --git a/examples/yarn-pnp/app/entry.server.tsx b/examples/yarn-pnp/app/entry.server.tsx new file mode 100644 index 00000000000..5afa18235cc --- /dev/null +++ b/examples/yarn-pnp/app/entry.server.tsx @@ -0,0 +1,21 @@ +import type { EntryContext } from "@remix-run/node"; +import { RemixServer } from "@remix-run/react"; +import { renderToString } from "react-dom/server"; + +export default function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext +) { + const markup = renderToString( + + ); + + responseHeaders.set("Content-Type", "text/html"); + + return new Response("" + markup, { + status: responseStatusCode, + headers: responseHeaders, + }); +} diff --git a/examples/yarn-pnp/app/root.tsx b/examples/yarn-pnp/app/root.tsx new file mode 100644 index 00000000000..927a0f745df --- /dev/null +++ b/examples/yarn-pnp/app/root.tsx @@ -0,0 +1,32 @@ +import type { MetaFunction } from "@remix-run/node"; +import { + Links, + LiveReload, + Meta, + Outlet, + Scripts, + ScrollRestoration, +} from "@remix-run/react"; + +export const meta: MetaFunction = () => ({ + charset: "utf-8", + title: "New Remix App", + viewport: "width=device-width,initial-scale=1", +}); + +export default function App() { + return ( + + + + + + + + + + + + + ); +} diff --git a/examples/yarn-pnp/app/routes/index.tsx b/examples/yarn-pnp/app/routes/index.tsx new file mode 100644 index 00000000000..da28b224ef3 --- /dev/null +++ b/examples/yarn-pnp/app/routes/index.tsx @@ -0,0 +1,18 @@ +export default function Index() { + return ( +
+

Welcome to Remix

+

+ This example is using{" "} + + Yarn PnP + + ! +

+
+ ); +} diff --git a/examples/yarn-pnp/package.json b/examples/yarn-pnp/package.json new file mode 100644 index 00000000000..e7fb41b63e5 --- /dev/null +++ b/examples/yarn-pnp/package.json @@ -0,0 +1,32 @@ +{ + "name": "remix-example-yarn-pnp", + "private": true, + "description": "", + "license": "", + "sideEffects": false, + "scripts": { + "build": "remix build", + "dev": "remix dev", + "start": "remix-serve build" + }, + "dependencies": { + "@remix-run/node": "1.5.1", + "@remix-run/react": "1.5.1", + "@remix-run/serve": "1.5.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "~": "link:./app" + }, + "devDependencies": { + "@remix-run/dev": "1.5.1", + "@types/react": "^17.0.24", + "@types/react-dom": "^17.0.9", + "esbuild": ">=0.10.0", + "express": "^4.17.1", + "typescript": "^4.1.2" + }, + "engines": { + "node": ">=14" + }, + "packageManager": "yarn@3.2.1" +} diff --git a/examples/yarn-pnp/public/favicon.ico b/examples/yarn-pnp/public/favicon.ico new file mode 100644 index 00000000000..8830cf6821b Binary files /dev/null and b/examples/yarn-pnp/public/favicon.ico differ diff --git a/examples/yarn-pnp/remix.config.js b/examples/yarn-pnp/remix.config.js new file mode 100644 index 00000000000..260b82c7cb1 --- /dev/null +++ b/examples/yarn-pnp/remix.config.js @@ -0,0 +1,10 @@ +/** + * @type {import('@remix-run/dev').AppConfig} + */ +module.exports = { + ignoredRouteFiles: ["**/.*"], + // appDirectory: "app", + // assetsBuildDirectory: "public/build", + // serverBuildPath: "build/index.js", + // publicPath: "/build/", +}; diff --git a/examples/yarn-pnp/remix.env.d.ts b/examples/yarn-pnp/remix.env.d.ts new file mode 100644 index 00000000000..72e2affe311 --- /dev/null +++ b/examples/yarn-pnp/remix.env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/examples/yarn-pnp/sandbox.config.json b/examples/yarn-pnp/sandbox.config.json new file mode 100644 index 00000000000..4363d87a30d --- /dev/null +++ b/examples/yarn-pnp/sandbox.config.json @@ -0,0 +1,6 @@ +{ + "hardReloadOnChange": true, + "container": { + "port": 3000 + } +} diff --git a/examples/yarn-pnp/tsconfig.json b/examples/yarn-pnp/tsconfig.json new file mode 100644 index 00000000000..53f97889224 --- /dev/null +++ b/examples/yarn-pnp/tsconfig.json @@ -0,0 +1,19 @@ +{ + "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], + "compilerOptions": { + "lib": ["DOM", "DOM.Iterable", "ES2019"], + "isolatedModules": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "moduleResolution": "node", + "resolveJsonModule": true, + "target": "ES2019", + "strict": true, + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + + // Remix takes care of building everything in `remix build`. + "noEmit": true + } +}