Skip to content

Commit

Permalink
chore(playground): add playground (remix-run#2663)
Browse files Browse the repository at this point in the history
Co-authored-by: Michaël De Boey <[email protected]>
  • Loading branch information
kentcdodds and MichaelDeBoey authored Apr 7, 2022
1 parent d9e36a1 commit e7b7c40
Show file tree
Hide file tree
Showing 39 changed files with 1,515 additions and 1 deletion.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
!.eslintrc.js
templates/deno
.tmp
/playground
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ yarn-error.log
/scripts/deployment-test/yarn.lock

/.idea/
/playground
/scripts/playground/template.local
/scripts/playground/template/build
/scripts/playground/template/package-lock.json
16 changes: 15 additions & 1 deletion docs/pages/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,21 @@ We use [Yarn workspaces](https://classic.yarnpkg.com/en/docs/workspaces/) to man

### Building

Running `yarn build` from the root directory will run the build.
Running `yarn build` from the root directory will run the build. You can run the build in watch mode with `yarn watch`.

### Playground

It's often really useful to be able to interact with a real app while developing features for apps. So you can place an app in the `playground` directory and the build process will automatically copy all the output to the `node_modules` of all the apps in the `playground` directory for you. It will even trigger a live reload event for you!

To generate a new playground, simply run:

```sh
yarn playground:new <?name>
```

Where the name of the playground is optional and defaults to `playground-${Date.now()}`. Then you can `cd` into the directory that's generated for you and run `npm run dev`. In another teminal window have `yarn watch` running and you're ready to work on whatever Remix features you like with live reload magic 🧙‍♂️

The playground generated from `yarn playground:new` is based on a template in `scripts/playground/template`. If you'd like to change anything about the template, you can create a custom one in `scripts/playground/template.local` which is `.gitignored` so you can customize it to your heart's content.

### Testing

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"test:integration": "jest --forceExit --runInBand --config ./integration/jest.config.js",
"pretest:integration": "rollup -c",
"bug-report-test": "yarn jest --config ./integration/jest.config.js integration/bug-report-test.ts",
"playground:new": "node ./scripts/playground/new.js",
"version": "node ./scripts/version.js",
"watch": "rollup -c -w",
"lint": "eslint --cache --ext .tsx,.ts,.js,.jsx,.md .",
Expand Down
3 changes: 3 additions & 0 deletions playground/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Playground

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)
60 changes: 60 additions & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import babel from "@rollup/plugin-babel";
import nodeResolve from "@rollup/plugin-node-resolve";
import copy from "rollup-plugin-copy";
import fse from "fs-extra";
import fs from "fs";

const executableBanner = "#!/usr/bin/env node\n";

Expand Down Expand Up @@ -83,6 +84,7 @@ function createRemix() {
{ src: `${sourceDir}/README.md`, dest: outputDir },
],
}),
copyToPlaygrounds(),
],
},
];
Expand Down Expand Up @@ -118,6 +120,7 @@ function remix() {
{ src: `${sourceDir}/README.md`, dest: outputDir },
],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -136,6 +139,7 @@ function remix() {
exclude: /node_modules/,
extensions: [".ts"],
}),
copyToPlaygrounds(),
],
},
];
Expand Down Expand Up @@ -196,6 +200,7 @@ function remixDev() {
};
},
},
copyToPlaygrounds(),
],
},
{
Expand All @@ -215,6 +220,7 @@ function remixDev() {
extensions: [".ts"],
}),
nodeResolve({ extensions: [".ts"] }),
copyToPlaygrounds(),
],
},
{
Expand All @@ -234,6 +240,7 @@ function remixDev() {
extensions: [".ts"],
}),
nodeResolve({ extensions: [".ts"] }),
copyToPlaygrounds(),
],
},
{
Expand All @@ -253,6 +260,7 @@ function remixDev() {
extensions: [".ts"],
}),
nodeResolve({ extensions: [".ts"] }),
copyToPlaygrounds(),
],
},
];
Expand Down Expand Up @@ -291,6 +299,7 @@ function remixServerRuntime() {
{ src: `${sourceDir}/README.md`, dest: outputDir },
],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -311,6 +320,7 @@ function remixServerRuntime() {
extensions: [".ts", ".tsx"],
}),
nodeResolve({ extensions: [".ts", ".tsx"] }),
copyToPlaygrounds(),
],
},
{
Expand All @@ -329,6 +339,7 @@ function remixServerRuntime() {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -347,6 +358,7 @@ function remixServerRuntime() {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
},
];
Expand Down Expand Up @@ -385,6 +397,7 @@ function remixNode() {
{ src: `${sourceDir}/README.md`, dest: outputDir },
],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -403,6 +416,7 @@ function remixNode() {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -421,6 +435,7 @@ function remixNode() {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
},
];
Expand Down Expand Up @@ -459,6 +474,7 @@ function remixCloudflare() {
{ src: `${sourceDir}/README.md`, dest: outputDir },
],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -477,6 +493,7 @@ function remixCloudflare() {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -495,6 +512,7 @@ function remixCloudflare() {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
},
];
Expand Down Expand Up @@ -525,6 +543,7 @@ function remixCloudflareWorkers() {
extensions: [".ts", ".tsx"],
}),
nodeResolve({ extensions: [".ts", ".tsx"] }),
copyToPlaygrounds(),
],
},
];
Expand Down Expand Up @@ -555,6 +574,7 @@ function remixCloudflarePages() {
extensions: [".ts", ".tsx"],
}),
nodeResolve({ extensions: [".ts", ".tsx"] }),
copyToPlaygrounds(),
],
},
];
Expand Down Expand Up @@ -596,6 +616,7 @@ function getAdapterConfig(adapterName) {
{ src: `${sourceDir}/README.md`, dest: outputDir },
],
}),
copyToPlaygrounds(),
],
},
...(hasMagicExports
Expand All @@ -616,6 +637,7 @@ function getAdapterConfig(adapterName) {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -634,6 +656,7 @@ function getAdapterConfig(adapterName) {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
},
]
Expand Down Expand Up @@ -688,6 +711,7 @@ function remixReact() {
{ src: `${sourceDir}/README.md`, dest: outputDir },
],
}),
copyToPlaygrounds(),
],
};

Expand All @@ -711,6 +735,7 @@ function remixReact() {
extensions: [".ts", ".tsx"],
}),
nodeResolve({ extensions: [".ts", ".tsx"] }),
copyToPlaygrounds(),
],
};

Expand All @@ -731,6 +756,7 @@ function remixReact() {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
};

Expand All @@ -751,6 +777,7 @@ function remixReact() {
exclude: /node_modules/,
extensions: [".ts", ".tsx"],
}),
copyToPlaygrounds(),
],
};

Expand Down Expand Up @@ -795,6 +822,7 @@ function remixServe() {
{ src: `${sourceDir}/README.md`, dest: outputDir },
],
}),
copyToPlaygrounds(),
],
},
{
Expand All @@ -814,6 +842,7 @@ function remixServe() {
extensions: [".ts"],
}),
nodeResolve({ extensions: [".ts"] }),
copyToPlaygrounds(),
],
},
];
Expand All @@ -838,3 +867,34 @@ export default function rollup(options) {

return builds;
}

function copyToPlaygrounds() {
return {
name: "copy-to-remix-playground",
async writeBundle(options, bundle) {
let playgroundsDir = path.join(__dirname, "playground");
let playgrounds = await fs.promises.readdir(playgroundsDir);
let writtenDir = path.join(__dirname, options.dir);
for (let playground of playgrounds) {
let playgroundDir = path.join(playgroundsDir, playground);
if (!fse.statSync(playgroundDir).isDirectory()) {
continue;
}
let destDir = writtenDir.replace(
path.join(__dirname, "build"),
playgroundDir
);
await fse.copy(writtenDir, destDir);

// tickle live reload by touching the server entry
let serverEntry = ["entry.server.tsx", "entry.server.jsx"].find(
(entryPath) =>
fse.existsSync(path.join(playgroundDir, "app", entryPath))
);
let serverEntryPath = path.join(playgroundDir, "app", serverEntry);
let serverEntryContent = await fse.readFile(serverEntryPath);
await fse.writeFile(serverEntryPath, serverEntryContent);
}
},
};
}
69 changes: 69 additions & 0 deletions scripts/playground/new.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env node

// this generates a new playground project in the .gitignored playground directory
// yarn playground:new <?name>

let path = require("path");
let { execSync } = require("child_process");
let fse = require("fs-extra");

createNewProject(process.argv[2]);

async function createNewProject(name = `playground-${Date.now()}`) {
let projectDir = path.join(__dirname, "../../playground", name);
let localTemplate = path.join(__dirname, "template.local");
let hasLocalTemplate = await fse.exists(localTemplate);
if (hasLocalTemplate) {
console.log(`ℹ️ Using local template: ${localTemplate}`);
} else {
console.log(
`ℹ️ Using default template. If you want to customize it, make a project in ${localTemplate.replace(
process.cwd(),
"."
)} and we'll use that one instead.`
);
}
let templateDir = hasLocalTemplate
? localTemplate
: path.join(__dirname, "template");
if (await fse.pathExists(projectDir)) {
throw new Error(
`🚨 A playground with the name ${name} already exists. Delete it first or use a different name.`
);
}
await fse.copy(templateDir, projectDir, {
filter(src, dest) {
return !src.includes("node_modules");
},
});

console.log("📥 Installing deps...");
execSync(`npm install`, { stdio: "inherit", cwd: projectDir });

let remixDeps = path.join(__dirname, "../../build/node_modules");

console.log("🏗 Building remix...");
execSync(`yarn rollup -c`, { stdio: "inherit" });

console.log("🚚 Copying remix deps...");
await fse.copy(remixDeps, path.join(projectDir, "node_modules"), {
overwrite: true,
});

let relativeProjectDir = projectDir.replace(process.cwd(), ".");
let hasInit = await fse.exists(path.join(projectDir, "remix.init"));
if (hasInit) {
console.log("🎬 Running Remix Init...");
execSync(`node ./node_modules/@remix-run/dev/cli init`, {
stdio: "inherit",
cwd: projectDir,
});
} else {
console.log(
`ℹ️ No remix.init directory found in ${relativeProjectDir}. Skipping init.`
);
}
console.log(
`✅ Done! Now in one terminal run \`yarn watch\` in the root of the remix repo and in another cd into ${relativeProjectDir} and run \`npm run dev\` and you should be set.`
);
}
2 changes: 2 additions & 0 deletions scripts/playground/template/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
DATABASE_URL="file:./data.db?connection_limit=1"
SESSION_SECRET="super-duper-s3cret"
6 changes: 6 additions & 0 deletions scripts/playground/template/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
**/public/build

**/prisma/data.db
**/prisma/data.db-journal

**/app/styles/tailwind.css
Loading

0 comments on commit e7b7c40

Please sign in to comment.