Init
This commit is contained in:
commit
84a1d08651
29
.eslintrc.js
Normal file
29
.eslintrc.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es6: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: ['prettier'],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaFeatures: {
|
||||||
|
jsx: true,
|
||||||
|
},
|
||||||
|
ecmaVersion: 2018,
|
||||||
|
sourceType: 'module',
|
||||||
|
project: './tsconfig.json',
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
'@typescript-eslint/eslint-plugin',
|
||||||
|
'prettier',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
camelcase: 'error',
|
||||||
|
'@typescript-eslint/return-await': 'off',
|
||||||
|
'@typescript-eslint/camelcase': 'off',
|
||||||
|
'no-param-reassign': ['error', { props: false }],
|
||||||
|
'no-underscore-dangle': ['error', { allow: ['_id'] }],
|
||||||
|
},
|
||||||
|
reportUnusedDisableDirectives: true,
|
||||||
|
};
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.out/
|
||||||
|
.tmp/
|
||||||
|
node_modules/
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
38
package.json
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "ssg",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"compile": "esbuild ssg/build.tsx --bundle --outfile=.tmp/ssg/build.js --jsx-import-source=@kitajs/html --minify --sourcemap --platform=node --external:esbuild",
|
||||||
|
"buld": "npm run compile && node .tmp/ssg/build.js"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@kitajs/html": "^4.2.7",
|
||||||
|
"@kitajs/ts-html-plugin": "^4.1.1",
|
||||||
|
"@types/node": "^22.14.0",
|
||||||
|
"esbuild": "^0.25.2",
|
||||||
|
"esbuild-sass-plugin": "^3.3.1",
|
||||||
|
"glob": "^11.0.1",
|
||||||
|
"prettier": "^3.5.3",
|
||||||
|
"typescript": "^5.8.3",
|
||||||
|
"eslint": "8.56.0",
|
||||||
|
"eslint-config-prettier": "9.1.0",
|
||||||
|
"eslint-plugin-import": "2.29.1",
|
||||||
|
"eslint-plugin-prettier": "5.1.3",
|
||||||
|
"@typescript-eslint/typescript-estree": "8.22.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "7.0.2",
|
||||||
|
"@typescript-eslint/parser": "7.0.2"
|
||||||
|
},
|
||||||
|
"prettier": {
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"arrowParens": "always",
|
||||||
|
"printWidth": 80
|
||||||
|
}
|
||||||
|
}
|
3375
pnpm-lock.yaml
Normal file
3375
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
3
src/components/body/body.module.scss
Normal file
3
src/components/body/body.module.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.body {
|
||||||
|
color: blue;
|
||||||
|
}
|
5
src/components/body/body.tsx
Normal file
5
src/components/body/body.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import styles from './body.module.scss';
|
||||||
|
|
||||||
|
export default function Body(props: { children: any }) {
|
||||||
|
return <p className={styles.body}>{props.children}</p>;
|
||||||
|
}
|
3
src/components/heading/heading.module.scss
Normal file
3
src/components/heading/heading.module.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.heading {
|
||||||
|
color: red;
|
||||||
|
}
|
5
src/components/heading/heading.tsx
Normal file
5
src/components/heading/heading.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import styles from './heading.module.scss';
|
||||||
|
|
||||||
|
export default function Heading(props: { children: any }) {
|
||||||
|
return <h1 className={styles.heading}>{props.children}</h1>;
|
||||||
|
}
|
3
src/pages/404.tsx
Normal file
3
src/pages/404.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default function NotFound() {
|
||||||
|
return <div>Not Found</div>;
|
||||||
|
}
|
11
src/pages/index.tsx
Normal file
11
src/pages/index.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import Heading from '../components/heading/heading';
|
||||||
|
import Body from '../components/body/body';
|
||||||
|
|
||||||
|
export default function Index() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Heading>foo</Heading>
|
||||||
|
<Body>Hello World!</Body>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
51
ssg/build.tsx
Normal file
51
ssg/build.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { glob } from 'glob';
|
||||||
|
import { build } from 'esbuild';
|
||||||
|
import { mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
||||||
|
import { sassPlugin } from 'esbuild-sass-plugin';
|
||||||
|
import Root from './root';
|
||||||
|
import { getPaths, getStylePath, outDir } from './utils';
|
||||||
|
|
||||||
|
mkdirSync(outDir, { recursive: true });
|
||||||
|
|
||||||
|
void (async () => {
|
||||||
|
const pages = await glob('src/pages/**/*.tsx');
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async (page) => {
|
||||||
|
const { pagePath, tmpJsPath, outputHtmlPath } = getPaths(page);
|
||||||
|
|
||||||
|
await build({
|
||||||
|
entryPoints: [pagePath],
|
||||||
|
bundle: true,
|
||||||
|
outfile: tmpJsPath,
|
||||||
|
jsxImportSource: '@kitajs/html',
|
||||||
|
minify: true,
|
||||||
|
platform: 'node',
|
||||||
|
external: ['esbuild'],
|
||||||
|
plugins: [
|
||||||
|
sassPlugin({
|
||||||
|
filter: /\.module\.scss$/,
|
||||||
|
type: 'local-css',
|
||||||
|
}),
|
||||||
|
sassPlugin({
|
||||||
|
filter: /\.scss$/,
|
||||||
|
type: 'css',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const { default: Page } = await import(tmpJsPath);
|
||||||
|
const html = Page.default();
|
||||||
|
let stylePaths: string[] = getStylePath(tmpJsPath, outputHtmlPath);
|
||||||
|
|
||||||
|
writeFileSync(
|
||||||
|
outputHtmlPath,
|
||||||
|
<Root title="My App" stylePaths={stylePaths} scriptPaths={[]}>
|
||||||
|
{html}
|
||||||
|
</Root>,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
rmSync('.tmp', { recursive: true });
|
||||||
|
})();
|
25
ssg/root.tsx
Normal file
25
ssg/root.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
interface Props {
|
||||||
|
children: HTMLElement;
|
||||||
|
title: string;
|
||||||
|
scriptPaths: string[];
|
||||||
|
stylePaths: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Root(props: Props) {
|
||||||
|
const { children, title, scriptPaths, stylePaths } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>{title}</title>
|
||||||
|
{stylePaths.map((path) => (
|
||||||
|
<link rel="stylesheet" href={path} />
|
||||||
|
))}
|
||||||
|
{scriptPaths.map((path) => (
|
||||||
|
<script src={path} />
|
||||||
|
))}
|
||||||
|
</head>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
31
ssg/utils.ts
Normal file
31
ssg/utils.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { cpSync, existsSync } from 'node:fs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
|
||||||
|
export const outDir = resolve('.out');
|
||||||
|
|
||||||
|
export const getStylePath = (tmpJsPath: string, outputHtmlPath: string) => {
|
||||||
|
let stylePaths: string[] = [];
|
||||||
|
|
||||||
|
if (existsSync(tmpJsPath.replace('.js', '.css'))) {
|
||||||
|
cpSync(
|
||||||
|
tmpJsPath.replace('.js', '.css'),
|
||||||
|
outputHtmlPath.replace('.html', '.css'),
|
||||||
|
);
|
||||||
|
|
||||||
|
stylePaths.push(
|
||||||
|
outputHtmlPath.replace('.html', '.css').replace(outDir, '.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stylePaths;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPaths = (rawPath: string) => {
|
||||||
|
const pagePath = resolve(rawPath);
|
||||||
|
const tmpJsPath = pagePath.replace('src', '.tmp').replace('.tsx', '.js');
|
||||||
|
const outputHtmlPath = pagePath
|
||||||
|
.replace('src/pages', '.out')
|
||||||
|
.replace('.tsx', '.html');
|
||||||
|
|
||||||
|
return { pagePath, tmpJsPath, outputHtmlPath };
|
||||||
|
};
|
23
tsconfig.json
Normal file
23
tsconfig.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"lib": ["dom", "dom.iterable", "es2021"],
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"jsxImportSource": "@kitajs/html",
|
||||||
|
"plugins": [{ "name": "@kitajs/ts-html-plugin" }],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"incremental": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"outDir": "./out",
|
||||||
|
},
|
||||||
|
"include": ["**/*.tsx", "**/*.ts"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user