mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-09-14 19:59:52 +08:00
ci(pages): add ESLint and bundle size check to CI pipeline (#558)
- Add ESLint with typescript-eslint and react-hooks plugin
- Add size-limit to monitor initial bundle size (150 kB threshold)
- Rename .js configs to .cjs for ESM compatibility ("type": "module")
- Fix no-useless-escape and no-useless-assignment lint errors
- Update pages-ci.yml with lint and size check steps
This commit is contained in:
@@ -29,6 +29,10 @@ jobs:
|
||||
working-directory: pages
|
||||
run: npm install
|
||||
|
||||
- name: Lint
|
||||
working-directory: pages
|
||||
run: npm run lint
|
||||
|
||||
- name: Typecheck
|
||||
working-directory: pages
|
||||
run: npm run typecheck
|
||||
@@ -36,3 +40,7 @@ jobs:
|
||||
- name: Build
|
||||
working-directory: pages
|
||||
run: npm run build
|
||||
|
||||
- name: Check bundle size
|
||||
working-directory: pages
|
||||
run: npm run size
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import js from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
|
||||
export default tseslint.config(
|
||||
js.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
plugins: { "react-hooks": reactHooks },
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
"react-hooks/set-state-in-effect": "off",
|
||||
"no-empty": ["error", { allowEmptyCatch: true }],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
},
|
||||
},
|
||||
{ ignores: ["dist/", "node_modules/", "*.cjs"] }
|
||||
);
|
||||
+16
-1
@@ -2,10 +2,13 @@
|
||||
"name": "open-code-review-landing",
|
||||
"version": "1.0.0",
|
||||
"description": "Landing page for Open Code Review",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "webpack serve",
|
||||
"build": "NODE_ENV=production webpack --mode production",
|
||||
"typecheck": "tsc --noEmit"
|
||||
"typecheck": "tsc --noEmit",
|
||||
"lint": "eslint src/",
|
||||
"size": "size-limit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@agentscope-ai/icons": "^1.0.68",
|
||||
@@ -20,11 +23,19 @@
|
||||
"overrides": {
|
||||
"fast-uri": "^3.1.2"
|
||||
},
|
||||
"size-limit": [
|
||||
{
|
||||
"path": "dist/*.bundle.js",
|
||||
"limit": "150 kB"
|
||||
}
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.5",
|
||||
"@babel/preset-env": "^7.29.5",
|
||||
"@babel/preset-react": "^7.23.5",
|
||||
"@babel/preset-typescript": "^7.23.3",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@size-limit/file": "^13.0.1",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.0",
|
||||
@@ -33,12 +44,16 @@
|
||||
"babel-loader": "^9.1.3",
|
||||
"copy-webpack-plugin": "^14.0.0",
|
||||
"css-loader": "^6.8.1",
|
||||
"eslint": "^10.8.0",
|
||||
"eslint-plugin-react-hooks": "^7.1.1",
|
||||
"html-webpack-plugin": "^5.5.3",
|
||||
"postcss": "^8.5.15",
|
||||
"postcss-loader": "^7.3.3",
|
||||
"size-limit": "^13.0.1",
|
||||
"style-loader": "^3.3.3",
|
||||
"tailwindcss": "^3.3.5",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-eslint": "^8.65.0",
|
||||
"webpack": "^5.89.0",
|
||||
"webpack-cli": "^5.1.4",
|
||||
"webpack-dev-server": "^5.2.4"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
tailwindcss: { config: './tailwind.config.cjs' },
|
||||
autoprefixer: {}
|
||||
}
|
||||
};
|
||||
@@ -113,7 +113,7 @@ export function searchBlog(query: string, language: string): { slug: BlogSlug; t
|
||||
const lowerTitle = meta.title.toLowerCase();
|
||||
const lowerSummary = (meta.summary || '').toLowerCase();
|
||||
|
||||
let snippet = '';
|
||||
let snippet: string;
|
||||
const contentIdx = lowerContent.indexOf(lowerQuery);
|
||||
if (lowerTitle.includes(lowerQuery)) {
|
||||
snippet = meta.title;
|
||||
@@ -122,7 +122,7 @@ export function searchBlog(query: string, language: string): { slug: BlogSlug; t
|
||||
} else if (contentIdx !== -1) {
|
||||
const start = Math.max(0, contentIdx - 30);
|
||||
const end = Math.min(content.length, contentIdx + query.length + 60);
|
||||
snippet = content.slice(start, end).replace(/[#*_`\[\]()]/g, '').replace(/\n/g, ' ').trim();
|
||||
snippet = content.slice(start, end).replace(/[#*_`[\]()]/g, '').replace(/\n/g, ' ').trim();
|
||||
if (start > 0) snippet = '...' + snippet;
|
||||
if (end < content.length) snippet = snippet + '...';
|
||||
} else {
|
||||
|
||||
@@ -198,7 +198,7 @@ export function searchDocs(query: string, language: string): { slug: DocSlug; ti
|
||||
// Extract snippet around match
|
||||
const start = Math.max(0, idx - 30);
|
||||
const end = Math.min(content.length, idx + query.length + 60);
|
||||
let snippet = content.slice(start, end).replace(/[#*_`\[\]()]/g, '').replace(/\n/g, ' ').trim();
|
||||
let snippet = content.slice(start, end).replace(/[#*_`[\]()]/g, '').replace(/\n/g, ' ').trim();
|
||||
if (start > 0) snippet = '...' + snippet;
|
||||
if (end < content.length) snippet = snippet + '...';
|
||||
const title = getDocTitle(slug, language);
|
||||
|
||||
@@ -17,7 +17,7 @@ export function extractHeadings(markdown: string): { id: string; text: string; l
|
||||
// Strip markdown link syntax [text](url) → text, then strip other formatting
|
||||
const text = match[2]
|
||||
.replace(/\[([^\]]+)]\([^)]*\)/g, '$1')
|
||||
.replace(/[`*_\[\]()]/g, '')
|
||||
.replace(/[`*_[\]()]/g, '')
|
||||
.trim();
|
||||
const id = generateHeadingId(text);
|
||||
headings.push({ id, text, level });
|
||||
|
||||
@@ -10,7 +10,7 @@ export function generateHeadingId(text: string): string {
|
||||
// bypassed by nested tags). Keeps text content, decodes HTML entities so the
|
||||
// TOC side (raw markdown) and renderer side (marked HTML output) agree.
|
||||
const plain = DOMPurify.sanitize(text, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] })
|
||||
.replace(/[`*_\[\]()]/g, '')
|
||||
.replace(/[`*_[\]()]/g, '')
|
||||
.trim();
|
||||
return plain.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff]+/g, '-').replace(/^-|-$/g, '');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user