Skip to content

Commit

Permalink
[migrate] upgrade to Next.js 15, ESLint 9, KoAJAX 3.1 & other latest …
Browse files Browse the repository at this point in the history
…Upstream packages

[add] Prettier CSS plugins

Signed-off-by: TechQuery <[email protected]>
  • Loading branch information
TechQuery committed Dec 1, 2024
1 parent 59a004a commit dbc7724
Show file tree
Hide file tree
Showing 22 changed files with 3,112 additions and 2,907 deletions.
10 changes: 0 additions & 10 deletions .eslintrc.json

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
## Technology stack

- Language: [TypeScript v5][10] + [MDX v3][11]
- Component engine: [Next.js v14][12]
- Component engine: [Next.js v15][12]
- Component suite: [Bootstrap v5][13]
- PWA framework: [Workbox v6][14]
- State management: [MobX v6][15]
Expand Down
8 changes: 4 additions & 4 deletions components/Form/JSONEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ export class ListField extends Component<FieldProps> {
}

addItem = (type: string) => {
var item: DataMeta = { type, value: [] },
{ innerValue } = this;
let item: DataMeta = { type, value: [] };
const { innerValue } = this;

switch (type) {
case 'string':
Expand Down Expand Up @@ -104,7 +104,7 @@ export class ListField extends Component<FieldProps> {

item.key = newKey;

for (let oldKey in value)
for (const oldKey in value)
if (!children.some(({ key }) => key === oldKey)) {
value[newKey] = value[oldKey];

Expand Down Expand Up @@ -168,7 +168,7 @@ export class ListField extends Component<FieldProps> {
<AddBar onSelect={this.addItem} />
</li>
{children.map(({ type, key, value }, index) => (
<li className="d-flex align-items-center gap-3" key={key}>
<li key={key} className="d-flex align-items-center gap-3">
{field_type === 'object' && (
<Form.Control
defaultValue={key}
Expand Down
2 changes: 1 addition & 1 deletion components/Form/MarkdownEditor/TurnDown.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import TurnDown from 'turndown';
// @ts-ignore
// @ts-expect-error no official types
import { gfm, strikethrough, tables, taskListItems } from 'turndown-plugin-gfm';

const Empty_HREF = /^(#|javascript:\s*void\(0\);?\s*)$/;
Expand Down
19 changes: 8 additions & 11 deletions components/Form/MarkdownEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,19 @@ export class MarkdownEditor extends Component<EditorProps> {
constructor(props: EditorProps) {
super(props);

for (let key in props.rules) this.convertor.addRule(key, props.rules[key]);
for (const key in props.rules)
this.convertor.addRule(key, props.rules[key]);
}

async componentDidMount() {
const MarkdownIME = await import('markdown-ime');
// @ts-ignore
// @ts-expect-error official type error
MarkdownIME.Enhance(this.root);
}

countText = debounce(() => {
var count = 0;

if (this.root) count = (this.root.textContent || '').trim().length;

this.count = count;
});
countText = debounce(
() => (this.count = this.root?.textContent?.trim().length || 0),
);

private manualChange() {
this.countText();
Expand Down Expand Up @@ -86,7 +83,7 @@ export class MarkdownEditor extends Component<EditorProps> {

event.preventDefault();

var list: DataTransferItem[] = Array.from(items);
let list: DataTransferItem[] = Array.from(items);

if (list.find(({ type }) => /xml|html/.test(type)))
list = list.filter(({ type }) => type !== 'text/plain');
Expand Down Expand Up @@ -128,8 +125,8 @@ export class MarkdownEditor extends Component<EditorProps> {
render() {
return (
<div
contentEditable
ref={this.contentEditable}
contentEditable
className={classNames(
'form-control',
'markdown-body',
Expand Down
10 changes: 5 additions & 5 deletions components/Git/ArticleEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class ArticleEditor extends Component {

return;
}
var content = (await readAs(data, 'text').result) as string;
let content = (await readAs(data, 'text').result) as string;

if (fileType.JSON.includes(type)) return (this.meta = JSON.parse(content));

Expand Down Expand Up @@ -136,7 +136,7 @@ export class ArticleEditor extends Component {
root = document.querySelector('div[contenteditable]');

if (root)
for (let element of root.querySelectorAll<HyperLink>('[href], [src]')) {
for (const element of root.querySelectorAll<HyperLink>('[href], [src]')) {
let URI =
element instanceof HTMLAnchorElement ? element.href : element.src;

Expand All @@ -163,7 +163,7 @@ export class ArticleEditor extends Component {

if (fileType.MarkDown.includes(type) && editorContent) {
if (!meta) return editorContent;
// @ts-ignore

meta.updated = formatDate();

return `---
Expand All @@ -178,7 +178,7 @@ export class ArticleEditor extends Component {
event.preventDefault();

const { currentRepository, repositoryStore, editorContent } = this,
// @ts-ignore
// @ts-expect-error DOM API shortcut
{ message } = event.currentTarget.elements;

if (!editorContent) return;
Expand All @@ -189,7 +189,7 @@ export class ArticleEditor extends Component {
({ src }) => new URL(src).protocol === 'blob:',
);

for (let file of media) {
for (const file of media) {
const blob = await blobOf(file.src);

const filePath = this.path.replace(
Expand Down
2 changes: 1 addition & 1 deletion components/Git/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const GitCard: FC<GitCardProps> = observer(
</nav>
<Row as="ul" className="list-unstyled g-4" xs={4}>
{languages.map(language => (
<Col as="li" key={language}>
<Col key={language} as="li">
<GitLogo name={language} />
</Col>
))}
Expand Down
2 changes: 1 addition & 1 deletion components/NotFoundCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const NotFoundCard: FC<ErrorProps> = ({ title }) =>
i18n.currentLanguage.startsWith('zh') ? (
<script
src="//cdn.dnpw.org/404/v1.min.js"
// @ts-ignore
// @ts-expect-error https://www.dnpw.org/cn/pa-notfound.html
jumptarget="/"
jumptime="-1"
error={title}
Expand Down
77 changes: 77 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// @ts-check
import { fixupConfigRules, fixupPluginRules } from '@eslint/compat';
import { FlatCompat } from '@eslint/eslintrc';
import eslint from '@eslint/js';
import eslintConfigPrettier from 'eslint-config-prettier';
import reactPlugin 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';

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

export default tsEslint.config(
// register all of the plugins up-front
{
plugins: {
'@typescript-eslint': tsEslint.plugin,
// @ts-expect-error https://github.com/jsx-eslint/eslint-plugin-react/issues/3699
react: fixupPluginRules(reactPlugin),
'simple-import-sort': simpleImportSortPlugin,
},
},
{
// config with just ignores is the replacement for `.eslintignore`
ignores: ['**/node_modules/**', '**/public/**', '**/.next/**'],
},

// extends ...
eslint.configs.recommended,
...tsEslint.configs.recommended,
...fixupConfigRules(flatCompat.extends('plugin:@next/next/core-web-vitals')),

// base config
{
languageOptions: {
globals: { ...globals.es2020, ...globals.browser, ...globals.node },
parserOptions: {
projectService: true,
tsconfigRootDir,
warnOnUnsupportedTypeScriptVersion: false,
},
},
rules: {
'no-empty-pattern': 'warn',
'simple-import-sort/exports': 'error',
'simple-import-sort/imports': 'error',
'@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',
'react/jsx-no-target-blank': 'warn',
'react/jsx-sort-props': [
'error',
{
reservedFirst: true,
callbacksLast: true,
noSortAlphabetically: true,
},
],
'@next/next/no-sync-scripts': 'warn',
},
},
{
files: ['**/*.js'],
extends: [tsEslint.configs.disableTypeChecked],
rules: {
// turn off other type-aware rules
'@typescript-eslint/internal/no-poorly-typed-ts-props': 'off',

// turn off rules that don't apply to JS code
'@typescript-eslint/explicit-function-return-type': 'off',
},
},
eslintConfigPrettier,
);
33 changes: 33 additions & 0 deletions models/Base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import 'core-js/full/array/from-async';

import { HTTPClient } from 'koajax';
import { githubClient } from 'mobx-github';
import { parseCookie } from 'mobx-i18n';

export const isServer = () => typeof window === 'undefined';

Expand All @@ -14,3 +18,32 @@ export const ownClient = new HTTPClient({
baseURI: `${API_Host}/api/`,
responseType: 'json',
});

export const PolyfillHost = 'https://polyfiller.kaiyuanshe.cn';

export const polyfillClient = new HTTPClient({
baseURI: PolyfillHost,
responseType: 'text',
});

const GithubToken =
parseCookie(globalThis.document?.cookie || '').token ||
process.env.GITHUB_TOKEN;

if (!isServer()) githubClient.baseURI = `${API_Host}/api/GitHub/`;

githubClient.use(({ request }, next) => {
if (GithubToken)
request.headers = {
authorization: `Bearer ${GithubToken}`,
...request.headers,
};
return next();
});

export const ProxyBaseURL = 'https://test.oss-toolbox.kaiyuanshe.cn/proxy';

export const githubRawClient = new HTTPClient({
baseURI: `${ProxyBaseURL}/raw.githubusercontent.com/`,
responseType: 'arraybuffer',
});
3 changes: 1 addition & 2 deletions models/Polyfill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { observable } from 'mobx';
import { BaseModel, toggle } from 'mobx-restful';
import { buildURLData } from 'web-utility';

import { PolyfillHost } from '../pages/api/polyfill';
import { ownClient } from './Base';
import { ownClient, PolyfillHost } from './Base';

export type JSEnvironment = 'window' | 'worker' | 'node';

Expand Down
29 changes: 3 additions & 26 deletions models/Repository.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,9 @@
import { HTTPClient } from 'koajax';
import { githubClient, RepositoryModel, UserModel } from 'mobx-github';
import { parseCookie } from 'mobx-i18n';
import { RepositoryModel, UserModel } from 'mobx-github';
import { toggle } from 'mobx-restful';

import { ProxyBaseURL } from '../pages/api/GitHub/core';
import { API_Host, isServer } from './Base';

const GithubToken =
parseCookie(globalThis.document?.cookie || '').token ||
process.env.GITHUB_TOKEN;

if (!isServer()) githubClient.baseURI = `${API_Host}/api/GitHub/`;

githubClient.use(({ request }, next) => {
if (GithubToken)
request.headers = {
authorization: `Bearer ${GithubToken}`,
...request.headers,
};
return next();
});
import { githubRawClient } from './Base';

export class GitRepositoryModel extends RepositoryModel {
downloader = new HTTPClient({
baseURI: `${ProxyBaseURL}/raw.githubusercontent.com/`,
responseType: 'arraybuffer',
});

@toggle('downloading')
async downloadRaw(
path: string,
Expand All @@ -41,7 +18,7 @@ export class GitRepositoryModel extends RepositoryModel {

ref = default_branch;
}
const { body } = await this.downloader.get<ArrayBuffer>(
const { body } = await githubRawClient.get<ArrayBuffer>(
`${identity}/${ref}/${path}`,
);
return body!;
Expand Down
15 changes: 4 additions & 11 deletions next.config.mjs → next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import NextMDX from '@next/mdx';
import { withSentryConfig } from '@sentry/nextjs';
import CopyPlugin from 'copy-webpack-plugin';
import { readdirSync, statSync } from 'fs';
// @ts-ignore
import { NextConfig } from 'next';
import setPWA from 'next-pwa';
// @ts-ignore
// @ts-expect-error no official types
import withLess from 'next-with-less';
import RemarkFrontMatter from 'remark-frontmatter';
import RemarkGfm from 'remark-gfm';
Expand All @@ -29,10 +29,7 @@ const withPWA = setPWA({
disable: isDev,
});

/**
* @type {import('next').NextConfig['webpack']}
*/
const webpack = config => {
const webpack: NextConfig['webpack'] = config => {
config.plugins.push(
new WP.NormalModuleReplacementPlugin(/^node:/, resource => {
resource.request = resource.request.replace(/^node:/, '');
Expand All @@ -53,10 +50,7 @@ const webpack = config => {
return config;
};

/**
* @type {import('next').NextConfig['rewrites']}
*/
const rewrites = async () => ({
const rewrites: NextConfig['rewrites'] = async () => ({
beforeFiles: [
{
source: '/proxy/github.com/:path*',
Expand Down Expand Up @@ -87,7 +81,6 @@ const rewrites = async () => ({
],
});

/** @type {import('next').NextConfig} */
const nextConfig = withPWA(
withLess(
withMDX({
Expand Down
Loading

1 comment on commit dbc7724

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for oss-toolbox ready!

✅ Preview
https://oss-toolbox-lowzjk4zp-techquerys-projects.vercel.app

Built with commit dbc7724.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.