diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index e5ebc4189cc..2096864cbad 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -30,6 +30,11 @@ jobs: node-version-file: ".nvmrc" cache: "pnpm" + - name: 🦕 Install Deno + uses: denoland/setup-deno@v1 + with: + deno-version: vx.x.x + - name: 📥 Install deps run: pnpm install --frozen-lockfile @@ -42,11 +47,6 @@ jobs: - name: 👔 Format run: pnpm format - - name: 🦕 Install Deno - uses: denoland/setup-deno@v1 - with: - deno-version: vx.x.x - - name: 👔 Format Deno files run: pnpm format:deno diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 95515d2b7b9..e6be4e96847 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,6 +28,11 @@ jobs: node-version-file: ".nvmrc" cache: "pnpm" + - name: 🦕 Install Deno + uses: denoland/setup-deno@v1 + with: + deno-version: vx.x.x + - name: Disable GitHub Actions Annotations run: | echo "::remove-matcher owner=tsc::" @@ -40,10 +45,5 @@ jobs: - name: 🔬 Lint run: pnpm lint - - name: 🦕 Install Deno - uses: denoland/setup-deno@v1 - with: - deno-version: vx.x.x - - name: 🔬 Lint deno files run: pnpm lint:deno diff --git a/.github/workflows/shared-test-unit.yml b/.github/workflows/shared-test-unit.yml index e8210320f83..8af89dd602b 100644 --- a/.github/workflows/shared-test-unit.yml +++ b/.github/workflows/shared-test-unit.yml @@ -38,6 +38,11 @@ jobs: node-version: ${{ matrix.node }} cache: "pnpm" + - name: 🦕 Install Deno + uses: denoland/setup-deno@v1 + with: + deno-version: vx.x.x + - name: Disable GitHub Actions Annotations run: | echo "::remove-matcher owner=tsc::" @@ -47,11 +52,6 @@ jobs: - name: 📥 Install deps run: pnpm install --frozen-lockfile - - name: 🦕 Install Deno - uses: denoland/setup-deno@v1 - with: - deno-version: vx.x.x - # It's faster to use the built `cli.js` in tests if its available and up-to-date - name: 🏗 Build run: pnpm build diff --git a/integration/helpers/vite-deno-template/deno.jsonc b/integration/helpers/vite-deno-template/deno.jsonc index 0e9265e7307..d51ec8a1de2 100644 --- a/integration/helpers/vite-deno-template/deno.jsonc +++ b/integration/helpers/vite-deno-template/deno.jsonc @@ -1,24 +1,21 @@ { "tasks": { - "build": "deno run -A npm:@remix-run/dev@^2.11.2 vite:build", - "dev": "deno run -A npm:@remix-run/dev@^2.11.2 vite:dev", + "build": "deno run -A npm:@remix-run/dev@* vite:build", + "dev": "deno run -A npm:@remix-run/dev@* vite:dev", "typecheck": "deno check '**/*' && deno run -A npm:typescript@^5.5.4/tsc", "typegen": "deno types > ./app/deno.d.ts" }, "exclude": ["app/", "build/"], "nodeModulesDir": true, + "unstable": ["kv"], "imports": { - "@remix-run/dev": "npm:@remix-run/dev@^2.11.2", - "@remix-run/express": "npm:@remix-run/express@^2.11.2", - "@remix-run/react": "npm:@remix-run/react@^2.11.2", - "@remix-run/server-runtime": "npm:@remix-run/server-runtime@^2.11.2", - "@std/http": "jsr:@std/http@^1.0.4", - "@std/path": "jsr:@std/path@^1.0.3", - "@types/node": "npm:@types/node@^22.5.1", + // These remix packages should be treated like workspace:* dependencies. + "@remix-run/dev": "npm:@remix-run/dev@*", + "@remix-run/react": "npm:@remix-run/react@*", + "@remix-run/server-runtime": "npm:@remix-run/server-runtime@*", "@types/react": "npm:@types/react@^18.3.5", "@types/react-dom": "npm:@types/react-dom@^18.3.0", "isbot": "npm:isbot@^5.1.17", - "postcss": "npm:postcss@^8.4.41", "react": "npm:react@^18.3.1", "react-dom": "npm:react-dom@^18.3.1", "typescript": "npm:typescript@^5.5.4", diff --git a/integration/helpers/vite.ts b/integration/helpers/vite.ts index 1cb61291259..64d928ecc61 100644 --- a/integration/helpers/vite.ts +++ b/integration/helpers/vite.ts @@ -396,7 +396,7 @@ async function waitForServer( let devStderr = bufferize(proc.stderr); await waitOn({ - resources: [`http://localhost:${args.port}${args.basename ?? "/"}`], + resources: [`http://127.0.0.1:${args.port}${args.basename ?? "/"}`], timeout: 10000, }).catch((err) => { let stdout = devStdout(); diff --git a/integration/vite-deno-test.ts b/integration/vite-deno-test.ts index 694dbf5eae9..210b158a6a5 100644 --- a/integration/vite-deno-test.ts +++ b/integration/vite-deno-test.ts @@ -6,6 +6,8 @@ import { test, viteConfig } from "./helpers/vite.js"; const files: Files = async ({ port }) => ({ "vite.config.ts": dedent` + import { vitePlugin as remix } from "@remix-run/dev"; + export default { ${await viteConfig.server({ port })} plugins: [ diff --git a/package.json b/package.json index db3e41ce083..73dfde35065 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "playground:new": "node ./scripts/playground/new.js", "publish": "node ./scripts/publish.js", "publish:private": "node ./scripts/publish-private.js", + "prepare": "node ./scripts/install-deno-deps.js integration/helpers/vite-deno-template templates/deno", "release": "node ./scripts/release.js", "test": "pnpm run \"/^test:.*/\"", "pretest:integration": "pnpm build", diff --git a/packages/remix-dev/config/defaults/entry.server.deno.tsx b/packages/remix-dev/config/defaults/entry.server.deno.tsx index ed939e4d0d5..2c455e3f955 100644 --- a/packages/remix-dev/config/defaults/entry.server.deno.tsx +++ b/packages/remix-dev/config/defaults/entry.server.deno.tsx @@ -1,7 +1,7 @@ import type { AppLoadContext, EntryContext } from "@remix-run/server-runtime"; import { RemixServer } from "@remix-run/react"; import * as isbotModule from "isbot"; -import { renderToReadableStream } from "react-dom/server"; +import { renderToReadableStream } from "react-dom/server.browser"; export default async function handleRequest( request: Request, diff --git a/scripts/copy-build-to-dist.mjs b/scripts/copy-build-to-dist.mjs index 1ad3808f83a..4ac1e1412d5 100644 --- a/scripts/copy-build-to-dist.mjs +++ b/scripts/copy-build-to-dist.mjs @@ -1,6 +1,6 @@ -import path from "node:path"; -import fse from "fs-extra"; import chalk from "chalk"; +import fse from "fs-extra"; +import path from "node:path"; const args = process.argv.slice(2); const tsc = process.env.CI || args.includes("--tsc"); @@ -9,6 +9,11 @@ const ROOT_DIR = process.cwd(); const PACKAGES_PATH = path.join(ROOT_DIR, "packages"); const DEFAULT_BUILD_PATH = path.join(ROOT_DIR, "build"); +// pnpm workspaces do not understand Deno projects and vice versa so we need to specify which projects need their node_modules updating +const DENO_NODE_MODULES_PATHS = [ + path.join(ROOT_DIR, "integration/helpers/vite-deno-template/node_modules"), +]; + let activeOutputDir = DEFAULT_BUILD_PATH; if (process.env.LOCAL_BUILD_DIRECTORY) { let appDir = path.resolve(process.env.LOCAL_BUILD_DIRECTORY); @@ -38,6 +43,8 @@ async function copyBuildToDist() { PACKAGES_PATH, parentDir === "@remix-run" ? `remix-${dirName}` : dirName ), + nodeModulesPath: + parentDir === "@remix-run" ? `${parentDir}/${dirName}` : dirName, }; }); @@ -50,13 +57,35 @@ async function copyBuildToDist() { "node", "globals.d.ts" ); - console.log(chalk.yellow(` 🛠 Writing globals.d.ts shim to ${dest}`)); + console.log(chalk.yellow(` 🛠 Writing globals.d.ts shim to ${dest}`)); await fse.writeFile(dest, "export * from './dist/globals';"); /** @type {Promise[]} */ let copyQueue = []; for (let pkg of packages) { try { + // Copy entire build artifact to node_modules dir for each Deno project that requires it + for (let denoNodeModulesPath of DENO_NODE_MODULES_PATHS) { + let destPath = path.join(denoNodeModulesPath, pkg.nodeModulesPath); + if (await fse.pathExists(destPath)) { + copyQueue.push( + (async () => { + console.log( + chalk.yellow( + ` 🛠 🦕 Copying ${path.relative( + ROOT_DIR, + pkg.build + )} to ${path.relative(ROOT_DIR, destPath)}` + ) + ); + fse.copy(pkg.build, destPath, { + recursive: true, + }); + })() + ); + } + } + let srcPath = path.join(pkg.build, "dist"); let destPath = path.join(pkg.src, "dist"); if (!(await fse.stat(srcPath)).isDirectory()) { @@ -66,7 +95,7 @@ async function copyBuildToDist() { (async () => { console.log( chalk.yellow( - ` 🛠 Copying ${path.relative( + ` 🛠 Copying ${path.relative( ROOT_DIR, srcPath )} to ${path.relative(ROOT_DIR, destPath)}` @@ -117,7 +146,7 @@ async function copyBuildToDist() { (async () => { let src = path.relative(ROOT_DIR, path.join(...srcFile.split("/"))); let dest = path.relative(ROOT_DIR, path.join(...destFile.split("/"))); - console.log(chalk.yellow(` 🛠 Copying ${src} to ${dest}`)); + console.log(chalk.yellow(` 🛠 Copying ${src} to ${dest}`)); await fse.copy(src, dest); })() ) @@ -126,7 +155,7 @@ async function copyBuildToDist() { await Promise.all(copyQueue); console.log( chalk.green( - " ✅ Successfully copied build files to package dist directories!" + " ✅ Successfully copied build files to package dist directories!" ) ); } diff --git a/scripts/install-deno-deps.js b/scripts/install-deno-deps.js new file mode 100644 index 00000000000..2d117f03693 --- /dev/null +++ b/scripts/install-deno-deps.js @@ -0,0 +1,23 @@ +const { spawnSync } = require("node:child_process"); +const path = require("node:path"); + +const denoProjectPaths = process.argv + .slice(2) + .map((denoProjectDir) => path.join(process.cwd(), denoProjectDir)); + +for (let denoProjectPath of denoProjectPaths) { + let { error } = spawnSync("deno", ["install", "--no-lock"], { + cwd: denoProjectPath, + env: { ...process.env, DENO_FUTURE: "1" }, + stdio: "inherit", + }); + + if (error) { + console.warn( + new Error( + `Failed to install dependencies for Deno project at ${denoProjectPath}`, + { cause: error } + ) + ); + } +}