Skip to content

Commit

Permalink
feat: remove all TypeScript references when isTypeScript is passed …
Browse files Browse the repository at this point in the history
…as `false` to `remix.init`
  • Loading branch information
MichaelDeBoey committed Aug 24, 2022
1 parent 1e6f4aa commit 5916fb3
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 67 deletions.
10 changes: 6 additions & 4 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
/**
* @type {import('@types/eslint').Linter.BaseConfig}
*/
/** @type {import('@types/eslint').Linter.BaseConfig} */
module.exports = {
extends: [
"@remix-run/eslint-config",
"@remix-run/eslint-config/node",
"@remix-run/eslint-config/jest-testing-library",
"prettier",
],
env: {
"cypress/globals": true,
},
plugins: ["cypress"],
// We're using vitest which has a very similar API to jest
// (so the linting plugins work nicely), but we have to
// set the jest version explicitly.
settings: {
jest: {
version: 27,
version: 28,
},
},
};
1 change: 1 addition & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
- main
- dev
pull_request: {}

permissions:
actions: write
contents: read
Expand Down
5 changes: 0 additions & 5 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,3 @@ function visitAndCheck(url: string, waitTime: number = 1000) {
Cypress.Commands.add("login", login);
Cypress.Commands.add("cleanupUser", cleanupUser);
Cypress.Commands.add("visitAndCheck", visitAndCheck);

/*
eslint
@typescript-eslint/no-namespace: "off",
*/
5 changes: 3 additions & 2 deletions cypress/support/create-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
// and it will log out the cookie value you can use to interact with the server
// as that new user.

import { parse } from "cookie";
import { installGlobals } from "@remix-run/node";
import { createUserSession } from "~/session.server";
import { parse } from "cookie";

import { createUser } from "~/models/user.server";
import { createUserSession } from "~/session.server";

installGlobals();

Expand Down
1 change: 1 addition & 0 deletions cypress/support/delete-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { PrismaClientKnownRequestError } from "@prisma/client/runtime";
import { installGlobals } from "@remix-run/node";

import { prisma } from "~/db.server";

installGlobals();
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"build:remix": "remix build",
"build:server": "esbuild --platform=node --format=cjs ./server.ts --outdir=build --bundle",
"dev": "run-p dev:*",
"dev:server": "cross-env NODE_ENV=development node --inspect --require ./node_modules/dotenv/config --require ./mocks ./build/server.js",
"dev:build": "cross-env NODE_ENV=development npm run build:server -- --watch",
"dev:remix": "cross-env NODE_ENV=development remix watch",
"dev:css": "cross-env NODE_ENV=development npm run generate:css -- --watch",
"dev:remix": "cross-env NODE_ENV=development remix watch",
"dev:server": "cross-env NODE_ENV=development node --inspect --require ./node_modules/dotenv/config --require ./mocks ./build/server.js",
"docker": "docker-compose up -d",
"format": "prettier --write .",
"generate:css": "tailwindcss -o ./app/styles/tailwind.css",
Expand Down Expand Up @@ -70,13 +70,14 @@
"autoprefixer": "^10.4.8",
"c8": "^7.12.0",
"cookie": "^0.5.0",
"cypress": "^10.6.0",
"cypress": "^10.6.1",
"dotenv": "^16.0.1",
"esbuild": "^0.15.5",
"eslint": "^8.22.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-cypress": "^2.12.1",
"happy-dom": "^6.0.4",
"msw": "^0.45.0",
"msw": "^0.45.1",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.16",
"prettier": "^2.7.1",
Expand All @@ -95,6 +96,6 @@
"node": ">=14"
},
"prisma": {
"seed": "node --require tsconfig-paths/register prisma/seed.js"
"seed": "ts-node --require tsconfig-paths/register prisma/seed.ts"
}
}
4 changes: 2 additions & 2 deletions prisma/seed.js → prisma/seed.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { PrismaClient } = require("@prisma/client");
const bcrypt = require("bcryptjs");
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";

const prisma = new PrismaClient();

Expand Down
191 changes: 144 additions & 47 deletions remix.init/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,108 @@ const fs = require("fs/promises");
const path = require("path");

const toml = require("@iarna/toml");
const PackageJson = require("@npmcli/package-json");
const YAML = require("yaml");
const sort = require("sort-package-json");

function escapeRegExp(string) {
const cleanupCypressFiles = (filesEntries) =>
filesEntries.flatMap(([filePath, content]) => {
const newContent = content
.replace(new RegExp("npx ts-node", "g"), "node")
.replace(new RegExp("create-user.ts", "g"), "create-user.js")
.replace(new RegExp("delete-user.ts", "g"), "delete-user.js");

return [fs.writeFile(filePath, newContent)];
});

const cleanupDeployWorkflow = (deployWorkflow, deployWorkflowPath) => {
delete deployWorkflow.jobs.typecheck;
deployWorkflow.jobs.deploy.needs = deployWorkflow.jobs.deploy.needs.filter(
(need) => need !== "typecheck"
);

return [fs.writeFile(deployWorkflowPath, YAML.stringify(deployWorkflow))];
};

const cleanupVitestConfig = (vitestConfig, vitestConfigPath) => {
const newVitestConfig = vitestConfig.replace(
"setup-test-env.ts",
"setup-test-env.js"
);

return [fs.writeFile(vitestConfigPath, newVitestConfig)];
};

const escapeRegExp = (string) =>
// $& means the whole matched string
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

const getRandomString = (length) => crypto.randomBytes(length).toString("hex");

const readFileIfNotTypeScript = (
isTypeScript,
filePath,
parseFunction = (result) => result
) =>
isTypeScript
? Promise.resolve()
: fs.readFile(filePath, "utf-8").then(parseFunction);

const removeUnusedDependencies = (dependencies, unusedDependencies) =>
Object.fromEntries(
Object.entries(dependencies).filter(
([key]) => !unusedDependencies.includes(key)
)
);

function getRandomString(length) {
return crypto.randomBytes(length).toString("hex");
}
const updatePackageJson = ({ APP_NAME, isTypeScript, packageJson }) => {
const {
devDependencies,
prisma: { seed: prismaSeed, ...prisma },
scripts: { typecheck, validate, ...scripts },
} = packageJson.content;

packageJson.update({
name: APP_NAME,
devDependencies: isTypeScript
? devDependencies
: removeUnusedDependencies(devDependencies, ["ts-node"]),
prisma: isTypeScript
? { ...prisma, seed: prismaSeed }
: {
...prisma,
seed: prismaSeed
.replace("ts-node", "node")
.replace("seed.ts", "seed.js"),
},
scripts: isTypeScript
? { ...scripts, typecheck, validate }
: { ...scripts, validate: validate.replace(" typecheck", "") },
});
};

async function main({ rootDirectory, packageManager, isTypeScript }) {
const main = async ({ isTypeScript, packageManager, rootDirectory }) => {
const README_PATH = path.join(rootDirectory, "README.md");
const FLY_TOML_PATH = path.join(rootDirectory, "fly.toml");
const EXAMPLE_ENV_PATH = path.join(rootDirectory, ".env.example");
const ENV_PATH = path.join(rootDirectory, ".env");
const PACKAGE_JSON_PATH = path.join(rootDirectory, "package.json");
const DEPLOY_YAML_PATH = path.join(
const DEPLOY_WORKFLOW_PATH = path.join(
rootDirectory,
".github/workflows/deploy.yml"
".github",
"workflows",
"deploy.yml"
);
const DOCKERFILE_PATH = path.join(rootDirectory, "Dockerfile");
const CYPRESS_SUPPORT_PATH = path.join(rootDirectory, "cypress", "support");
const CYPRESS_COMMANDS_PATH = path.join(CYPRESS_SUPPORT_PATH, "commands.js"); // We renamed this during `create-remix`
const CREATE_USER_COMMAND_PATH = path.join(
CYPRESS_SUPPORT_PATH,
"create-user.js"
); // We renamed this during `create-remix`
const DELETE_USER_COMMAND_PATH = path.join(
CYPRESS_SUPPORT_PATH,
"delete-user.js"
); // We renamed this during `create-remix`
const VITEST_CONFIG_PATH = path.join(rootDirectory, "vitest.config.js"); // We renamed this during `create-remix`

const REPLACER = "blues-stack-template";

Expand All @@ -37,15 +116,31 @@ async function main({ rootDirectory, packageManager, isTypeScript }) {
// get rid of anything that's not allowed in an app name
.replace(/[^a-zA-Z0-9-_]/g, "-");

const [prodContent, readme, env, packageJson, deployConfig, dockerfile] =
await Promise.all([
fs.readFile(FLY_TOML_PATH, "utf-8"),
fs.readFile(README_PATH, "utf-8"),
fs.readFile(EXAMPLE_ENV_PATH, "utf-8"),
fs.readFile(PACKAGE_JSON_PATH, "utf-8").then((s) => JSON.parse(s)),
fs.readFile(DEPLOY_YAML_PATH, "utf-8").then((s) => YAML.parse(s)),
fs.readFile(DOCKERFILE_PATH, "utf-8"),
]);
const [
prodContent,
readme,
env,
dockerfile,
cypressCommands,
createUserCommand,
deleteUserCommand,
deployWorkflow,
vitestConfig,
packageJson,
] = await Promise.all([
fs.readFile(FLY_TOML_PATH, "utf-8"),
fs.readFile(README_PATH, "utf-8"),
fs.readFile(EXAMPLE_ENV_PATH, "utf-8"),
fs.readFile(DOCKERFILE_PATH, "utf-8"),
readFileIfNotTypeScript(isTypeScript, CYPRESS_COMMANDS_PATH),
readFileIfNotTypeScript(isTypeScript, CREATE_USER_COMMAND_PATH),
readFileIfNotTypeScript(isTypeScript, DELETE_USER_COMMAND_PATH),
readFileIfNotTypeScript(isTypeScript, DEPLOY_WORKFLOW_PATH, (s) =>
YAML.parse(s)
),
readFileIfNotTypeScript(isTypeScript, VITEST_CONFIG_PATH),
PackageJson.load(rootDirectory),
]);

const newEnv = env.replace(
/^SESSION_SECRET=.*$/m,
Expand All @@ -60,25 +155,6 @@ async function main({ rootDirectory, packageManager, isTypeScript }) {
APP_NAME
);

let saveDeploy = null;
if (!isTypeScript) {
delete packageJson.scripts.typecheck;
packageJson.scripts.validate = packageJson.scripts.validate.replace(
" typecheck",
""
);

delete deployConfig.jobs.typecheck;
deployConfig.jobs.deploy.needs = deployConfig.jobs.deploy.needs.filter(
(n) => n !== "typecheck"
);
// only write the deploy config if it's changed
saveDeploy = fs.writeFile(DEPLOY_YAML_PATH, YAML.stringify(deployConfig));
}

const newPackageJson =
JSON.stringify(sort({ ...packageJson, name: APP_NAME }), null, 2) + "\n";

const lockfile = {
npm: "package-lock.json",
yarn: "yarn.lock",
Expand All @@ -92,26 +168,47 @@ async function main({ rootDirectory, packageManager, isTypeScript }) {
)
: dockerfile;

await Promise.all([
updatePackageJson({ APP_NAME, isTypeScript, packageJson });

const fileOperationPromises = [
fs.writeFile(FLY_TOML_PATH, toml.stringify(prodToml)),
fs.writeFile(README_PATH, newReadme),
fs.writeFile(ENV_PATH, newEnv),
fs.writeFile(PACKAGE_JSON_PATH, newPackageJson),
fs.writeFile(DOCKERFILE_PATH, newDockerfile),
saveDeploy,
packageJson.save(),
fs.copyFile(
path.join(rootDirectory, "remix.init", "gitignore"),
path.join(rootDirectory, ".gitignore")
),
fs.rm(path.join(rootDirectory, ".github/ISSUE_TEMPLATE"), {
fs.rm(path.join(rootDirectory, ".github", "ISSUE_TEMPLATE"), {
recursive: true,
}),
fs.rm(path.join(rootDirectory, ".github/PULL_REQUEST_TEMPLATE.md")),
]);
fs.rm(path.join(rootDirectory, ".github", "PULL_REQUEST_TEMPLATE.md")),
];

if (!isTypeScript) {
fileOperationPromises.push(
...cleanupCypressFiles([
[CYPRESS_COMMANDS_PATH, cypressCommands],
[CREATE_USER_COMMAND_PATH, createUserCommand],
[DELETE_USER_COMMAND_PATH, deleteUserCommand],
])
);

fileOperationPromises.push(
...cleanupDeployWorkflow(deployWorkflow, DEPLOY_WORKFLOW_PATH)
);

fileOperationPromises.push(
...cleanupVitestConfig(vitestConfig, VITEST_CONFIG_PATH)
);
}

await Promise.all(fileOperationPromises);

execSync("npm run format -- --loglevel warn", {
stdio: "inherit",
cwd: rootDirectory,
stdio: "inherit",
});

console.log(
Expand All @@ -131,6 +228,6 @@ Setup is almost complete. Follow these steps to finish initialization:
npm run dev
`.trim()
);
}
};

module.exports = main;
2 changes: 1 addition & 1 deletion remix.init/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"license": "MIT",
"dependencies": {
"@iarna/toml": "^2.2.5",
"sort-package-json": "^1.57.0",
"@npmcli/package-json": "^2.0.0",
"yaml": "^2.1.1"
}
}
2 changes: 1 addition & 1 deletion vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// <reference types="vitest" />
/// <reference types="vite/client" />

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
Expand Down

0 comments on commit 5916fb3

Please sign in to comment.