Skip to content

Commit

Permalink
[add] Model, API & Page of Web polyfill CDN
Browse files Browse the repository at this point in the history
[optimize] switch Docker compose to Share mode
  • Loading branch information
TechQuery committed Mar 3, 2024
1 parent 51f1507 commit 97457f9
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 25 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
- CI / CD: GitHub [Actions][16] + [Vercel][17]
- Monitor service: [Sentry][18]

## Major features

### Open Source license filter

- [introduction](https://kaiyuanshe.feishu.cn/wiki/wikcnRn5pkE3BSvqFUMkJPymaG3)
- [home page](https://oss-toolbox.vercel.app/license-filter/)
- [source code](pages/license-filter.tsx)

## Major examples

1. [Markdown articles](pages/article/)
Expand Down
2 changes: 1 addition & 1 deletion components/MainNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const { t } = i18n,
LanguageMenu = dynamic(import('./LanguageMenu'), { ssr: false });

export const MainNavigator: FC = observer(() => (
<Navbar bg="primary" variant="dark" fixed="top" expand="sm" collapseOnSelect>
<Navbar bg="primary" variant="dark" fixed="top" expand="lg" collapseOnSelect>
<Container>
<Navbar.Brand href="/">{t('open_source_treasure_box')}</Navbar.Brand>

Expand Down
4 changes: 2 additions & 2 deletions components/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ export const MainRoutes: () => Link[] = () => [
title: 'GitHub issues',
path: '/issue',
},
{ title: t('license_tool'), path: '/tool/license-filter' },
{ title: t('license_tool'), path: '/license-filter' },
{
title: `${t('Web_polyfill_CDN')} v1`,
path: 'https://polyfill.kaiyuanshe.cn/',
},
{
title: `${t('Web_polyfill_CDN')} v2`,
path: 'https://polyfiller.kaiyuanshe.cn/',
path: '/polyfill',
},
{ title: t('open_source_mirror'), path: 'http://mirror.kaiyuanshe.cn/' },
{ title: 'Git Pager', path: 'https://git-pager.vercel.app/' },
Expand Down
24 changes: 2 additions & 22 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
version: '3'

networks:
idea2app:

services:
oss-toolbox:
image: kaiyuanshe/oss-toolbox
networks:
- idea2app
ports:
- 3002:3000
healthcheck:
test: ['CMD-SHELL', 'curl -f http://localhost:3000/ || exit 1']
interval: 3s
Expand All @@ -25,20 +22,3 @@ services:
driver: 'json-file'
options:
max-size: '10m'

autoheal:
image: willfarrell/autoheal:1.2.0
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: always

caddy:
depends_on:
- oss-toolbox
image: caddy
ports:
- 80:80
- 443:443
networks:
- idea2app
command: caddy reverse-proxy --from your.domain.com --to oss-toolbox:3000
88 changes: 88 additions & 0 deletions models/Polyfill.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
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';

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

export type LibraryAlias = Record<JSEnvironment, string>;

export type LibraryPath = Record<JSEnvironment, string[]>;

export interface Library {
features: string[];
dependencies: string[];
contexts: {};
meta?: object;
mustComeAfter?: string | string[];
}

export interface RemoteLibrary extends Library {
library: string | LibraryAlias;
relativePaths: string[] | LibraryPath;
}

export interface LocalLibrary extends Library {
version: string;
localPaths: string[];
}

export interface Alias {
polyfills: string[];
}

export type PolyfillIndex = Record<
string,
RemoteLibrary | LocalLibrary | Alias
>;

export const UserAgent: Record<string, string> = {
'IE 11':
'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko',
'Edge 18':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.19042',
'Safari 13.2':
'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1',
'Opera 9.8': 'Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.16',
'UC 12':
'Mozilla/5.0 (Linux; U; Android 8.1.0; en-US; Nexus 6P Build/OPM7.181205.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.11.1.1197 Mobile Safari/537.36',
'Firefox 70':
'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:70.0) Gecko/20100101 Firefox/70.0',
'Android 4':
'Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
};

export class PolyfillModel extends BaseModel {
@observable
accessor index: PolyfillIndex = {};

@observable
accessor currentUA = '';

@observable
accessor sourceCode = '';

@toggle('downloading')
async getIndex() {
const { body } = await ownClient.get<PolyfillIndex>(
`${PolyfillHost}/index.json`,
);
return (this.index = body!);
}

@toggle('downloading')
async getSourceCode(UA: string, features: string[]) {
const response = await fetch(
`/api/polyfill?${buildURLData({ features })}`,
{
headers: { 'User-Agent': UserAgent[UA] },
},
);
this.currentUA = UA;
return (this.sourceCode = await response.text());
}
}

export default new PolyfillModel();
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"next-pwa": "~5.6.0",
"next-ssr-middleware": "^0.7.0",
"next-with-less": "^3.0.1",
"primereact": "^10.5.1",
"prismjs": "^1.29.0",
"react": "^18.2.0",
"react-bootstrap": "^2.10.1",
Expand Down
27 changes: 27 additions & 0 deletions pages/api/polyfill.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { HTTPClient } from 'koajax';

import { safeAPI } from './core';

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

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

export default safeAPI(async ({ method, url, headers, body }, response) => {
delete headers.host;

const { status, body: data } = await polyfillClient.request({
// @ts-ignore
method,
path: url!,
// @ts-ignore
headers,
body: body || undefined,
});

response.status(status);
response.setHeader('Access-Control-Allow-Headers', '*');
response.send(data);
});
114 changes: 114 additions & 0 deletions pages/polyfill.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { Loading } from 'idea-react';
import { computed, observable } from 'mobx';
import { textJoin } from 'mobx-i18n';
import { observer } from 'mobx-react';
import { compose, translator } from 'next-ssr-middleware';
import { TreeNode } from 'primereact/treenode';
import { TreeSelect, TreeSelectSelectionKeysType } from 'primereact/treeselect';
import { Component } from 'react';
import { Card, Container, Dropdown, DropdownButton } from 'react-bootstrap';

import { PageHead } from '../components/PageHead';
import polyfillStore, { UserAgent } from '../models/Polyfill';
import { i18n } from '../models/Translation';
import { PolyfillHost } from './api/polyfill';

export const getServerSideProps = compose(translator(i18n));

const { t } = i18n;

@observer
export default class PolyfillPage extends Component {
@computed
get options() {
return Object.entries(polyfillStore.index)
.map(([key, data]) => !('polyfills' in data) && { key, label: key, data })
.filter(Boolean) as TreeNode[];
}

@observable
accessor selectOptions: TreeSelectSelectionKeysType = {};

@computed
get features() {
return Object.keys(this.selectOptions);
}

@computed
get polyfillURL() {
return `${PolyfillHost}/api/polyfill?features=${this.features}`;
}

componentDidMount() {
polyfillStore.getIndex();
}

renderContent() {
const { options, selectOptions, features, polyfillURL } = this,
{ currentUA, sourceCode } = polyfillStore;

return (
<main className="d-flex flex-column gap-3 mb-3">
<TreeSelect
placeholder="features"
display="chip"
filter
selectionMode="checkbox"
options={options}
value={selectOptions}
onChange={({ value }) =>
(this.selectOptions = value as TreeSelectSelectionKeysType)
}
/>
<div className="d-flex justify-content-around align-items-center">
<DropdownButton title={textJoin(t('examples'), currentUA)}>
{Object.entries(UserAgent).map(([name, value]) => (
<Dropdown.Item
key={name}
title={value}
onClick={() => polyfillStore.getSourceCode(name, features)}
>
{name}
</Dropdown.Item>
))}
</DropdownButton>

<h1>{t('Web_polyfill_CDN')}</h1>
</div>

<Card body>
<a target="_blank" href={polyfillURL} rel="noreferrer">
{polyfillURL}
</a>
<hr />
<pre>
<code>{sourceCode}</code>
</pre>
</Card>
</main>
);
}

render() {
const { downloading } = polyfillStore;

return (
<Container>
<PageHead title={t('Web_polyfill_CDN')}>
<link
rel="stylesheet"
href="https://unpkg.com/primereact/resources/primereact.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/primereact/resources/themes/bootstrap4-light-blue/theme.css"
/>
</PageHead>

{downloading > 0 && <Loading />}

{this.renderContent()}
</Container>
);
}
}
21 changes: 21 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 comment on commit 97457f9

@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-ejqr7w9yq-techquery.vercel.app

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

Please sign in to comment.