commit
6603e2c578
17 changed files with 1543 additions and 5055 deletions
|
@ -1,38 +0,0 @@
|
|||
const presets = [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: false,
|
||||
// see also zloirock/core-js https://bit.ly/2JLnrgw
|
||||
useBuiltIns: 'usage',
|
||||
corejs: '3.8.1',
|
||||
// new in babel 7.9.0 https://babeljs.io/blog/2020/03/16/7.9.0
|
||||
bugfixes: true,
|
||||
},
|
||||
],
|
||||
['@babel/preset-react', { runtime: 'automatic' }],
|
||||
'@babel/preset-typescript',
|
||||
];
|
||||
|
||||
module.exports = (api) => {
|
||||
// https://babeljs.io/docs/en/config-files#apicache
|
||||
api.cache.using(() => process.env.NODE_ENV);
|
||||
// https://babeljs.io/docs/en/config-files#apienv
|
||||
const isDev = api.env('development');
|
||||
const plugins = [
|
||||
[
|
||||
'@babel/plugin-transform-runtime',
|
||||
{
|
||||
corejs: false,
|
||||
helpers: true,
|
||||
regenerator: true,
|
||||
useESModules: true,
|
||||
},
|
||||
],
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
'@babel/plugin-proposal-do-expressions',
|
||||
isDev ? 'react-refresh/babel' : false,
|
||||
].filter(Boolean);
|
||||
return { presets, plugins };
|
||||
};
|
|
@ -1,23 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="shortcut icon" href="yacd.ico" />
|
||||
<link rel="icon" type="image/png" sizes="64x64" href="yacd-64.png" />
|
||||
<link rel="icon" type="image/png" sizes="128x128" href="yacd-128.png" />
|
||||
<link
|
||||
rel="apple-touch-icon-precomposed"
|
||||
href="apple-touch-icon-precomposed.png"
|
||||
/>
|
||||
<link rel="apple-touch-icon-precomposed" href="apple-touch-icon-precomposed.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="yacd">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="application-name" content="yacd" />
|
||||
<meta name="description" content="Yet Another Clash Dashboard" />
|
||||
<meta name="theme-color" content="#202020" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<title>yacd</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" data-base-url="http://127.0.0.1:9090"></div>
|
||||
<script type="module" src="/src/app.tsx"></script>
|
||||
</body>
|
||||
</html>
|
139
package.json
139
package.json
|
@ -4,8 +4,10 @@
|
|||
"description": "Yet another Clash dashboard",
|
||||
"scripts": {
|
||||
"lint": "eslint --fix --cache src",
|
||||
"start": "NODE_ENV=development node server.js",
|
||||
"build": "NODE_ENV=production webpack",
|
||||
"dev": "vite",
|
||||
"start": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview",
|
||||
"pretty": "prettier --single-quote --write 'src/**/*.{js,scss,ts,tsx,md}'"
|
||||
},
|
||||
"browserslist": [
|
||||
|
@ -21,118 +23,87 @@
|
|||
"private": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.8",
|
||||
"@babel/runtime": "7.14.0",
|
||||
"@hsjs/react-cache": "0.0.0-alpha.aa94237",
|
||||
"@reach/tooltip": "^0.13.2",
|
||||
"@sentry/browser": "^6.2.0",
|
||||
"chart.js": "^2.9.2",
|
||||
"@reach/tooltip": "0.15.0",
|
||||
"@sentry/browser": "6.4.1",
|
||||
"chart.js": "2.9.2",
|
||||
"clsx": "^1.1.0",
|
||||
"core-js": "^3.9.0",
|
||||
"date-fns": "^2.17.0",
|
||||
"core-js": "3.13.1",
|
||||
"date-fns": "2.22.1",
|
||||
"fontsource-open-sans": "^4.0.0",
|
||||
"fontsource-roboto-mono": "^4.0.0",
|
||||
"framer-motion": "^3.7.0",
|
||||
"framer-motion": "4.1.17",
|
||||
"history": "^5.0.0",
|
||||
"i18next": "^19.9.0",
|
||||
"i18next-browser-languagedetector": "^6.0.1",
|
||||
"i18next-http-backend": "^1.1.1",
|
||||
"immer": "^8.0.1",
|
||||
"i18next": "20.3.1",
|
||||
"i18next-browser-languagedetector": "6.1.1",
|
||||
"i18next-http-backend": "1.2.6",
|
||||
"immer": "9.0.2",
|
||||
"invariant": "^2.2.4",
|
||||
"lodash-es": "^4.17.21",
|
||||
"memoize-one": "^5.1.1",
|
||||
"modern-normalize": "^1.0.0",
|
||||
"memoize-one": "5.2.1",
|
||||
"modern-normalize": "1.1.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "0.0.0-experimental-94c0244ba",
|
||||
"react-dom": "0.0.0-experimental-94c0244ba",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-feather": "^2.0.9",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-i18next": "^11.8.8",
|
||||
"react-i18next": "11.10.0",
|
||||
"react-icons": "^4.2.0",
|
||||
"react-modal": "^3.12.1",
|
||||
"react-query": "^3.12.0",
|
||||
"react-modal": "3.13.1",
|
||||
"react-query": "3.16.0",
|
||||
"react-router": "6.0.0-beta.0",
|
||||
"react-router-dom": "6.0.0-beta.0",
|
||||
"react-switch": "^6.0.0",
|
||||
"react-table": "^7.6.3",
|
||||
"react-tabs": "^3.2.0",
|
||||
"react-tiny-fab": "^4.0.2",
|
||||
"react-table": "7.7.0",
|
||||
"react-tabs": "3.2.2",
|
||||
"react-tiny-fab": "4.0.3",
|
||||
"react-window": "^1.8.5",
|
||||
"recoil": "^0.1.2",
|
||||
"recoil": "0.3.1",
|
||||
"regenerator-runtime": "^0.13.7",
|
||||
"reselect": "^4.0.0",
|
||||
"tslib": "^2.1.0",
|
||||
"workbox-core": "^6.1.1",
|
||||
"workbox-expiration": "^6.1.1",
|
||||
"workbox-precaching": "^6.1.1",
|
||||
"workbox-routing": "^6.1.1",
|
||||
"workbox-strategies": "^6.1.1"
|
||||
"tslib": "2.2.0",
|
||||
"workbox-core": "6.1.5",
|
||||
"workbox-expiration": "6.1.5",
|
||||
"workbox-precaching": "6.1.5",
|
||||
"workbox-routing": "6.1.5",
|
||||
"workbox-strategies": "6.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.13.8",
|
||||
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
||||
"@babel/plugin-proposal-do-expressions": "^7.12.13",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
|
||||
"@babel/plugin-transform-runtime": "^7.13.8",
|
||||
"@babel/preset-env": "^7.13.8",
|
||||
"@babel/preset-react": "^7.12.13",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
|
||||
"@types/invariant": "^2.2.33",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@types/jest": "26.0.23",
|
||||
"@types/lodash-es": "^4.17.4",
|
||||
"@types/react": "^17.0.2",
|
||||
"@types/react-dom": "^17.0.1",
|
||||
"@types/react-helmet": "^6.1.0",
|
||||
"@types/react": "17.0.8",
|
||||
"@types/react-dom": "17.0.5",
|
||||
"@types/react-modal": "^3.12.0",
|
||||
"@types/react-tabs": "^2.3.2",
|
||||
"@types/react-window": "^1.8.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.15.2",
|
||||
"@typescript-eslint/parser": "^4.15.2",
|
||||
"autoprefixer": "^10.2.4",
|
||||
"babel-eslint": "10.x",
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^7.0.0",
|
||||
"css-loader": "^5.1.0",
|
||||
"css-minimizer-webpack-plugin": "^1.2.0",
|
||||
"cssnano": "^4.1.7",
|
||||
"eslint": "^7.21.0",
|
||||
"@types/react-window": "1.8.3",
|
||||
"@typescript-eslint/eslint-plugin": "4.25.0",
|
||||
"@typescript-eslint/parser": "4.25.0",
|
||||
"@vitejs/plugin-react-refresh": "1.3.3",
|
||||
"autoprefixer": "10.2.6",
|
||||
"cssnano": "5.0.5",
|
||||
"eslint": "7.27.0",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-config-react-app": "^6.0.0",
|
||||
"eslint-import-resolver-webpack": "^0.13.0",
|
||||
"eslint-plugin-flowtype": "^5.3.1",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jest": "^24.1.5",
|
||||
"eslint-plugin-flowtype": "5.7.2",
|
||||
"eslint-plugin-import": "2.23.4",
|
||||
"eslint-plugin-jest": "24.3.6",
|
||||
"eslint-plugin-jsx-a11y": "^6.3.1",
|
||||
"eslint-plugin-react": "^7.22.0",
|
||||
"eslint-plugin-react": "7.24.0",
|
||||
"eslint-plugin-react-hooks": "^4.1.2",
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"express": "^4.17.1",
|
||||
"file-loader": "^6.1.1",
|
||||
"fork-ts-checker-notifier-webpack-plugin": "^3.0.0",
|
||||
"fork-ts-checker-webpack-plugin": "^6.1.0",
|
||||
"html-webpack-plugin": "^5.2.0",
|
||||
"mini-css-extract-plugin": "^1.3.9",
|
||||
"postcss": "^8.2.6",
|
||||
"postcss": "8.3.0",
|
||||
"postcss-custom-media": "^8.0.0",
|
||||
"postcss-extend-rule": "^3.0.0",
|
||||
"postcss-import": "^14.0.0",
|
||||
"postcss-loader": "^5.0.0",
|
||||
"postcss-nested": "^5.0.4",
|
||||
"postcss-import": "14.0.2",
|
||||
"postcss-loader": "5.3.0",
|
||||
"postcss-nested": "5.0.5",
|
||||
"postcss-simple-vars": "^6.0.3",
|
||||
"prettier": "^2.2.1",
|
||||
"react-refresh": "^0.9.0",
|
||||
"prettier": "2.3.0",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"style-loader": "^2.0.0",
|
||||
"terser-webpack-plugin": "^5.1.1",
|
||||
"ts-loader": "^8.0.17",
|
||||
"typescript": "^4.2.2",
|
||||
"webpack": "^5.24.2",
|
||||
"webpack-bundle-analyzer": "^4.4.0",
|
||||
"webpack-cli": "^4.5.0",
|
||||
"webpack-dev-middleware": "^4.1.0",
|
||||
"webpack-hot-middleware": "^2.22.2",
|
||||
"workbox-webpack-plugin": "^6.1.1"
|
||||
"typescript": "4.3.2",
|
||||
"vite": "2.3.4",
|
||||
"vite-plugin-pwa": "0.7.3"
|
||||
}
|
||||
}
|
||||
|
|
23
postcss.config.js
Normal file
23
postcss.config.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require('postcss-import')(),
|
||||
require('postcss-simple-vars')(),
|
||||
require('postcss-custom-media')({
|
||||
importFrom: [
|
||||
{
|
||||
customMedia: {
|
||||
'--breakpoint-not-small': 'screen and (min-width: 30em)',
|
||||
'--breakpoint-medium':
|
||||
'screen and (min-width: 30em) and (max-width: 60em)',
|
||||
'--breakpoint-large': 'screen and (min-width: 60em)',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
require('postcss-nested')(),
|
||||
require('autoprefixer')(),
|
||||
require('postcss-extend-rule')(),
|
||||
],
|
||||
};
|
62
server.js
62
server.js
|
@ -1,62 +0,0 @@
|
|||
const path = require('path');
|
||||
const config = require('./webpack.config');
|
||||
const webpack = require('webpack');
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
|
||||
const devMiddleware = require('webpack-dev-middleware');
|
||||
const hotMiddleware = require('webpack-hot-middleware');
|
||||
|
||||
const { PORT } = process.env;
|
||||
const port = PORT ? Number(PORT) : 3000;
|
||||
const publicPath = config.output.publicPath;
|
||||
|
||||
config.entry.app.import.unshift('webpack-hot-middleware/client');
|
||||
config.plugins.push(
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin()
|
||||
);
|
||||
|
||||
const compiler = webpack(config);
|
||||
|
||||
const wdm = devMiddleware(compiler, { publicPath });
|
||||
const whm = hotMiddleware(compiler);
|
||||
|
||||
app.use(wdm);
|
||||
app.use(whm);
|
||||
|
||||
app.get('/_dev', (_req, res) => {
|
||||
const outputPath = wdm.getFilenameFromUrl(publicPath || '/');
|
||||
const filesystem = wdm.fileSystem;
|
||||
const content = filesystem.readdirSync(outputPath);
|
||||
res.end(content.join('\n'));
|
||||
});
|
||||
|
||||
app.use('*', (_req, res, next) => {
|
||||
const filename = path.join(compiler.outputPath, 'index.html');
|
||||
compiler.outputFileSystem.readFile(filename, (err, result) => {
|
||||
if (err) return next(err);
|
||||
|
||||
res.set('content-type', 'text/html');
|
||||
res.send(result);
|
||||
res.end();
|
||||
});
|
||||
});
|
||||
|
||||
const host = '0.0.0.0';
|
||||
|
||||
app.listen(port, host, () => {
|
||||
console.log(`>> Listening at http://${host}:${port}`);
|
||||
});
|
||||
|
||||
wdm.waitUntilValid(() => {
|
||||
console.log(
|
||||
`
|
||||
>> Build ready at:
|
||||
|
||||
http://${host}:${port}
|
||||
http://127.0.0.1:${port}
|
||||
http://localhost:${port}
|
||||
`
|
||||
);
|
||||
});
|
|
@ -12,8 +12,12 @@ const rootEl = document.getElementById('app');
|
|||
|
||||
Modal.setAppElement(rootEl);
|
||||
|
||||
const root = ReactDOM.unstable_createRoot(rootEl);
|
||||
root.render(<Root />);
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<Root />
|
||||
</React.StrictMode>,
|
||||
rootEl
|
||||
);
|
||||
|
||||
swRegistration.register();
|
||||
|
||||
|
|
|
@ -69,7 +69,9 @@ const routes = [
|
|||
{ path: '/proxies', element: <Proxies /> },
|
||||
{ path: '/rules', element: <Rules /> },
|
||||
{ path: '/about', element: <About /> },
|
||||
__DEV__ ? { path: '/style', element: <StyleGuide /> } : false,
|
||||
process.env.NODE_ENV === 'development'
|
||||
? { path: '/style', element: <StyleGuide /> }
|
||||
: false,
|
||||
].filter(Boolean) as PartialRouteObject[];
|
||||
|
||||
function RouteInnerApp() {
|
||||
|
|
|
@ -43,22 +43,3 @@ export function Selection2({
|
|||
</fieldset>
|
||||
);
|
||||
}
|
||||
|
||||
// for test
|
||||
// @ts-expect-error ts-migrate(7030) FIXME: Not all code paths return a value.
|
||||
export function Option({ title }) {
|
||||
// eslint-disable-next-line no-undef
|
||||
if (__DEV__) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: 100,
|
||||
height: 60,
|
||||
backgroundColor: '#eee',
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import React from 'react';
|
||||
import Switch from 'react-switch';
|
||||
import S from 'react-switch';
|
||||
|
||||
import { getTheme } from '../store/app';
|
||||
import { connect } from './StateProvider';
|
||||
|
||||
// workaround https://github.com/vitejs/vite/issues/2139#issuecomment-802981228
|
||||
const Switch = S.default ? S.default : S;
|
||||
|
||||
function SwitchThemed({ checked = false, onChange, theme, name }) {
|
||||
const offColor = theme === 'dark' ? '#393939' : '#e9e9e9';
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as React from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { connect } from 'src/components/StateProvider';
|
||||
import { getClashAPIConfig, getClashAPIConfigs } from 'src/store/app';
|
||||
|
||||
|
@ -8,21 +7,27 @@ const mapState = (s) => ({
|
|||
apiConfigs: getClashAPIConfigs(s),
|
||||
});
|
||||
|
||||
function HeadImpl({ apiConfig, apiConfigs }: { apiConfig: { baseURL: string }, apiConfigs: any[] }) {
|
||||
let title = 'yacd';
|
||||
if (apiConfigs.length > 1) {
|
||||
try {
|
||||
const host = new URL(apiConfig.baseURL).host;
|
||||
title = `${host} - yacd`;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
function HeadImpl({
|
||||
apiConfig,
|
||||
apiConfigs,
|
||||
}: {
|
||||
apiConfig: { baseURL: string };
|
||||
apiConfigs: any[];
|
||||
}) {
|
||||
React.useEffect(() => {
|
||||
let title = 'yacd';
|
||||
if (apiConfigs.length > 1) {
|
||||
try {
|
||||
const host = new URL(apiConfig.baseURL).host;
|
||||
title = `${host} - yacd`;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Helmet>
|
||||
<title>{title}</title>
|
||||
</Helmet>
|
||||
);
|
||||
document.title = title;
|
||||
});
|
||||
|
||||
return <></>;
|
||||
}
|
||||
|
||||
export const Head = connect(mapState)(HeadImpl);
|
||||
|
|
1
src/custom.d.ts
vendored
1
src/custom.d.ts
vendored
|
@ -13,7 +13,6 @@ interface Window {
|
|||
|
||||
// webpack definePlugin replacing variables
|
||||
declare const __VERSION__: string;
|
||||
declare const __DEV__: string;
|
||||
declare const process = {
|
||||
env: {
|
||||
NODE_ENV: string,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
|
||||
import { commonChartOptions } from '../misc/chart';
|
||||
import { commonChartOptions } from 'src/misc/chart';
|
||||
|
||||
const { useEffect } = React;
|
||||
const options = commonChartOptions;
|
||||
|
@ -13,7 +12,6 @@ export default function useLineChart(
|
|||
extraChartOptions = {}
|
||||
) {
|
||||
useEffect(() => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'getContext' does not exist on type 'HTML... Remove this comment to see the full error message
|
||||
const ctx = document.getElementById(elementId).getContext('2d');
|
||||
const c = new Chart(ctx, {
|
||||
type: 'line',
|
||||
|
|
|
@ -46,7 +46,7 @@ registerRoute(
|
|||
// Return true to signal that we want to use the handler.
|
||||
return true;
|
||||
},
|
||||
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
|
||||
createHandlerBoundToURL('index.html')
|
||||
);
|
||||
|
||||
// An example runtime caching route for requests that aren't handled by the
|
||||
|
|
|
@ -2,29 +2,32 @@
|
|||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"target": "ESNext",
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowJs": false,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react",
|
||||
"downlevelIteration": true,
|
||||
"importHelpers": true,
|
||||
"sourceMap": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"allowJs": false,
|
||||
"checkJs": false,
|
||||
"lib": ["dom", "es2015", "es2016", "es2017", "esnext"],
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"experimentalDecorators": true,
|
||||
"noImplicitAny": false,
|
||||
"noUnusedParameters": false,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"types": ["jest"],
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
"types": ["jest"]
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
||||
|
|
35
vite.config.ts
Normal file
35
vite.config.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
import reactRefresh from '@vitejs/plugin-react-refresh';
|
||||
import * as path from 'path';
|
||||
import * as pkg from './package.json';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode }) => ({
|
||||
define: {
|
||||
__VERSION__: JSON.stringify(pkg.version),
|
||||
'process.env.NODE_ENV': JSON.stringify(mode),
|
||||
'process.env.PUBLIC_URL': JSON.stringify('./'),
|
||||
},
|
||||
publicDir: 'assets',
|
||||
build: {
|
||||
// the default value is 'dist'
|
||||
// which make more sense
|
||||
// but change this may break other people's tools
|
||||
outDir: 'public',
|
||||
},
|
||||
plugins: [
|
||||
reactRefresh(),
|
||||
VitePWA({
|
||||
srcDir: 'src',
|
||||
outDir: 'public',
|
||||
filename: 'sw.ts',
|
||||
strategies: 'injectManifest',
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
src: path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
}));
|
|
@ -1,186 +0,0 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||
const HTMLPlugin = require('html-webpack-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin');
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||
const { InjectManifest } = require('workbox-webpack-plugin');
|
||||
|
||||
const pkg = require('./package.json');
|
||||
|
||||
process.env.BABEL_ENV = process.env.NODE_ENV;
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const publicPath = '';
|
||||
|
||||
const html = new HTMLPlugin({
|
||||
title: 'yacd - Yet Another Clash Dashboard',
|
||||
template: 'src/index.template.ejs',
|
||||
scriptLoading: 'defer',
|
||||
filename: 'index.html',
|
||||
});
|
||||
|
||||
const postcssPlugins = () =>
|
||||
[
|
||||
require('postcss-import')(),
|
||||
require('postcss-simple-vars')(),
|
||||
require('postcss-custom-media')({
|
||||
importFrom: [
|
||||
{
|
||||
customMedia: {
|
||||
'--breakpoint-not-small': 'screen and (min-width: 30em)',
|
||||
'--breakpoint-medium':
|
||||
'screen and (min-width: 30em) and (max-width: 60em)',
|
||||
'--breakpoint-large': 'screen and (min-width: 60em)',
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
require('postcss-nested')(),
|
||||
require('autoprefixer')(),
|
||||
require('postcss-extend-rule')(),
|
||||
].filter(Boolean);
|
||||
|
||||
const postcssOptions = { plugins: postcssPlugins() };
|
||||
|
||||
const cssExtractPlugin = new MiniCssExtractPlugin({
|
||||
filename: isDev ? '[name].css' : '[name].[contenthash].css',
|
||||
});
|
||||
|
||||
const bundleAnalyzerPlugin = new BundleAnalyzerPlugin({
|
||||
analyzerMode: 'static',
|
||||
reportFilename: 'report.html',
|
||||
openAnalyzer: false,
|
||||
});
|
||||
|
||||
const plugins = [
|
||||
html,
|
||||
new webpack.DefinePlugin({
|
||||
__DEV__: JSON.stringify(isDev),
|
||||
__VERSION__: JSON.stringify(pkg.version),
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
'process.env.PUBLIC_URL': JSON.stringify(publicPath),
|
||||
}),
|
||||
new ForkTsCheckerWebpackPlugin(),
|
||||
new ForkTsCheckerNotifierWebpackPlugin({
|
||||
title: 'TypeScript',
|
||||
excludeWarnings: false,
|
||||
}),
|
||||
new CopyPlugin({ patterns: [{ from: 'assets' }] }),
|
||||
new CleanWebpackPlugin(),
|
||||
// chart.js requires moment
|
||||
// and we don't need locale stuff in moment
|
||||
new webpack.IgnorePlugin({ resourceRegExp: /(^\.\/locale$)|(moment$)/ }),
|
||||
isDev
|
||||
? false
|
||||
: new InjectManifest({
|
||||
swSrc: './src/sw.ts',
|
||||
dontCacheBustURLsMatching: /\.[0-9a-f]{20}\./,
|
||||
exclude: [
|
||||
/\.map$/,
|
||||
/asset-manifest\.json$/,
|
||||
/LICENSE/,
|
||||
'CNAME',
|
||||
'_headers',
|
||||
],
|
||||
}),
|
||||
// https://github.com/pmmmwh/react-refresh-webpack-plugin
|
||||
isDev
|
||||
? new ReactRefreshWebpackPlugin({
|
||||
overlay: { sockIntegration: 'whm' },
|
||||
})
|
||||
: false,
|
||||
// isDev ? false : new webpack.HashedModuleIdsPlugin(),
|
||||
isDev ? false : cssExtractPlugin,
|
||||
isDev ? false : bundleAnalyzerPlugin,
|
||||
].filter(Boolean);
|
||||
|
||||
module.exports = {
|
||||
stats: {
|
||||
children: false,
|
||||
},
|
||||
// https://webpack.js.org/configuration/devtool/
|
||||
devtool: isDev ? 'eval-source-map' : 'source-map',
|
||||
entry: {
|
||||
app: { import: ['./src/app.tsx'], dependOn: 'libs' },
|
||||
libs: { import: ['react-query', 'react-modal'], dependOn: 'vendor' },
|
||||
vendor: { import: ['react', 'react-dom'], dependOn: 'corejs' },
|
||||
corejs: { import: 'core-js' },
|
||||
},
|
||||
context: __dirname,
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'public'),
|
||||
filename: isDev ? '[name].js' : '[name].[contenthash].js',
|
||||
publicPath,
|
||||
},
|
||||
mode: isDev ? 'development' : 'production',
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js'],
|
||||
alias: {
|
||||
src: path.resolve(__dirname, 'src'),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
// to work around "Module not found" issue for babel runtime imports
|
||||
// https://github.com/webpack/webpack/issues/11467
|
||||
{
|
||||
test: /\.m?js/,
|
||||
resolve: { fullySpecified: false },
|
||||
},
|
||||
{
|
||||
test: /\.[tj]sx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: { loader: 'babel-loader', options: { cacheDirectory: true } },
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|woff|woff2)(\?.+)?$/,
|
||||
use: [{ loader: 'file-loader', options: { name: '[name].[ext]' } }],
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
exclude: /\.module\.css$/,
|
||||
use: [
|
||||
isDev ? { loader: 'style-loader' } : MiniCssExtractPlugin.loader,
|
||||
{ loader: 'css-loader' },
|
||||
{ loader: 'postcss-loader', options: { postcssOptions } },
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.module\.css$/,
|
||||
use: [
|
||||
isDev ? { loader: 'style-loader' } : MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: isDev
|
||||
? '[path]_[name]_[local]_[hash:base64:5]'
|
||||
: '[hash:base64:10]',
|
||||
},
|
||||
},
|
||||
},
|
||||
{ loader: 'postcss-loader', options: { postcssOptions } },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
splitChunks: { chunks: 'all' },
|
||||
minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
|
||||
},
|
||||
plugins,
|
||||
bail: true,
|
||||
cache: {
|
||||
type: 'filesystem',
|
||||
buildDependencies: {
|
||||
config: [__filename],
|
||||
},
|
||||
},
|
||||
};
|
Loading…
Reference in a new issue