feat: initial bootstrappy stuff
This commit is contained in:
parent
70c42751e3
commit
025cc4f6f1
@ -1,84 +0,0 @@
|
|||||||
/**
|
|
||||||
* This is intended to be a basic starting point for linting in your app.
|
|
||||||
* It relies on recommended configs out of the box for simplicity, but you can
|
|
||||||
* and should modify this configuration to best suit your team's needs.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @type {import('eslint').Linter.Config} */
|
|
||||||
module.exports = {
|
|
||||||
root: true,
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: "latest",
|
|
||||||
sourceType: "module",
|
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
commonjs: true,
|
|
||||||
es6: true,
|
|
||||||
},
|
|
||||||
ignorePatterns: ["!**/.server", "!**/.client"],
|
|
||||||
|
|
||||||
// Base config
|
|
||||||
extends: ["eslint:recommended"],
|
|
||||||
|
|
||||||
overrides: [
|
|
||||||
// React
|
|
||||||
{
|
|
||||||
files: ["**/*.{js,jsx,ts,tsx}"],
|
|
||||||
plugins: ["react", "jsx-a11y"],
|
|
||||||
extends: [
|
|
||||||
"plugin:react/recommended",
|
|
||||||
"plugin:react/jsx-runtime",
|
|
||||||
"plugin:react-hooks/recommended",
|
|
||||||
"plugin:jsx-a11y/recommended",
|
|
||||||
],
|
|
||||||
settings: {
|
|
||||||
react: {
|
|
||||||
version: "detect",
|
|
||||||
},
|
|
||||||
formComponents: ["Form"],
|
|
||||||
linkComponents: [
|
|
||||||
{ name: "Link", linkAttribute: "to" },
|
|
||||||
{ name: "NavLink", linkAttribute: "to" },
|
|
||||||
],
|
|
||||||
"import/resolver": {
|
|
||||||
typescript: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Typescript
|
|
||||||
{
|
|
||||||
files: ["**/*.{ts,tsx}"],
|
|
||||||
plugins: ["@typescript-eslint", "import"],
|
|
||||||
parser: "@typescript-eslint/parser",
|
|
||||||
settings: {
|
|
||||||
"import/internal-regex": "^~/",
|
|
||||||
"import/resolver": {
|
|
||||||
node: {
|
|
||||||
extensions: [".ts", ".tsx"],
|
|
||||||
},
|
|
||||||
typescript: {
|
|
||||||
alwaysTryTypes: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
extends: [
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"plugin:import/recommended",
|
|
||||||
"plugin:import/typescript",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
// Node
|
|
||||||
{
|
|
||||||
files: [".eslintrc.cjs"],
|
|
||||||
env: {
|
|
||||||
node: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@ -4,15 +4,15 @@
|
|||||||
* For more information, see https://remix.run/file-conventions/entry.client
|
* For more information, see https://remix.run/file-conventions/entry.client
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RemixBrowser } from "@remix-run/react";
|
import { RemixBrowser } from '@remix-run/react'
|
||||||
import { startTransition, StrictMode } from "react";
|
import { startTransition, StrictMode } from 'react'
|
||||||
import { hydrateRoot } from "react-dom/client";
|
import { hydrateRoot } from 'react-dom/client'
|
||||||
|
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
hydrateRoot(
|
hydrateRoot(
|
||||||
document,
|
document,
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<RemixBrowser />
|
<RemixBrowser/>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
|
|||||||
@ -4,137 +4,134 @@
|
|||||||
* For more information, see https://remix.run/file-conventions/entry.server
|
* For more information, see https://remix.run/file-conventions/entry.server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PassThrough } from "node:stream";
|
import { PassThrough } from 'node:stream'
|
||||||
|
|
||||||
import type { AppLoadContext, EntryContext } from "@remix-run/node";
|
import type { EntryContext } from '@remix-run/node'
|
||||||
import { createReadableStreamFromReadable } from "@remix-run/node";
|
import { createReadableStreamFromReadable } from '@remix-run/node'
|
||||||
import { RemixServer } from "@remix-run/react";
|
import { RemixServer } from '@remix-run/react'
|
||||||
import { isbot } from "isbot";
|
import { isbot } from 'isbot'
|
||||||
import { renderToPipeableStream } from "react-dom/server";
|
import { renderToPipeableStream } from 'react-dom/server'
|
||||||
|
|
||||||
const ABORT_DELAY = 5_000;
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
const ABORT_DELAY = 5000
|
||||||
|
|
||||||
export default function handleRequest(
|
export default async function handleRequest(
|
||||||
request: Request,
|
request: Request,
|
||||||
responseStatusCode: number,
|
responseStatusCode: number,
|
||||||
responseHeaders: Headers,
|
responseHeaders: Headers,
|
||||||
remixContext: EntryContext,
|
remixContext: EntryContext
|
||||||
// This is ignored so we can keep it in the template for visibility. Feel
|
|
||||||
// free to delete this parameter in your app if you're not using it!
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
loadContext: AppLoadContext
|
|
||||||
) {
|
) {
|
||||||
return isbot(request.headers.get("user-agent") || "")
|
return isbot(request.headers.get('user-agent') ?? '')
|
||||||
? handleBotRequest(
|
? handleBotRequest(
|
||||||
request,
|
request,
|
||||||
responseStatusCode,
|
responseStatusCode,
|
||||||
responseHeaders,
|
responseHeaders,
|
||||||
remixContext
|
remixContext
|
||||||
)
|
)
|
||||||
: handleBrowserRequest(
|
: handleBrowserRequest(
|
||||||
request,
|
request,
|
||||||
responseStatusCode,
|
responseStatusCode,
|
||||||
responseHeaders,
|
responseHeaders,
|
||||||
remixContext
|
remixContext
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBotRequest(
|
async function handleBotRequest(
|
||||||
request: Request,
|
request: Request,
|
||||||
responseStatusCode: number,
|
responseStatusCode: number,
|
||||||
responseHeaders: Headers,
|
responseHeaders: Headers,
|
||||||
remixContext: EntryContext
|
remixContext: EntryContext
|
||||||
) {
|
) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let shellRendered = false;
|
let shellRendered = false
|
||||||
const { pipe, abort } = renderToPipeableStream(
|
const { pipe, abort } = renderToPipeableStream(
|
||||||
<RemixServer
|
<RemixServer
|
||||||
context={remixContext}
|
context={remixContext}
|
||||||
url={request.url}
|
url={request.url}
|
||||||
abortDelay={ABORT_DELAY}
|
abortDelay={ABORT_DELAY}
|
||||||
/>,
|
/>,
|
||||||
{
|
{
|
||||||
onAllReady() {
|
onAllReady() {
|
||||||
shellRendered = true;
|
shellRendered = true
|
||||||
const body = new PassThrough();
|
const body = new PassThrough()
|
||||||
const stream = createReadableStreamFromReadable(body);
|
const stream = createReadableStreamFromReadable(body)
|
||||||
|
|
||||||
responseHeaders.set("Content-Type", "text/html");
|
responseHeaders.set('Content-Type', 'text/html')
|
||||||
|
|
||||||
resolve(
|
resolve(
|
||||||
new Response(stream, {
|
new Response(stream, {
|
||||||
headers: responseHeaders,
|
headers: responseHeaders,
|
||||||
status: responseStatusCode,
|
status: responseStatusCode
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
pipe(body);
|
pipe(body)
|
||||||
},
|
},
|
||||||
onShellError(error: unknown) {
|
onShellError(error: unknown) {
|
||||||
reject(error);
|
reject(error)
|
||||||
},
|
},
|
||||||
onError(error: unknown) {
|
onError(error: unknown) {
|
||||||
responseStatusCode = 500;
|
responseStatusCode = 500
|
||||||
// Log streaming rendering errors from inside the shell. Don't log
|
// Log streaming rendering errors from inside the shell. Don't log
|
||||||
// errors encountered during initial shell rendering since they'll
|
// errors encountered during initial shell rendering since they'll
|
||||||
// reject and get logged in handleDocumentRequest.
|
// reject and get logged in handleDocumentRequest.
|
||||||
if (shellRendered) {
|
if (shellRendered) {
|
||||||
console.error(error);
|
console.error(error)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
setTimeout(abort, ABORT_DELAY);
|
setTimeout(abort, ABORT_DELAY)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBrowserRequest(
|
async function handleBrowserRequest(
|
||||||
request: Request,
|
request: Request,
|
||||||
responseStatusCode: number,
|
responseStatusCode: number,
|
||||||
responseHeaders: Headers,
|
responseHeaders: Headers,
|
||||||
remixContext: EntryContext
|
remixContext: EntryContext
|
||||||
) {
|
) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let shellRendered = false;
|
let shellRendered = false
|
||||||
const { pipe, abort } = renderToPipeableStream(
|
const { pipe, abort } = renderToPipeableStream(
|
||||||
<RemixServer
|
<RemixServer
|
||||||
context={remixContext}
|
context={remixContext}
|
||||||
url={request.url}
|
url={request.url}
|
||||||
abortDelay={ABORT_DELAY}
|
abortDelay={ABORT_DELAY}
|
||||||
/>,
|
/>,
|
||||||
{
|
{
|
||||||
onShellReady() {
|
onShellReady() {
|
||||||
shellRendered = true;
|
shellRendered = true
|
||||||
const body = new PassThrough();
|
const body = new PassThrough()
|
||||||
const stream = createReadableStreamFromReadable(body);
|
const stream = createReadableStreamFromReadable(body)
|
||||||
|
|
||||||
responseHeaders.set("Content-Type", "text/html");
|
responseHeaders.set('Content-Type', 'text/html')
|
||||||
|
|
||||||
resolve(
|
resolve(
|
||||||
new Response(stream, {
|
new Response(stream, {
|
||||||
headers: responseHeaders,
|
headers: responseHeaders,
|
||||||
status: responseStatusCode,
|
status: responseStatusCode
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
pipe(body);
|
pipe(body)
|
||||||
},
|
},
|
||||||
onShellError(error: unknown) {
|
onShellError(error: unknown) {
|
||||||
reject(error);
|
reject(error)
|
||||||
},
|
},
|
||||||
onError(error: unknown) {
|
onError(error: unknown) {
|
||||||
responseStatusCode = 500;
|
responseStatusCode = 500
|
||||||
// Log streaming rendering errors from inside the shell. Don't log
|
// Log streaming rendering errors from inside the shell. Don't log
|
||||||
// errors encountered during initial shell rendering since they'll
|
// errors encountered during initial shell rendering since they'll
|
||||||
// reject and get logged in handleDocumentRequest.
|
// reject and get logged in handleDocumentRequest.
|
||||||
if (shellRendered) {
|
if (shellRendered) {
|
||||||
console.error(error);
|
console.error(error)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
setTimeout(abort, ABORT_DELAY);
|
setTimeout(abort, ABORT_DELAY)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
3
app/tailwind.css
Normal file
3
app/tailwind.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
10928
package-lock.json
generated
10928
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
78
package.json
78
package.json
@ -1,40 +1,40 @@
|
|||||||
{
|
{
|
||||||
"name": "headplane-remix",
|
"name": "headplane",
|
||||||
"private": true,
|
"private": true,
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "remix vite:build",
|
"build": "remix vite:build",
|
||||||
"dev": "remix vite:dev",
|
"dev": "remix vite:dev",
|
||||||
"lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
|
"lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
|
||||||
"start": "remix-serve ./build/server/index.js",
|
"start": "remix-serve ./build/server/index.js",
|
||||||
"typecheck": "tsc"
|
"typecheck": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@remix-run/node": "^2.8.1",
|
"@heroicons/react": "^2.1.3",
|
||||||
"@remix-run/react": "^2.8.1",
|
"@remix-run/node": "^2.8.1",
|
||||||
"@remix-run/serve": "^2.8.1",
|
"@remix-run/react": "^2.8.1",
|
||||||
"isbot": "^4.1.0",
|
"@remix-run/serve": "^2.8.1",
|
||||||
"react": "^18.2.0",
|
"clsx": "^2.1.0",
|
||||||
"react-dom": "^18.2.0"
|
"isbot": "^4.1.0",
|
||||||
},
|
"oauth4webapi": "^2.10.3",
|
||||||
"devDependencies": {
|
"react": "^18.2.0",
|
||||||
"@remix-run/dev": "^2.8.1",
|
"react-dom": "^18.2.0"
|
||||||
"@types/react": "^18.2.20",
|
},
|
||||||
"@types/react-dom": "^18.2.7",
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
"@remix-run/dev": "^2.8.1",
|
||||||
"@typescript-eslint/parser": "^6.7.4",
|
"@types/react": "^18.2.20",
|
||||||
"eslint": "^8.38.0",
|
"@types/react-dom": "^18.2.7",
|
||||||
"eslint-import-resolver-typescript": "^3.6.1",
|
"autoprefixer": "^10.4.19",
|
||||||
"eslint-plugin-import": "^2.28.1",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
"eslint-config-tale": "^1.0.16",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"postcss": "^8.4.38",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"tailwindcss": "^3.4.1",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6",
|
||||||
"vite": "^5.1.0",
|
"vite": "^5.1.0",
|
||||||
"vite-tsconfig-paths": "^4.2.1"
|
"vite-tsconfig-paths": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6477
pnpm-lock.yaml
Normal file
6477
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
10
tailwind.config.ts
Normal file
10
tailwind.config.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import type { Config } from 'tailwindcss'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
content: ['./app/**/*.{js,jsx,ts,tsx}'],
|
||||||
|
theme: {
|
||||||
|
extend: {}
|
||||||
|
},
|
||||||
|
plugins: []
|
||||||
|
} satisfies Config
|
||||||
|
|
||||||
@ -1,32 +1,32 @@
|
|||||||
{
|
{
|
||||||
"include": [
|
"include": [
|
||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
"**/*.tsx",
|
"**/*.tsx",
|
||||||
"**/.server/**/*.ts",
|
"**/.server/**/*.ts",
|
||||||
"**/.server/**/*.tsx",
|
"**/.server/**/*.tsx",
|
||||||
"**/.client/**/*.ts",
|
"**/.client/**/*.ts",
|
||||||
"**/.client/**/*.tsx"
|
"**/.client/**/*.tsx"
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||||
"types": ["@remix-run/node", "vite/client"],
|
"types": ["@remix-run/node", "vite/client"],
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "Bundler",
|
"moduleResolution": "Bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"~/*": ["./app/*"]
|
"~/*": ["./app/*"]
|
||||||
},
|
},
|
||||||
|
|
||||||
// Vite takes care of building everything, not tsc.
|
// Vite takes care of building everything, not tsc.
|
||||||
"noEmit": true
|
"noEmit": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { vitePlugin as remix } from "@remix-run/dev";
|
import { vitePlugin as remix } from '@remix-run/dev'
|
||||||
import { installGlobals } from "@remix-run/node";
|
import { installGlobals } from '@remix-run/node'
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from 'vite'
|
||||||
import tsconfigPaths from "vite-tsconfig-paths";
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||||
|
|
||||||
installGlobals();
|
installGlobals()
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [remix(), tsconfigPaths()],
|
plugins: [remix({
|
||||||
});
|
basename: '/admin'
|
||||||
|
}), tsconfigPaths()]
|
||||||
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user