Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/Lark-notification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
env:
HAS_LARK_WEBHOOK: ${{ secrets.LARK_CHATBOT_HOOK_URL != '' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7

- uses: denoland/setup-deno@v2
with:
Expand Down
56 changes: 14 additions & 42 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,20 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}

- uses: actions/setup-node@v6
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}
with:
node-version: 24

- name: Deploy to Vercel
id: vercel-deployment
if: ${{ env.VERCEL_TOKEN && env.VERCEL_ORG_ID && env.VERCEL_PROJECT_ID }}
shell: bash
run: |
set -euo pipefail

npm install vercel -g

if [[ "$GITHUB_REF" == 'refs/heads/main' ]]; then
DeployOutput=$(vercel -t "$VERCEL_TOKEN" --prod)
else
DeployOutput=$(vercel -t "$VERCEL_TOKEN")
fi
echo "$DeployOutput"

ParsedURL=$(echo "$DeployOutput" | grep -Eo 'https://[^[:space:]]*\.vercel\.app' | tail -n 1)

if [[ -z "$ParsedURL" ]]; then
echo "Failed to parse Vercel URL from deploy output"
exit 1
fi
vercel inspect "$ParsedURL" -t "$VERCEL_TOKEN" -F json > vercel-inspect.json

InspectURL=$(jq -r '.url // empty' vercel-inspect.json)

if [[ -z "$InspectURL" ]]; then
echo "Failed to parse inspect url from vercel-inspect.json"
exit 1
fi
if [[ "$InspectURL" != http* ]]; then
InspectURL="https://$InspectURL"
fi
echo "preview-url=$InspectURL" >> "$GITHUB_OUTPUT"
uses: amondnet/vercel-action@v42.3.0
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
working-directory: ./
vercel-args: ${{ github.ref == 'refs/heads/main' && ' --prod' || '' }}

- name: Lark notification
uses: Open-Source-Bazaar/feishu-action@v3
Expand All @@ -68,13 +40,13 @@ jobs:
header:
title:
tag: plain_text
content: Vercel 部署通知
content: Vercel deployment
template: blue
body:
elements:
- tag: markdown
content: |
**Git 仓库:** [${{ github.server_url }}/${{ github.repository }}](${{ github.server_url }}/${{ github.repository }})
**代码分支:** [${{ github.ref }}](${{ github.server_url }}/${{ github.repository }}/tree/${{ github.ref_name }})
**提交作者:** [${{ github.actor }}](${{ github.server_url }}/${{ github.actor }})
**预览链接:** [${{ steps.vercel-deployment.outputs.preview-url }}](${{ steps.vercel-deployment.outputs.preview-url }})
- **Git Repository**: [${{ github.server_url }}/${{ github.repository }}](${{ github.server_url }}/${{ github.repository }})
- **Code Branch**: [${{ github.ref }}](${{ github.server_url }}/${{ github.repository }}/tree/${{ github.ref_name }})
- **Commit Author**: [${{ github.actor }}](${{ github.server_url }}/${{ github.actor }})
- **Preview Link**: [${{ steps.vercel-deployment.outputs.preview-url }}](${{ steps.vercel-deployment.outputs.preview-url }})
2 changes: 1 addition & 1 deletion .github/workflows/self-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
self-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7

- uses: OWASP/cve-lite-cli@v1
with:
Expand Down
10 changes: 7 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:24-slim AS base
FROM node:26-slim AS base
RUN apt-get update && \
apt-get install ca-certificates curl libjemalloc-dev -y --no-install-recommends && \
rm -rf /var/lib/apt/lists/*
Expand All @@ -9,17 +9,21 @@ ENV MALLOC_CONF=dirty_decay_ms:1000,narenas:2,background_thread:true
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN npm i pnpm@latest -g
COPY . /app
WORKDIR /app

FROM base AS build
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm i --frozen-lockfile
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY patches ./patches
RUN pnpm fetch --frozen-lockfile --store-dir=/pnpm/store
COPY . .
RUN pnpm i --offline --frozen-lockfile --store-dir=/pnpm/store
RUN pnpm build

FROM base
COPY --from=build /app/public ./public
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.env* ./
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
Expand Down
106 changes: 5 additions & 101 deletions eslint.config.ts
Original file line number Diff line number Diff line change
@@ -1,116 +1,20 @@
import cspellPlugin from '@cspell/eslint-plugin';
import eslint from '@eslint/js';
import nextPlugin from '@next/eslint-plugin-next';
import stylistic from '@stylistic/eslint-plugin';
import { defineConfig } from 'eslint/config';
import eslintConfigPrettier from 'eslint-config-prettier';
import react from 'eslint-plugin-react';
import simpleImportSortPlugin from 'eslint-plugin-simple-import-sort';
import globals from 'globals';
import tsEslint from 'typescript-eslint';
import { fileURLToPath } from 'url';
import nextJS from 'eslint-idea2app-next-js';

/**
* @see{@link https://github.com/typescript-eslint/typescript-eslint/blob/main/eslint.config.mjs}
* @see{@link https://github.com/vercel/next.js/issues/71763#issuecomment-2476838298}
*/

const tsconfigRootDir = fileURLToPath(new URL('.', import.meta.url));

export default defineConfig(
// register all of the plugins up-front
{
plugins: {
'@cspell': cspellPlugin,
'@stylistic': stylistic,
'simple-import-sort': simpleImportSortPlugin,
'@typescript-eslint': tsEslint.plugin,
react,
'@next/next': nextPlugin,
},
},
export default [
...nextJS,
{
// config with just ignores is the replacement for `.eslintignore`
ignores: ['**/node_modules/**', '**/public/**', '**/.next/**', '.github/scripts/**'],
},

// extends ...
eslint.configs.recommended,
...tsEslint.configs.recommended,

// base config
{
languageOptions: {
globals: { ...globals.es2020, ...globals.browser, ...globals.node },
parserOptions: {
projectService: true,
tsconfigRootDir,
warnOnUnsupportedTypeScriptVersion: false,
},
},
rules: {
// spellchecker
'@cspell/spellchecker': [
'warn',
{
cspell: {
language: 'en',
dictionaries: ['typescript', 'node', 'html', 'css', 'bash', 'npm', 'pnpm'],
words: ['hackathon'],
words: ['aliyun', 'datav', 'Giscus', 'hackathon', 'Serwist'],
},
},
],
// stylistic
'@stylistic/padding-line-between-statements': [
'error',
{ blankLine: 'always', prev: '*', next: 'return' },
{ blankLine: 'always', prev: 'directive', next: '*' },
{ blankLine: 'any', prev: 'directive', next: 'directive' },
{
blankLine: 'always',
prev: '*',
next: ['enum', 'interface', 'type'],
},
],
'arrow-body-style': ['error', 'as-needed'],
'no-empty-pattern': 'warn',
'no-console': ['error', { allow: ['warn', 'error', 'info'] }],
'no-restricted-syntax': [
'error',
{
selector: "TSPropertySignature[key.name='children']",
message: 'Please use PropsWithChildren<T> instead of defining children manually',
},
],
'consistent-return': 'warn',
'prefer-destructuring': ['error', { object: true, array: true }],
// simple-import-sort
'simple-import-sort/exports': 'error',
'simple-import-sort/imports': 'error',
// TypeScript
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-unsafe-declaration-merging': 'warn',
'@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
// React
'react/no-unescaped-entities': 'off',
'react/self-closing-comp': ['error', { component: true, html: true }],
'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }],
'react/jsx-no-target-blank': 'warn',
'react/jsx-sort-props': [
'error',
{
reservedFirst: true,
callbacksLast: true,
noSortAlphabetically: true,
},
],
// Next.js
...nextPlugin.configs.recommended.rules,
...nextPlugin.configs['core-web-vitals'].rules,
'@next/next/no-sync-scripts': 'warn',
},
},
eslintConfigPrettier,
);
];
11 changes: 5 additions & 6 deletions next.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import setMDX from '@next/mdx';
import withSerwistInit from '@serwist/next';
import { NextConfig } from 'next';
import setPWA from 'next-pwa';
// @ts-expect-error no official types
import withLess from 'next-with-less';
import remarkFrontmatter from 'remark-frontmatter';
Expand All @@ -17,10 +17,9 @@ const withMDX = setMDX({
},
extension: /\.mdx?$/,
}),
withPWA = setPWA({
dest: 'public',
register: true,
skipWaiting: true,
withSerwist = withSerwistInit({
swSrc: 'service-worker.ts',
swDest: 'public/sw.js',
disable: isDev,
});

Expand Down Expand Up @@ -51,7 +50,7 @@ const redirects: NextConfig['redirects'] = async () =>
},
]);

export default withPWA(
export default withSerwist(
withLess(
withMDX({
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
Expand Down
83 changes: 37 additions & 46 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,83 +6,74 @@
"scripts": {
"prepare": "husky",
"install": "pnpx git-utility download https://github.com/Open-Source-Bazaar/key-vault main Open-Source-Bazaar.github.io || true",
"postinstall": "next typegen",
"postinstall": "next typegen --webpack",
"dev": "next dev --webpack",
"build": "cross-env CI=true next build --webpack",
"start": "next start",
"test": "lint-staged && tsc --noEmit"
},
"dependencies": {
"@giscus/react": "^3.1.0",
"@khmyznikov/pwa-install": "^0.7.0",
"@koa/router": "^15.7.0",
"@mdx-js/loader": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@next/mdx": "16.4.2",
"core-js": "^3.49.0",
"@next/mdx": "16.4.3",
"@serwist/next": "^9.5.13",
"core-js": "^3.51.0",
"echarts-jsx": "^0.6.0",
"file-type": "^22.0.1",
"idea-react": "^2.2.2",
"file-type": "^22.2.0",
"idea-react": "^2.3.5",
"jsonwebtoken": "^9.0.3",
"koa": "^3.2.1",
"koa-jwt": "^4.0.4",
"koajax": "^3.3.0",
"koajax": "^3.3.1",
"license-filter": "^0.2.5",
"marked": "^15.0.12",
"mime": "^4.1.0",
"mobx": "^6.16.1",
"mobx-github": "^0.7.0",
"mobx-i18n": "^0.7.5",
"mobx-lark": "^2.10.0",
"mobx-react": "^9.2.2",
"mobx-react-helper": "^0.5.2",
"mobx-restful": "^2.1.4",
"mobx-restful-table": "^2.6.6",
"marked": "^18.1.2",
"mime": "^4.1.1",
"mobx": "^7.1.3",
"mobx-github": "^0.7.1",
"mobx-i18n": "^0.7.9",
"mobx-lark": "^2.10.2",
"mobx-react": "^10.0.3",
"mobx-react-helper": "^0.5.4",
"mobx-restful": "^2.1.5",
"mobx-restful-table": "^2.7.8",
"mobx-strapi": "^0.8.1",
"next": "16.4.2",
"next-pwa": "^5.6.0",
"next-ssr-middleware": "^1.1.1",
"nodemailer": "^9.0.4",
"next": "16.4.3",
"next-ssr-middleware": "^1.1.5",
"nodemailer": "^10.2.1",
"open-react-map": "^0.9.1",
"react": "^19.2.8",
"react": "^19.3.1",
"react-bootstrap": "^2.10.10",
"react-dom": "^19.2.8",
"react-dom": "^19.3.1",
"react-typed-component": "^1.0.6",
"remark-frontmatter": "^5.0.0",
"remark-mdx-frontmatter": "^5.2.0",
"web-utility": "^4.7.2",
"yaml": "^2.9.0"
"remark-mdx-frontmatter": "^6.0.0",
"serwist": "^9.5.13",
"web-utility": "^4.8.1",
"yaml": "^2.9.1"
},
"devDependencies": {
"@cspell/eslint-plugin": "^10.0.1",
"@eslint/js": "^10.0.1",
"@next/eslint-plugin-next": "16.4.2",
"@softonus/prettier-plugin-duplicate-remover": "^1.1.2",
"@stylistic/eslint-plugin": "^5.10.0",
"@types/eslint-config-prettier": "^6.11.3",
"@types/jsonwebtoken": "^9.0.10",
"@types/koa": "^3.0.3",
"@types/next-pwa": "^5.6.9",
"@types/node": "^24.13.3",
"@types/nodemailer": "^8.0.1",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4",
"@types/node": "^26.6.5",
"@types/nodemailer": "^8.0.2",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"cross-env": "^10.1.0",
"eslint": "^10.8.0",
"eslint-config-next": "16.4.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-simple-import-sort": "^14.0.0",
"globals": "^17.9.0",
"eslint": "^10.13.0",
"eslint-idea2app-next-js": "^0.1.1",
"husky": "^9.1.7",
"jiti": "^2.7.0",
"less": "^4.8.1",
"less": "^4.9.1",
"less-loader": "^13.0.0",
"lint-staged": "^17.3.0",
"lint-staged": "^17.6.0",
"next-with-less": "^3.0.1",
"prettier": "^3.9.6",
"prettier": "^3.9.10",
"prettier-plugin-css-order": "^2.2.0",
"typescript": "~6.0.3",
"typescript-eslint": "^8.66.0"
"typescript": "~6.0.3"
},
"resolutions": {
"next": "$next"
Expand Down
Loading
Loading