From c68c9a99737f2e8401ef6ea4086d419b79bdf189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Tue, 8 Aug 2023 16:13:22 +0200 Subject: [PATCH 01/18] chore: use `build.mode` wherever possible (#7089) --- docs/guides/envvars.md | 7 ++----- docs/guides/manual-mode.md | 2 +- docs/other-api/dev.md | 2 +- integration/helpers/cf-template/server.ts | 5 +---- integration/helpers/deno-template/server.ts | 2 +- integration/hmr-test.ts | 5 +++-- templates/arc/server.ts | 2 +- templates/cloudflare-pages/server.ts | 2 +- templates/express/server.js | 2 +- 9 files changed, 12 insertions(+), 17 deletions(-) diff --git a/docs/guides/envvars.md b/docs/guides/envvars.md index 0e80c598292..17d42246106 100644 --- a/docs/guides/envvars.md +++ b/docs/guides/envvars.md @@ -53,11 +53,8 @@ Then, you can pass those through via `getLoadContext` in your server file: ```ts export const onRequest = createPagesFunctionHandler({ build, - getLoadContext(context) { - // Hand-off Cloudflare ENV vars to the Remix `context` object - return { env: context.env }; - }, - mode: process.env.NODE_ENV, + getLoadContext: (context) => ({ env: context.env }), // Hand-off Cloudflare ENV vars to the Remix `context` object + mode: build.mode, }); ``` diff --git a/docs/guides/manual-mode.md b/docs/guides/manual-mode.md index cb9cdd5bf98..68b1eacfd55 100644 --- a/docs/guides/manual-mode.md +++ b/docs/guides/manual-mode.md @@ -250,7 +250,7 @@ app.all( ? createDevRequestHandler(build) : createRequestHandler({ build, - mode: process.env.NODE_ENV, + mode: build.mode, }) ); ``` diff --git a/docs/other-api/dev.md b/docs/other-api/dev.md index d492ae6d583..848d3a351d0 100644 --- a/docs/other-api/dev.md +++ b/docs/other-api/dev.md @@ -95,7 +95,7 @@ app.all( "*", createRequestHandler({ build, - mode: process.env.NODE_ENV, + mode: build.mode, }) ); diff --git a/integration/helpers/cf-template/server.ts b/integration/helpers/cf-template/server.ts index 4f4b2ad0aff..49eda486cf8 100644 --- a/integration/helpers/cf-template/server.ts +++ b/integration/helpers/cf-template/server.ts @@ -1,7 +1,4 @@ import { createEventHandler } from "@remix-run/cloudflare-workers"; import * as build from "@remix-run/dev/server-build"; -addEventListener( - "fetch", - createEventHandler({ build, mode: process.env.NODE_ENV }) -); +addEventListener("fetch", createEventHandler({ build, mode: build.mode })); diff --git a/integration/helpers/deno-template/server.ts b/integration/helpers/deno-template/server.ts index 87e95bf7b18..943b4f0616e 100644 --- a/integration/helpers/deno-template/server.ts +++ b/integration/helpers/deno-template/server.ts @@ -5,8 +5,8 @@ import * as build from "@remix-run/dev/server-build"; const remixHandler = createRequestHandlerWithStaticFiles({ build, - mode: process.env.NODE_ENV, getLoadContext: () => ({}), + mode: build.mode, }); const port = Number(Deno.env.get("PORT")) || 8000; diff --git a/integration/hmr-test.ts b/integration/hmr-test.ts index 69231d25384..5fefafc6058 100644 --- a/integration/hmr-test.ts +++ b/integration/hmr-test.ts @@ -59,12 +59,13 @@ let fixture = (options: { appPort: number; devPort: number }): FixtureInit => ({ app.use(express.static("public", { immutable: true, maxAge: "1y" })); const BUILD_DIR = path.join(process.cwd(), "build"); + const build = require(BUILD_DIR); app.all( "*", createRequestHandler({ - build: require(BUILD_DIR), - mode: process.env.NODE_ENV, + build, + mode: build.mode, }) ); diff --git a/templates/arc/server.ts b/templates/arc/server.ts index dee2e3177cf..fba9f66780b 100644 --- a/templates/arc/server.ts +++ b/templates/arc/server.ts @@ -8,5 +8,5 @@ installGlobals(); export const handler = createRequestHandler({ build, - mode: process.env.NODE_ENV, + mode: build.mode, }); diff --git a/templates/cloudflare-pages/server.ts b/templates/cloudflare-pages/server.ts index d8f4dcf1425..56df96a4aa7 100644 --- a/templates/cloudflare-pages/server.ts +++ b/templates/cloudflare-pages/server.ts @@ -9,5 +9,5 @@ if (process.env.NODE_ENV === "development") { export const onRequest = createPagesFunctionHandler({ build, getLoadContext: (context) => ({ env: context.env }), - mode: process.env.NODE_ENV, + mode: build.mode, }); diff --git a/templates/express/server.js b/templates/express/server.js index 3c8f90a8423..75fa7d7579b 100644 --- a/templates/express/server.js +++ b/templates/express/server.js @@ -42,7 +42,7 @@ app.all( ? createDevRequestHandler() : createRequestHandler({ build, - mode: process.env.NODE_ENV, + mode: build.mode, }) ); From 40a687e7aebe0eabd0bfb9eaf7ca100d840c2936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Tue, 8 Aug 2023 16:37:53 +0200 Subject: [PATCH 02/18] feat(remix-server-runtime): use `type-fest`'s `Jsonify` type in `Serialize` (#6642) Co-authored-by: Pedro Cattori --- packages/remix-server-runtime/package.json | 3 +- packages/remix-server-runtime/serialize.ts | 67 +++------------------- 2 files changed, 11 insertions(+), 59 deletions(-) diff --git a/packages/remix-server-runtime/package.json b/packages/remix-server-runtime/package.json index 380bf47e21a..1c633b009e1 100644 --- a/packages/remix-server-runtime/package.json +++ b/packages/remix-server-runtime/package.json @@ -21,7 +21,8 @@ "@web3-storage/multipart-parser": "^1.0.0", "cookie": "^0.4.1", "set-cookie-parser": "^2.4.8", - "source-map": "^0.7.3" + "source-map": "^0.7.3", + "type-fest": "^4.0.0" }, "devDependencies": { "@remix-run/web-file": "^3.0.3", diff --git a/packages/remix-server-runtime/serialize.ts b/packages/remix-server-runtime/serialize.ts index 6fd357b315c..6592ac52a52 100644 --- a/packages/remix-server-runtime/serialize.ts +++ b/packages/remix-server-runtime/serialize.ts @@ -1,51 +1,21 @@ +import type { Jsonify } from "type-fest"; + import type { AppData } from "./data"; import type { TypedDeferredData, TypedResponse } from "./responses"; -type JsonPrimitive = - | string - | number - | boolean - | String - | Number - | Boolean - | null; -type NonJsonPrimitive = undefined | Function | symbol; - -/* - * `any` is the only type that can let you equate `0` with `1` - * See https://stackoverflow.com/a/49928360/1490091 - */ -type IsAny = 0 extends 1 & T ? true : false; - -// prettier-ignore -type Serialize = - IsAny extends true ? any : - T extends TypedDeferredData ? SerializeDeferred : - T extends JsonPrimitive ? T : - T extends NonJsonPrimitive ? never : - T extends { toJSON(): infer U } ? U : - T extends [] ? [] : - T extends [unknown, ...unknown[]] ? SerializeTuple : - T extends ReadonlyArray ? (U extends NonJsonPrimitive ? null : Serialize)[] : - T extends object ? SerializeObject> : - never -; - -/** JSON serialize [tuples](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) */ -type SerializeTuple = T extends [infer F, ...infer R] - ? [Serialize, ...SerializeTuple] - : []; +// Note: The return value has to be `any` and not `unknown` so it can match `void`. +type ArbitraryFunction = (...args: any[]) => any; +type NotJsonable = ArbitraryFunction | undefined | symbol; -/** JSON serialize objects (not including arrays) and classes */ -type SerializeObject = { - [k in keyof T as T[k] extends NonJsonPrimitive ? never : k]: Serialize; -}; +type Serialize = T extends TypedDeferredData + ? SerializeDeferred + : Jsonify; // prettier-ignore type SerializeDeferred> = { [k in keyof T as T[k] extends Promise ? k : - T[k] extends NonJsonPrimitive ? never : + T[k] extends NotJsonable ? never : k ]: T[k] extends Promise @@ -53,25 +23,6 @@ type SerializeDeferred> = { : Serialize extends never ? k : Serialize; }; -/* - * For an object T, if it has any properties that are a union with `undefined`, - * make those into optional properties instead. - * - * Example: { a: string | undefined} --> { a?: string} - */ -type UndefinedToOptional = { - // Property is not a union with `undefined`, keep as-is - [k in keyof T as undefined extends T[k] ? never : k]: T[k]; -} & { - // Property _is_ a union with `defined`. Set as optional (via `?`) and remove `undefined` from the union - [k in keyof T as undefined extends T[k] ? k : never]?: Exclude< - T[k], - undefined - >; -}; - -type ArbitraryFunction = (...args: any[]) => unknown; - /** * Infer JSON serialized data type returned by a loader or action. * From 8bc1b13d09e81415b18d2937c224a8365d3ce21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Tue, 8 Aug 2023 17:18:31 +0200 Subject: [PATCH 03/18] docs: remove `other-api/dev-v2` (#7088) Co-authored-by: Pedro Cattori --- docs/other-api/dev-v2.md | 389 --------------------------------------- 1 file changed, 389 deletions(-) delete mode 100644 docs/other-api/dev-v2.md diff --git a/docs/other-api/dev-v2.md b/docs/other-api/dev-v2.md deleted file mode 100644 index 33a8d6726c1..00000000000 --- a/docs/other-api/dev-v2.md +++ /dev/null @@ -1,389 +0,0 @@ ---- -title: "@remix-run/dev CLI (v2)" -order: 2 -new: true ---- - -# Remix CLI (v2) - -The Remix CLI comes from the `@remix-run/dev` package. It also includes the compiler. Make sure it is in your `package.json` `devDependencies` so it doesn't get deployed to your server. - -To get a full list of available commands and flags, run: - -```sh -npx @remix-run/dev -h -``` - -## `remix build` - -Builds your app for production. This command will set `process.env.NODE_ENV` to `production` and minify the output for deployment. - -```sh -remix build -``` - -### Options - -| Option | flag | config | default | -| ---------------------------------------- | ------------- | ------ | ------- | -| Generate sourcemaps for production build | `--sourcemap` | N/A | `false` | - -## `remix dev` - -Runs the Remix compiler in watch mode and spins up your app server. - -The Remix compiler will: - -1. Set `NODE_ENV` to `development` -2. Watch your app code for changes and trigger rebuilds -3. Restart your app server whenever rebuilds succeed -4. Send code updates to the browser via Live Reload and HMR + Hot Data Revalidation - -πŸŽ₯ For an introduction and deep dive into HMR and HDR in Remix, check out our videos: - -- [HMR and Hot Data Revalidation πŸ”₯][hmr-and-hdr] -- [Mental model for the new dev flow 🧠][mental-model] -- [Migrating your project to v2 dev flow 🚚][migrating] - - - -What is "Hot Data Revalidation"? - -Like HMR, HDR is a way of hot updating your app without needing to refresh the page. -That way you can keep your app state as your edits are applied in your app. -HMR handles client-side code updates like when you change the components, markup, or styles in your app. -Likewise, HDR handles server-side code updates. - -That means any time your change a `loader` on your current page (or any code that your `loader` depends on), Remix will re-fetch data from your changed loader. -That way your app is _always_ up-to-date with the latest code changes, client-side or server-side. - -To learn more about how HMR and HDR work together, check out [Pedro's talk at Remix Conf 2023][legendary-dx]. - - - -### With custom app server - -If you used a template to get started, hopefully it's already integrated with `remix dev` out-of-the-box. -If not, you can follow these steps to integrate your project with `remix dev`: - -1. Replace your dev scripts in `package.json` and use `-c` to specify your app server command: - -```json filename=package.json -{ - "scripts": { - "dev": "remix dev -c \"node ./server.js\"" - } -} -``` - -2. Ensure `broadcastDevReady` is called when your app server is up and running: - -```js filename=server.js lines=[12,25-27] -import path from "node:path"; - -import { broadcastDevReady } from "@remix-run/node"; -import express from "express"; - -const BUILD_DIR = path.resolve(__dirname, "build"); -const build = require(BUILD_DIR); - -const app = express(); - -// ... code for setting up your express app goes here ... - -app.all( - "*", - createRequestHandler({ - build, - mode: process.env.NODE_ENV, - }) -); - -const port = 3000; -app.listen(port, () => { - console.log(`πŸ‘‰ http://localhost:${port}`); - - if (process.env.NODE_ENV === "development") { - broadcastDevReady(build); - } -}); -``` - - - -For CloudFlare, use `logDevReady` instead of `broadcastDevReady`. - -Why? `broadcastDevReady` uses `fetch` to send a ready message to the Remix compiler, -but CloudFlare does not support async I/O like `fetch` outside of request handling. - - - -### Options - -Options priority order is: 1. flags, 2. config, 3. defaults. - -| Option | flag | config | default | description | -| --------------- | ------------------ | --------- | --------------------------------- | -------------------------------------------------------- | -| Command | `-c` / `--command` | `command` | `remix-serve ` | Command used to run your app server | -| Manual | `--manual` | `manual` | `false` | See [guide for manual mode][manual-mode] | -| Port | `--port` | `port` | Dynamically chosen open port | Internal port used by the Remix compiler for hot updates | -| TLS key | `--tls-key` | `tlsKey` | N/A | TLS key for configuring local HTTPS | -| TLS certificate | `--tls-cert` | `tlsCert` | N/A | TLS certificate for configuring local HTTPS | - -For example: - -```js filename=remix.config.js -/** @type {import('@remix-run/dev').AppConfig} */ -module.exports = { - dev: { - // ...any other options you want to set go here... - manual: true, - tlsKey: "./key.pem", - tlsCert: "./cert.pem", - }, -}; -``` - -### Setting a custom port - -The `remix dev --port` option sets the internal port used for hot updates. -**It does not affect the port your app runs on.** - -To set your app server port, set it the way you normally would in production. -For example, you may have it hardcoded in your `server.js` file. - -If you are using `remix-serve` as your app server, you can use its `--port` flag to set the app server port: - -``` -remix dev -c "remix-serve --port 8000 ./build" -``` - -In contrast, the `remix dev --port` option is an escape-hatch for users who need fine-grain control of network ports. -Most users, should not need to use `remix dev --port`. - -### Manual mode - -By default, `remix dev` will restart your app server whenever a rebuild occurs. -If you'd like to keep your app server running without restarts across rebuilds, check out our [guide for manual mode][manual-mode]. - -You can see if app server restarts are a bottleneck for your project by comparing the times reported by `remix dev`: - -- `rebuilt (Xms)` πŸ‘‰ the Remix compiler took `X` milliseconds to rebuild your app -- `app server ready (Yms)` πŸ‘‰ Remix restarted your app server and it took `Y` milliseconds to start with the new code changes - -### Pick up changes from other packages - -If you are using a monorepo, you might want Remix to perform hot updates not only when your app code changes, but whenever you change code in any of your apps dependencies. - -For example, you could have a UI library package (`packages/ui`) that is used within your Remix app (`packages/app`). -To pick up changes in `packages/ui`, you can configure [watchPaths][watch-paths] to include your packages. - -### How to set up MSW - -To use [Mock Service Worker][msw] in development, you'll need to: - -1. Run MSW as part of your app server -2. Configure MSW to not mock internal "dev ready" messages to the Remix compiler - -Make sure that you are setting up your mocks for your _app server_ within the `-c` flag so that the `REMIX_DEV_ORIGIN` environment variable is available to your mocks. -For example, you can use `NODE_OPTIONS` to set Node's `--require` flag when running `remix-serve`: - -```json filename=package.json -{ - "scripts": { - "dev": "remix dev -c \"npm run dev:app\"", - "dev:app": "cross-env NODE_OPTIONS=\"--require ./mocks\" remix-serve ./build" - } -} -``` - -Next, you can use `REMIX_DEV_ORIGIN` to let MSW forward internal "dev ready" messages on `/ping`: - -```ts -import { rest } from "msw"; - -const REMIX_DEV_PING = new URL( - process.env.REMIX_DEV_ORIGIN -); -REMIX_DEV_PING.pathname = "/ping"; - -export const server = setupServer( - rest.post(REMIX_DEV_PING.href, (req) => req.passthrough()) - // ... other request handlers go here ... -); -``` - -### How to set up local HTTPS - -For this example, let's use [mkcert][mkcert]. -After you have it installed, make sure to: - -- Create a local Certificate Authority if you haven't already done so -- Use `NODE_EXTRA_CA_CERTS` for Node compatibility - -```sh -mkcert -install # create a local CA -export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem" # tell Node to use our local CA -``` - -Now, create the TLS key and certificate: - -```sh -mkcert -key-file key.pem -cert-file cert.pem localhost -``` - -πŸ‘† You can change `localhost` to something else if you are using custom hostnames. - -Next, use the `key.pem` and `cert.pem` to get HTTPS working locally with your app server. -This depends on what you are using for your app server. -For example, here's how you could use HTTPS with an Express server: - -```ts filename=server.js -import fs from "node:fs"; -import https from "node:https"; -import path from "node:path"; - -import express from "express"; - -const BUILD_DIR = path.resolve(__dirname, "build"); -const build = require(BUILD_DIR); - -const app = express(); - -// ... code setting up your express app goes here ... - -const server = https.createServer( - { - key: fs.readFileSync("path/to/key.pem"), - cert: fs.readFileSync("path/to/cert.pem"), - }, - app -); - -const port = 3000; -server.listen(port, () => { - console.log(`πŸ‘‰ https://localhost:${port}`); - - if (process.env.NODE_ENV === "development") { - broadcastDevReady(build); - } -}); -``` - -Now that the app server is set up, you should be able to build and run your app in production mode with TLS. -To get the Remix compiler to interop with TLS, you'll need to specify the TLS cert and key you created: - -```sh -remix dev --tls-key=key.pem --tls-cert=cert.pem -c "node ./server.js" -``` - -Alternatively, you can specify the TLS key and cert via the `dev.tlsCert` and `dev.tlsKey` config options. -Now your app server and Remix compiler are TLS ready! - -### How to integrate with a reverse proxy - -Let's say you have the app server and Remix compiler both running on the same machine: - -- App server πŸ‘‰ `http://localhost:1234` -- Remix compiler πŸ‘‰ `http://localhost:5678` - -Then, you setup a reverse proxy in front of the app server: - -- Reverse proxy πŸ‘‰ `https://myhost` - -But the internal HTTP and WebSocket connections to support hot updates will still try to reach the Remix compiler's unproxied origin: - -- Hot updates πŸ‘‰ `http://localhost:5678` / `ws://localhost:5678` ❌ - -To get the internal connections to point to the reverse proxy, you can use the `REMIX_DEV_ORIGIN` environment variable: - -```sh -REMIX_DEV_ORIGIN=https://myhost remix dev -``` - -Now, hot updates will be sent correctly to the proxy: - -- Hot updates πŸ‘‰ `https://myhost` / `wss://myhost` βœ… - -### Performance tuning and debugging - -#### Path imports - -Currently, when Remix rebuilds your app, the compiler has to process your app code along with any of its dependencies. -The compiler treeshakes unused code from app so that you don't ship any unused code to browser and so that you keep your server as slim as possible. -But the compiler still needs to _crawl_ all the code to know what to keep and what to treeshake away. - -In short, this means that the way you do imports and exports can have a big impact on how long it takes to rebuild your app. -For example, if you are using a library like Material UI or AntD you can likely speed up your builds by using [path imports][path-imports]: - -```diff -- import { Button, TextField } from '@mui/material'; -+ import Button from '@mui/material/Button'; -+ import TextField from '@mui/material/TextField'; -``` - -In the future, Remix could pre-bundle dependencies in development to avoid this problem entirely. -But today, you can help the compiler out by using path imports. - -#### Debugging bundles - -Dependending on your app and dependencies, you might be processing much more code than your app needs. -Check out our [bundle analysis guide][bundle-analysis] for more details. - -### Troubleshooting - -#### HMR: hot updates losing app state - -Hot Module Replacement is supposed to keep your app's state around between hot updates. -But in some cases React cannot distinguish between existing components being changed and new components being added. -[React needs `key`s][react-keys] to disambiguate these cases and track changes when sibling elements are modified. - -Additionally, when adding or removing hooks, React Refresh treats that as a brand-new component. -So if you add `useLoaderData` to your component, you may lose state local to that component. - -These are limitations of React and [React Refresh][react-refresh], not Remix. - -#### HDR: every code change triggers HDR - -Hot Data Revalidation detects loader changes by trying to bundle each loader and then fingerprinting the content for each. -It relies on tree shaking to determine whether your changes affect each loader or not. - -To ensure that tree shaking can reliably detect changes to loaders, make sure you declare that your app's package is side effect free: - -```json filename=package.json -{ - "sideEffects": false -} -``` - -#### HDR: harmless console errors when loader data is removed - -When you delete a loader or remove some of the data being returned by that loader, your app should be hot updated correctly. -But you may notice console errors logged in your browser. - -React strict-mode and React Suspense can cause multiple renders when hot updates are applied. -Most of these render correctly, including the final render that is visible to you. -But intermediate renders can sometimes use new loader data with old React components, which is where those errors come from. - -We are continuing to investigate the underlying race condition to see if we can smooth that over. -In the meantime, if those console errors bother you, you can refresh the page whenever they occur. - -#### HDR: performance - -When the Remix compiler builds (and rebuilds) your app, you may notice a slight slowdown as the compiler needs to crawl the dependencies for each loader. -That way Remix can detect loader changes on rebuilds. - -While the initial build slowdown is inherently a cost for HDR, we plan to optimize rebuilds so that there is no perceivable slowdown for HDR rebuilds. - -[hmr-and-hdr]: https://www.youtube.com/watch?v=2c2OeqOX72s -[mental-model]: https://www.youtube.com/watch?v=zTrjaUt9hLo -[migrating]: https://www.youtube.com/watch?v=6jTL8GGbIuc -[legendary-dx]: https://www.youtube.com/watch?v=79M4vYZi-po -[watch-paths]: https://remix.run/docs/en/1.17.1/file-conventions/remix-config#watchpaths -[react-keys]: https://react.dev/learn/rendering-lists#why-does-react-need-keys -[react-refresh]: https://github.com/facebook/react/tree/main/packages/react-refresh -[msw]: https://mswjs.io/ -[mkcert]: https://github.com/FiloSottile/mkcert -[path-imports]: https://mui.com/material-ui/guides/minimizing-bundle-size/#option-one-use-path-imports -[bundle-analysis]: ../guides/performance -[manual-mode]: ../guides/manual-mode From b2d8691e02a6775109b1f3230be3fddb43815139 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Tue, 8 Aug 2023 12:50:51 -0400 Subject: [PATCH 04/18] chore: add `deduplicate-yarn` workflow (#6109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Logan McAnsh Co-authored-by: MichaΓ«l De Boey --- .github/workflows/deduplicate-yarn.yml | 44 ++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/deduplicate-yarn.yml diff --git a/.github/workflows/deduplicate-yarn.yml b/.github/workflows/deduplicate-yarn.yml new file mode 100644 index 00000000000..3528fbb797a --- /dev/null +++ b/.github/workflows/deduplicate-yarn.yml @@ -0,0 +1,44 @@ +name: βš™οΈ Deduplicate yarn.lock + +on: + push: + branches: + - dev + paths: + - ./yarn.lock + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + format: + if: github.repository == 'remix-run/remix' + runs-on: ubuntu-latest + + steps: + - name: ⬇️ Checkout repo + uses: actions/checkout@v3 + + - name: βŽ” Setup node + uses: actions/setup-node@v3 + with: + node-version-file: ".nvmrc" + cache: "yarn" + + - name: οΈοΈβš™οΈ Dedupe yarn.lock + run: npx yarn-deduplicate && rm -rf ./node_modules && yarn + + - name: πŸ’ͺ Commit + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + + git add . + if [ -z "$(git status --porcelain)" ]; then + echo "πŸ’Ώ no deduplication needed" + exit 0 + fi + git commit -m "chore: deduplicate `yarn.lock`" + git push + echo "πŸ’Ώ https://github.com/$GITHUB_REPOSITORY/commit/$(git rev-parse HEAD)" From ba992fa7f667ffc106787073fe37c780e889108a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20De=20Boey?= Date: Tue, 8 Aug 2023 19:31:04 +0200 Subject: [PATCH 05/18] chore(remix-dev): remove unused `type-fest` dependency (#7047) --- packages/remix-dev/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/remix-dev/package.json b/packages/remix-dev/package.json index 78030778801..446ed3f0b7b 100644 --- a/packages/remix-dev/package.json +++ b/packages/remix-dev/package.json @@ -87,8 +87,7 @@ "msw": "^0.39.2", "shelljs": "^0.8.5", "strip-ansi": "^6.0.1", - "tiny-invariant": "^1.2.0", - "type-fest": "^4.0.0" + "tiny-invariant": "^1.2.0" }, "peerDependencies": { "@remix-run/serve": "^1.19.2", From 23f27efcfa1d2189ce26813a811df3e2f71a4d26 Mon Sep 17 00:00:00 2001 From: Wilco Schoneveld Date: Tue, 8 Aug 2023 20:36:35 +0200 Subject: [PATCH 06/18] feat(remix-react): use unique key for script:ld+json meta descriptors (#6954) Co-authored-by: Matt Brophy --- .changeset/olive-lemons-marry.md | 5 +++++ contributors.yml | 1 + packages/remix-react/components.tsx | 19 ++++++++----------- 3 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 .changeset/olive-lemons-marry.md diff --git a/.changeset/olive-lemons-marry.md b/.changeset/olive-lemons-marry.md new file mode 100644 index 00000000000..e178e0b3401 --- /dev/null +++ b/.changeset/olive-lemons-marry.md @@ -0,0 +1,5 @@ +--- +"@remix-run/react": patch +--- + +Use unique key for `script:ld+json` meta descriptors diff --git a/contributors.yml b/contributors.yml index 62d50ee7fd1..91a7e07bbdd 100644 --- a/contributors.yml +++ b/contributors.yml @@ -533,6 +533,7 @@ - vorcigernix - wangbinyq - weavdale +- wilcoschoneveld - willhack - willin - wizardlyhel diff --git a/packages/remix-react/components.tsx b/packages/remix-react/components.tsx index 50f39d1a153..4b79348dad3 100644 --- a/packages/remix-react/components.tsx +++ b/packages/remix-react/components.tsx @@ -606,21 +606,18 @@ export function Meta() { } if ("script:ld+json" in metaProps) { - let json: string | null = null; try { - json = JSON.stringify(metaProps["script:ld+json"]); - } catch (err) {} - return ( - json != null && ( + let json = JSON.stringify(metaProps["script:ld+json"]); + return (