@shark-pepper/create-app 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ plugins: {
3
+ autoprefixer: {},
4
+ },
5
+ };
@@ -1,5 +1,20 @@
1
- import { Outlet } from 'react-router-dom';
1
+ import styles from '@/styles/App.module.scss';
2
2
 
3
3
  export default function App() {
4
- return <Outlet />;
4
+ return (
5
+ <div className={styles.app}>
6
+ <svg
7
+ width="112"
8
+ role="img"
9
+ viewBox="0 0 24 24"
10
+ fill="#087ea4"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ >
13
+ <title>React</title>
14
+ <path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z" />
15
+ </svg>
16
+ <p className={styles.thanks}>Thanks for using @shark-pepper/create-app</p>
17
+ <p className={styles.start}>Let's start coding!</p>
18
+ </div>
19
+ );
5
20
  }
@@ -2,12 +2,12 @@ import React from 'react';
2
2
  import { createRoot } from 'react-dom/client';
3
3
  import { BrowserRouter, useRoutes } from 'react-router-dom';
4
4
  import routes from './routes';
5
- import 'normalize.css';
6
5
 
7
6
  const AppRouter: React.FC = () => useRoutes(routes);
8
7
 
9
8
  const container = document.getElementById('root')!;
10
9
  const root = createRoot(container);
10
+
11
11
  root.render(
12
12
  <React.StrictMode>
13
13
  <BrowserRouter>
@@ -1,24 +1,11 @@
1
- import { Navigate, RouteObject } from 'react-router-dom';
2
- import ProtectedRoute from '@/components/ProtectedRoute';
3
- import Home from '@/pages/Home';
4
- import Login from '@/pages/Login';
5
- import App from '../App';
1
+ import { RouteObject } from 'react-router-dom';
2
+ import App from '@/App';
6
3
 
7
4
  const routes: RouteObject[] = [
8
5
  {
9
6
  path: '/',
10
- element: (
11
- <ProtectedRoute>
12
- <App />
13
- </ProtectedRoute>
14
- ),
15
- children: [
16
- { index: true, element: <Home /> },
17
- { path: 'home', element: <Navigate to="/" replace /> },
18
- { path: '*', element: <div>404 Not Found</div> },
19
- ],
7
+ element: <App />,
20
8
  },
21
- { path: 'login', element: <Login /> },
22
9
  ];
23
10
 
24
11
  export default routes;
@@ -0,0 +1,16 @@
1
+ .app {
2
+ height: 100vh;
3
+ display: flex;
4
+ flex-direction: column;
5
+ justify-content: center;
6
+ align-items: center;
7
+ }
8
+
9
+ .thanks {
10
+ font-size: 20px;
11
+ }
12
+
13
+ .start {
14
+ font-size: 20px;
15
+ margin-top: 0;
16
+ }
@@ -0,0 +1,53 @@
1
+ import path from 'path';
2
+
3
+ const __dirname = path.resolve();
4
+
5
+ export default {
6
+ entry: path.resolve(__dirname, './src/index.tsx'),
7
+ output: {
8
+ path: path.resolve(__dirname, './dist'),
9
+ publicPath: '/',
10
+ clean: true,
11
+ },
12
+ resolve: {
13
+ extensions: ['.ts', '.tsx', '.js', '.jsx'],
14
+ alias: {
15
+ '@': path.resolve(__dirname, './src'),
16
+ },
17
+ },
18
+ module: {
19
+ rules: [
20
+ {
21
+ test: /\.(png|jpe?g|gif|svg|webp)$/i,
22
+ type: 'asset',
23
+ parser: { dataUrlCondition: { maxSize: 10 * 1024 } },
24
+ generator: { filename: 'images/[name].[hash:8][ext]' },
25
+ },
26
+ {
27
+ test: /\.(woff2?|eot|ttf|otf)$/i,
28
+ type: 'asset/resource',
29
+ generator: { filename: 'fonts/[name].[hash:8][ext]' },
30
+ },
31
+ ],
32
+ },
33
+
34
+ optimization: {
35
+ splitChunks: {
36
+ chunks: 'all',
37
+ cacheGroups: {
38
+ reactVendor: {
39
+ test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
40
+ name: 'react-vendor',
41
+ chunks: 'all',
42
+ },
43
+ vendor: {
44
+ test: /[\\/]node_modules[\\/]/,
45
+ name: 'vendor',
46
+ chunks: 'all',
47
+ },
48
+ },
49
+ },
50
+ runtimeChunk: 'single',
51
+ moduleIds: 'deterministic',
52
+ },
53
+ };
@@ -0,0 +1,79 @@
1
+ import path from 'path';
2
+ import { merge } from 'webpack-merge';
3
+ import HtmlWebpackPlugin from 'html-webpack-plugin';
4
+ import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
5
+ import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
6
+ import common from './webpack.common.js';
7
+
8
+ const __dirname = path.resolve();
9
+
10
+ export default merge(common, {
11
+ mode: 'development',
12
+
13
+ output: {
14
+ filename: 'js/[name].js',
15
+ chunkFilename: 'js/[name].chunk.js',
16
+ },
17
+
18
+ module: {
19
+ rules: [
20
+ {
21
+ test: /\.tsx?$/,
22
+ use: [
23
+ {
24
+ loader: 'esbuild-loader',
25
+ options: { loader: 'tsx', target: 'es2017' },
26
+ },
27
+ ],
28
+ exclude: /node_modules/,
29
+ },
30
+ {
31
+ test: /\.module\.scss$/,
32
+ use: [
33
+ 'style-loader',
34
+ {
35
+ loader: 'css-loader',
36
+ options: {
37
+ modules: {
38
+ localIdentName: '[name]__[local]___[hash:base64:5]',
39
+ exportLocalsConvention: 'asIs',
40
+ },
41
+ esModule: false,
42
+ },
43
+ },
44
+ 'postcss-loader',
45
+ 'sass-loader',
46
+ ],
47
+ },
48
+ {
49
+ test: /\.scss$/,
50
+ use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
51
+ exclude: /\.module\.scss$/,
52
+ },
53
+ ],
54
+ },
55
+
56
+ plugins: [
57
+ new HtmlWebpackPlugin({
58
+ template: path.resolve(__dirname, './public/index.html'),
59
+ inject: 'body',
60
+ minify: false,
61
+ }),
62
+ new ReactRefreshWebpackPlugin(),
63
+ new ForkTsCheckerWebpackPlugin({
64
+ async: true,
65
+ typescript: { configFile: path.resolve(__dirname, './tsconfig.json') },
66
+ }),
67
+ ].filter(Boolean),
68
+
69
+ devtool: 'cheap-module-source-map',
70
+
71
+ devServer: {
72
+ static: path.resolve(__dirname, './public'),
73
+ compress: true,
74
+ port: 3000,
75
+ hot: true,
76
+ historyApiFallback: true,
77
+ open: true,
78
+ },
79
+ });
@@ -0,0 +1,82 @@
1
+ import path from 'path';
2
+ import { merge } from 'webpack-merge';
3
+ import HtmlWebpackPlugin from 'html-webpack-plugin';
4
+ import MiniCssExtractPlugin from 'mini-css-extract-plugin';
5
+ import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
6
+ import common from './webpack.common.js';
7
+
8
+ const __dirname = path.resolve();
9
+
10
+ export default merge(common, {
11
+ mode: 'production',
12
+
13
+ output: {
14
+ filename: 'js/[name].[contenthash:8].js',
15
+ chunkFilename: 'js/[name].[contenthash:8].chunk.js',
16
+ },
17
+
18
+ module: {
19
+ rules: [
20
+ {
21
+ test: /\.tsx?$/,
22
+ use: [
23
+ {
24
+ loader: 'babel-loader',
25
+ },
26
+ ],
27
+ exclude: /node_modules/,
28
+ },
29
+ {
30
+ test: /\.module\.scss$/,
31
+ use: [
32
+ MiniCssExtractPlugin.loader,
33
+ {
34
+ loader: 'css-loader',
35
+ options: {
36
+ modules: {
37
+ localIdentName: '[hash:base64:8]',
38
+ exportLocalsConvention: 'asIs',
39
+ },
40
+ esModule: false,
41
+ },
42
+ },
43
+ 'postcss-loader',
44
+ 'sass-loader',
45
+ ],
46
+ },
47
+ {
48
+ test: /\.scss$/,
49
+ use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'],
50
+ exclude: /\.module\.scss$/,
51
+ },
52
+ ],
53
+ },
54
+
55
+ plugins: [
56
+ new HtmlWebpackPlugin({
57
+ template: path.resolve(__dirname, './public/index.html'),
58
+ inject: true,
59
+ minify: {
60
+ removeComments: true,
61
+ collapseWhitespace: true,
62
+ removeRedundantAttributes: true,
63
+ useShortDoctype: true,
64
+ removeEmptyAttributes: true,
65
+ removeStyleLinkTypeAttributes: true,
66
+ keepClosingSlash: true,
67
+ minifyJS: true,
68
+ minifyCSS: true,
69
+ minifyURLs: true,
70
+ },
71
+ }),
72
+ new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' }),
73
+ new ForkTsCheckerWebpackPlugin({
74
+ async: false,
75
+ typescript: {
76
+ configFile: path.resolve(__dirname, './tsconfig.json'),
77
+ },
78
+ }),
79
+ ].filter(Boolean),
80
+
81
+ devtool: 'source-map',
82
+ });
@@ -1,108 +0,0 @@
1
- export default {
2
- root: true, // 表示 ESLint 配置在此目录为根,不向上查找
3
- env: {
4
- browser: true,
5
- es2022: true,
6
- },
7
- parser: "@typescript-eslint/parser", // 使用 TypeScript 解析器
8
- parserOptions: {
9
- ecmaVersion: 2022, // 支持最新 ECMAScript 语法
10
- sourceType: "module", // 支持 ES Modules
11
- ecmaFeatures: {
12
- jsx: true, // 支持 JSX
13
- },
14
- project: "./tsconfig.json", // 类型检查,启用 rules 依赖类型信息
15
- },
16
- plugins: [
17
- "@typescript-eslint",
18
- "react",
19
- "react-hooks",
20
- "import",
21
- "cspell", // 拼写检查
22
- ],
23
- extends: [
24
- "eslint:recommended", // ESLint 内置推荐规则
25
- "plugin:@typescript-eslint/recommended", // TypeScript 推荐规则
26
- "plugin:@typescript-eslint/recommended-requiring-type-checking", // 依赖类型信息的规则
27
- "plugin:react/recommended", // React 推荐规则
28
- "plugin:react-hooks/recommended", // React hooks 推荐规则
29
- "plugin:import/errors",
30
- "plugin:import/warnings",
31
- "plugin:import/typescript",
32
- "plugin:cspell/recommended", // 拼写检查规则
33
- "prettier", // 关闭与 Prettier 冲突的规则
34
- ],
35
- settings: {
36
- react: {
37
- version: "detect", // 自动检测 React 版本
38
- },
39
- "import/resolver": {
40
- typescript: {}, // 支持路径别名解析
41
- },
42
- cspell: {
43
- language: "en",
44
- skipWords: ["React", "TypeScript", "Webpack", "eslint", "pnpm"],
45
- ignorePaths: ["node_modules", "dist"],
46
- },
47
- },
48
- rules: {
49
- // ✅ TypeScript 相关
50
- "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], // 未使用变量允许 _ 前缀
51
- "@typescript-eslint/explicit-function-return-type": "off", // 不强制函数返回类型
52
- "@typescript-eslint/no-explicit-any": "warn", // 尽量避免 any
53
- "@typescript-eslint/strict-boolean-expressions": "warn", // 布尔表达式严格检查
54
-
55
- // ✅ React 相关
56
- "react/prop-types": "off", // TS 已经类型检查,不需要 prop-types
57
- "react/react-in-jsx-scope": "off", // React 17+ 不需要显式 import React
58
-
59
- // ✅ Hooks 相关
60
- "react-hooks/rules-of-hooks": "error", // Hooks 调用规则
61
- "react-hooks/exhaustive-deps": "warn", // effect 依赖检查
62
-
63
- // ✅ Import 相关
64
- "import/order": [
65
- "warn",
66
- {
67
- groups: [
68
- "builtin",
69
- "external",
70
- "internal",
71
- "parent",
72
- "sibling",
73
- "index",
74
- ],
75
- "newlines-between": "always",
76
- },
77
- ],
78
- "import/no-unresolved": "error",
79
- "import/no-cycle": ["error", { maxDepth: 1 }],
80
-
81
- // ✅ 拼写检查
82
- "cspell/spellchecker": [
83
- "warn",
84
- {
85
- words: [
86
- "frontend",
87
- "backend",
88
- "utils",
89
- "eslint",
90
- "webpack",
91
- "typescript",
92
- ],
93
- skipWords: ["React", "TSX", "JSX", "npm", "pnpm"],
94
- ignorePaths: ["node_modules", "dist", "build"],
95
- ignoreRegExpList: ["/^_/"], // 忽略下划线开头的标识符
96
- },
97
- ],
98
-
99
- // ✅ 其他风格
100
- "no-console": ["warn", { allow: ["warn", "error"] }], // 允许 warn/error
101
- "no-debugger": "warn",
102
- "prefer-const": "warn",
103
- "arrow-body-style": ["warn", "as-needed"],
104
- "no-param-reassign": "warn",
105
- "no-duplicate-imports": "warn",
106
- },
107
- ignorePatterns: ["node_modules/", "dist/", "build/", "*.config.js"],
108
- };
@@ -1,17 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import { Navigate, useLocation } from 'react-router-dom';
3
-
4
- interface ProtectedRouteProps {
5
- children: ReactNode;
6
- redirectPath?: string;
7
- }
8
-
9
- export default function ProtectedRoute({ children, redirectPath = '/login' }: ProtectedRouteProps) {
10
- const location = useLocation();
11
- const isAuth = localStorage.getItem('isAuth') === 'true';
12
-
13
- if (!isAuth) {
14
- return <Navigate to={redirectPath} state={{ from: location }} replace />;
15
- }
16
- return children;
17
- }
@@ -1,15 +0,0 @@
1
- import '../styles/Home.scss';
2
-
3
- export default function Home() {
4
- const handleClick = () => {
5
- localStorage.setItem('isAuth', 'false');
6
- window.location.reload();
7
- };
8
-
9
- return (
10
- <div className="home">
11
- <h1>Home Page</h1>
12
- <button onClick={handleClick}>Logout</button>
13
- </div>
14
- );
15
- }
@@ -1,29 +0,0 @@
1
- import { Navigate, useLocation, useNavigate } from 'react-router-dom';
2
- import '../styles/Login.scss';
3
-
4
- export default function Login() {
5
- const navigate = useNavigate();
6
- const location = useLocation();
7
-
8
- const from = (location.state as any)?.from?.pathname || '/';
9
- const isAuth = localStorage.getItem('isAuth') === 'true';
10
-
11
- if (isAuth) {
12
- return <Navigate to="/" replace />;
13
- }
14
-
15
- const handleLogin = () => {
16
- localStorage.setItem('isAuth', 'true');
17
- navigate(from, { replace: true });
18
- };
19
-
20
- return (
21
- <div className="container">
22
- <div className="welcome">
23
- <h1>Thanks for using @shark-pepper/create-app</h1>
24
- <h2>Let's start coding!</h2>
25
- </div>
26
- <button onClick={handleLogin}>Login Now</button>
27
- </div>
28
- );
29
- }
@@ -1,9 +0,0 @@
1
- .home {
2
- height: 100vh;
3
- display: flex;
4
- justify-self: center;
5
- align-items: center;
6
- button {
7
- margin-left: 36px;
8
- }
9
- }
@@ -1,16 +0,0 @@
1
- @mixin flex-center($direction: row) {
2
- display: flex;
3
- flex-direction: $direction;
4
- justify-content: center;
5
- align-items: center;
6
- }
7
-
8
- .container {
9
- height: 100vh;
10
- @include flex-center(column);
11
- .welcome {
12
- width: 750px;
13
- margin-bottom: 40px;
14
- @include flex-center(column);
15
- }
16
- }
@@ -1,123 +0,0 @@
1
- import path from 'path';
2
- import HtmlWebpackPlugin from 'html-webpack-plugin';
3
- import MiniCssExtractPlugin from 'mini-css-extract-plugin';
4
- import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
5
- import ESLintPlugin from 'eslint-webpack-plugin';
6
-
7
- const __dirname = path.resolve(); // ESModule 下获取 __dirname
8
-
9
- const isProd = process.env.NODE_ENV === 'production';
10
-
11
- export default {
12
- mode: isProd ? 'production' : 'development',
13
-
14
- entry: path.resolve(__dirname, 'src/index.tsx'),
15
-
16
- output: {
17
- path: path.resolve(__dirname, 'dist'),
18
- filename: isProd ? 'js/[name].[contenthash:8].js' : 'js/[name].js',
19
- chunkFilename: isProd ? 'js/[name].[contenthash:8].chunk.js' : 'js/[name].chunk.js',
20
- publicPath: '/',
21
- clean: true, // 自动清理 dist 目录
22
- },
23
-
24
- resolve: {
25
- extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
26
- alias: {
27
- '@': path.resolve(__dirname, 'src'),
28
- },
29
- },
30
-
31
- module: {
32
- rules: [
33
- // TS / TSX
34
- {
35
- test: /\.tsx?$/,
36
- use: [
37
- {
38
- loader: 'ts-loader',
39
- options: { transpileOnly: true }, // 类型检查交给 ForkTsCheckerWebpackPlugin
40
- },
41
- ],
42
- exclude: /node_modules/,
43
- },
44
-
45
- // CSS / SCSS
46
- {
47
- test: /\.css$/i,
48
- use: [
49
- isProd ? MiniCssExtractPlugin.loader : 'style-loader',
50
- 'css-loader',
51
- 'postcss-loader',
52
- ],
53
- },
54
- {
55
- test: /\.s[ac]ss$/i,
56
- use: [
57
- isProd ? MiniCssExtractPlugin.loader : 'style-loader',
58
- 'css-loader',
59
- 'postcss-loader',
60
- 'sass-loader',
61
- ],
62
- },
63
-
64
- // 静态资源(图片 / 字体)
65
- {
66
- test: /\.(png|jpe?g|gif|svg|webp)$/i,
67
- type: 'asset',
68
- parser: { dataUrlCondition: { maxSize: 10 * 1024 } },
69
- generator: { filename: 'images/[name].[hash:8][ext]' },
70
- },
71
- {
72
- test: /\.(woff2?|eot|ttf|otf)$/i,
73
- type: 'asset/resource',
74
- generator: { filename: 'fonts/[name].[hash:8][ext]' },
75
- },
76
- ],
77
- },
78
-
79
- plugins: [
80
- new HtmlWebpackPlugin({
81
- template: path.resolve(__dirname, 'public/index.html'),
82
- inject: 'body',
83
- minify: isProd ? { removeComments: true, collapseWhitespace: true } : false,
84
- }),
85
- isProd && new MiniCssExtractPlugin({ filename: 'css/[name].[contenthash:8].css' }),
86
- new ForkTsCheckerWebpackPlugin({
87
- async: !isProd,
88
- typescript: { configFile: path.resolve(__dirname, 'tsconfig.json') },
89
- }),
90
- new ESLintPlugin({ extensions: ['ts', 'tsx', 'js', 'jsx'], fix: true, emitWarning: !isProd }),
91
- ].filter(Boolean),
92
-
93
- devtool: isProd ? 'source-map' : 'eval-cheap-module-source-map',
94
-
95
- devServer: {
96
- static: path.resolve(__dirname, 'public'),
97
- compress: true,
98
- port: 3000,
99
- hot: true,
100
- historyApiFallback: true,
101
- open: true,
102
- },
103
-
104
- optimization: {
105
- splitChunks: {
106
- chunks: 'all',
107
- cacheGroups: {
108
- reactVendor: {
109
- test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
110
- name: 'react-vendor',
111
- chunks: 'all',
112
- },
113
- vendor: {
114
- test: /[\\/]node_modules[\\/]/,
115
- name: 'vendor',
116
- chunks: 'all',
117
- },
118
- },
119
- },
120
- runtimeChunk: 'single',
121
- moduleIds: 'deterministic',
122
- },
123
- };