Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(playground): add playground #2663

Merged
merged 13 commits into from
Apr 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 🧙‍♂️
machour marked this conversation as resolved.
Show resolved Hide resolved

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