Просмотр исходного кода

添加项目结构和初始文件

新增多个图片、HTML页面、配置文件及脚本,初始化项目结构。包括创建了首页、赞助商列表页以及相关的样式和脚本文件,同时配置了.gitignore、package.json等项目管理文件。
SongZihuan 3 месяцев назад
Сommit
e312e071f3

+ 30 - 0
.eslintignore

@@ -0,0 +1,30 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+dist-*
+dist-development
+dist-production
+dist-dev
+dist-prod
+docs
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 128 - 0
.eslintrc.cjs

@@ -0,0 +1,128 @@
+/*!
+ * https://eslint.bootcss.com/docs/rules/
+ * https://eslint.vuejs.org/rules/
+ */
+
+module.exports = {
+  root: true,
+  env: {
+    browser: true,
+    node: true,
+    es6: true
+  },
+  parserOptions: {
+    ecmaVersion: 11,
+    sourceType: 'module'
+  },
+  extends: ['prettier', 'eslint:recommended', 'plugin:prettier/recommended'],
+  plugins: ['prettier'],
+  rules: {
+    'no-undef': 'off',
+    'prettier/prettier': 'warn',
+    'no-unused-vars': 'warn',
+    // 禁用debugger
+    'no-debugger': 'warn',
+    // 禁止出现重复的 case 标签
+    'no-duplicate-case': 'warn',
+    // 禁止出现空语句块
+    // 'no-empty': 'warn',
+    // 禁止不必要的括号
+    'no-extra-parens': 'off',
+    // 禁止对 function 声明重新赋值
+    'no-func-assign': 'warn',
+    // 禁止在 return、throw、continue 和 break 语句之后出现不可达代码
+    'no-unreachable': 'warn',
+    // 强制所有控制语句使用一致的括号风格
+    curly: 'warn',
+    // 要求 switch 语句中有 default 分支
+    'default-case': 'warn',
+    // 强制尽可能地使用点号
+    'dot-notation': 'warn',
+    // 要求使用 === 和 !==
+    // eqeqeq: 'warn',
+    // 禁止 if 语句中 return 语句之后有 else 块
+    'no-else-return': 'warn',
+    // 禁止出现空函数
+    // 'no-empty-function': 'warn',
+    // 禁用不必要的嵌套块
+    'no-lone-blocks': 'warn',
+    // 禁止使用多个空格
+    'no-multi-spaces': 'warn',
+    // 禁止多次声明同一变量
+    'no-redeclare': 'warn',
+    // 禁止在 return 语句中使用赋值语句
+    'no-return-assign': 'warn',
+    // 禁用不必要的 return await
+    'no-return-await': 'warn',
+    // 禁止自我赋值
+    'no-self-assign': 'warn',
+    // 禁止自身比较
+    'no-self-compare': 'warn',
+    // 禁止不必要的 catch 子句
+    'no-useless-catch': 'warn',
+    // 禁止多余的 return 语句
+    'no-useless-return': 'warn',
+    // 禁止变量声明与外层作用域的变量同名
+    'no-shadow': 'off',
+    // 允许delete变量
+    'no-delete-var': 'off',
+    // 强制数组方括号中使用一致的空格
+    'array-bracket-spacing': 'warn',
+    // 强制在代码块中使用一致的大括号风格
+    'brace-style': 'warn',
+    // 强制使用骆驼拼写法命名约定
+    // camelcase: 'warn',
+    // 强制使用一致的缩进
+    indent: 'off',
+    // 强制在 JSX 属性中一致地使用双引号或单引号
+    // 'jsx-quotes': 'warn',
+    // 强制可嵌套的块的最大深度4
+    'max-depth': 'warn',
+    // 强制最大行数 300
+    // "max-lines": ["warn", { "max": 1200 }],
+    // 强制函数最大代码行数 50
+    // 'max-lines-per-function': ['warn', { max: 70 }],
+    // 强制函数块最多允许的的语句数量20
+    'max-statements': ['warn', 100],
+    // 强制回调函数最大嵌套深度
+    'max-nested-callbacks': ['warn', 5],
+    // 强制每一行中所允许的最大语句数量
+    'max-statements-per-line': ['warn', { max: 1 }],
+    // 要求方法链中每个调用都有一个换行符
+    'newline-per-chained-call': ['warn', { ignoreChainWithDepth: 3 }],
+    // 禁止 if 作为唯一的语句出现在 else 语句中
+    'no-lonely-if': 'warn',
+    // 禁止空格和 tab 的混合缩进
+    'no-mixed-spaces-and-tabs': 'warn',
+    // 禁止出现多行空行
+    'no-multiple-empty-lines': 'warn',
+    // 禁止出现;
+    semi: ['warn', 'never'],
+    // 强制在块之前使用一致的空格
+    'space-before-blocks': 'warn',
+    // 强制在 function的左括号之前使用一致的空格
+    // 'space-before-function-paren': ['warn', 'never'],
+    // 强制在圆括号内使用一致的空格
+    'space-in-parens': 'warn',
+    // 要求操作符周围有空格
+    'space-infix-ops': 'warn',
+    // 强制在一元操作符前后使用一致的空格
+    'space-unary-ops': 'warn',
+    // 强制在注释中 // 或 /* 使用一致的空格
+    // "spaced-comment": "warn",
+    // 强制在 switch 的冒号左右有空格
+    'switch-colon-spacing': 'warn',
+    // 强制箭头函数的箭头前后使用一致的空格
+    'arrow-spacing': 'warn',
+    'no-var': 'warn',
+    'prefer-const': 'warn',
+    'prefer-rest-params': 'warn',
+    'no-useless-escape': 'warn',
+    'no-irregular-whitespace': 'warn',
+    'no-prototype-builtins': 'warn',
+    'no-fallthrough': 'warn',
+    'no-extra-boolean-cast': 'warn',
+    'no-case-declarations': 'warn',
+    'no-async-promise-executor': 'warn'
+  }
+}

+ 36 - 0
.gitignore

@@ -0,0 +1,36 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+dist-*
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+*.bak
+.npmrc
+
+tsconfig.json
+vite.config.ts.timestamp-*
+
+pnpm-lock.yaml
+package-lock.json
+yarn.lock
+
+huan-*.tgz

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 13 - 0
.idea/ContributionsndSponsorships.iml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.tmp" />
+      <excludeFolder url="file://$MODULE_DIR$/dist-dev" />
+      <excludeFolder url="file://$MODULE_DIR$/temp" />
+      <excludeFolder url="file://$MODULE_DIR$/tmp" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 14 - 0
.idea/deployment.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
+    <serverData>
+      <paths name="bt.song-zh.com">
+        <serverdata>
+          <mappings>
+            <mapping local="$PROJECT_DIR$" web="/" />
+          </mappings>
+        </serverdata>
+      </paths>
+    </serverData>
+  </component>
+</project>

+ 6 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="GoNameStartsWithPackageName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
+  </profile>
+</component>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/ContributionsndSponsorships.iml" filepath="$PROJECT_DIR$/.idea/ContributionsndSponsorships.iml" />
+    </modules>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 70 - 0
.npmignore

@@ -0,0 +1,70 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+# Node
+node_modules
+.npmrc
+pnpm-lock.yaml
+package-lock.json
+yarn.lock
+
+# Pack
+huan-*.tgz
+
+# Build
+dist
+dist-*
+dist-ssr
+dist-dev
+dist-prod
+
+# Git
+.git
+.gitignore
+
+# Github
+github-page
+docs
+.github
+
+# Local
+*.local
+
+# Hidden
+.*
+!.prettierrc.cjs
+!.npmignore
+!.eslintignore
+!.eslintrc.cjs
+!public/.__ignore__
+
+# IDE
+.vscode
+.idea
+
+# System
+.DS_Store
+desktop.ini
+thumbs.db
+iconcache.db
+IconCache.db
+ntuser.dat
+ntuser.dat.log
+hiberfil.sys
+pagefile.sys
+$Recycle.Bin
+Recycle Bin
+
+# Other
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+*.bak

+ 14 - 0
.prettierrc.cjs

@@ -0,0 +1,14 @@
+module.exports = {
+    printWidth: 120, // 换行字符串阈值
+    tabWidth: 2, // 设置工具每一个水平缩进的空格数
+    useTabs: false,
+    semi: false, // 句末是否加分号
+    vueIndentScriptAndStyle: true,
+    singleQuote: true, // 用单引号
+    trailingComma: 'none', // 最后一个对象元素符加逗号
+    bracketSpacing: true,
+    jsxBracketSameLine: true, // jsx > 是否另取一行
+    arrowParens: 'always', // 不需要写文件开头的 @prettier
+    insertPragma: false, // 不需要自动在文件开头加入 @prettier
+    endOfLine: 'lf' // 换行符使用
+}

+ 8 - 0
LICENSE

@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright (c) 2025 宋子桓(Song Zihuan)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 20 - 0
README.md

@@ -0,0 +1,20 @@
+# 宋子桓(Song Zihuan)代码项目贡献者和赞助者主页。
+
+这是一个非常简单的多入口点(MPA Multiple Page Application)项目,我使用了静态的HTML+CSS+JS进行编码。
+
+## 作者信息
+作者:宋子桓(Song Zihuan)
+
+作者 Github:[github.com/SongZihuan](https://github.com/SongZihuan)
+
+作者主页:[song-zh.com](https://song-zh.com)
+
+作者邮箱:[songzihuan@song-zh.com](mailto://songzihuan@song-zh.com)
+
+## 项目信息
+项目托管地址:[github.com/Cr-Huan/contributions-and-sponsorships](https://github.com/Cr-Huan/contributions-and-sponsorships)
+
+最后更新时间:2025年1月27日。
+
+## 特别注意
+备注:以上README为作者原文。

+ 15 - 0
REEPORT

@@ -0,0 +1,15 @@
+如何报告 Contributions And Sponsorships
+
+作者:宋子桓(Song Zihuan)
+作者 Github:https://github.com/SongZihuan
+作者主页:https://song-zh.com
+作者邮箱:songzihuan@song-zh.com
+
+Github:https://github.com/SongZihuan/contributions-and-sponsorships
+Github Issues:https://github.com/SongZihuan/contributions-and-sponsorships/issues
+
+报告:您可以通过 Github Issues 或作者邮箱报告问题并联系作者。
+质量保证:如果您仅拥有此项目根目录下的 LICENSE 文件中的许可证,您将无法获得任何质量保证。但作者很乐意为您解决问题,除非此项目已存档为只读。
+其他 Fork 版本:请联系 Fork 版本的作者寻求帮助。
+
+备注:以上REPORT为作者原文。

+ 36 - 0
babel_config.js

@@ -0,0 +1,36 @@
+const config = {
+  presets: [
+    [
+      '@babel/preset-env', // 使用 @babel/preset-env 转换语法
+      {
+        // 目标环境配置,根据需要调整
+        targets: {
+          browsers: [
+            // 你可以指定具体的浏览器版本,例如:
+            // "last 2 versions",
+            // ">= 1%",
+            // "Chrome >= 49",
+            // "Firefox >= 45",
+            // 或使用 "defaults" 自动选择一组常见的浏览器版本
+            'defaults'
+          ]
+        },
+        // 启用或禁用模块转换
+        modules: false, // 或 "auto" / "commonjs"
+
+        // 可选:按需加载 polyfills
+        useBuiltIns: 'usage', // 根据代码实际使用情况自动引入 polyfills
+        corejs: 3 // 如果使用按需加载,需要指定 core-js 的版本
+
+        // 可选:包含或排除特定的 transforms
+        // exclude: ['transform-regenerator'], // 例如,排除 regenerator 转换
+        // include: ['@babel/plugin-proposal-class-properties'], // 或者包含额外的提案特性
+      }
+    ]
+  ],
+
+  // 可选:包含全局的 Babel 插件
+  plugins: []
+}
+
+export default config

+ 5 - 0
config.json

@@ -0,0 +1,5 @@
+{
+  "ICP": "粤ICP备2022108417号",
+  "WANGAN": "粤公网安备44011402000783号",
+  "注释:": "若您要运行此网站,并公开发布,请根据当地法律进行ICP备案和网安备案。"
+}

+ 56 - 0
package.json

@@ -0,0 +1,56 @@
+{
+  "name": "contributions-and-sponsorships",
+  "version": "1.0.0",
+  "description": "宋子桓项目的支持者和贡献者项目名单",
+  "repository": "https://github.com/SongZihuan/contributions-and-sponsorships",
+  "bug": "https://github.com/SongZihuan/contributions-and-sponsorships/issues",
+  "homepage": "https://github.com/SongZihuan/contributions-and-sponsorships",
+  "module": "./src/index.js",
+  "type": "module",
+  "private": true,
+  "engines": {
+    "node": ">=18",
+    "pnpm": ">=8"
+  },
+  "scripts": {
+    "init": "npx pnpm install",
+    "lint": "eslint --ext .js,.mjs,.cjs --fix .",
+    "lint:debug": "eslint --ext .js,.mjs,.cjs --debug --fix .",
+    "dev": "npx webpack server --config webpack_config_dev.js",
+    "build:dev": "npx webpack --config webpack_config_dev.js",
+    "build:dev:run": "npx pnpm build:dev && npx pnpm dev",
+    "prod": "npx webpack server --config webpack_config_prod.js",
+    "build:prod": "npx webpack --config webpack_config_prod.js",
+    "build:prod:run": "npx pnpm build:prod && npx pnpm prod",
+    "github": "npx webpack server --config webpack_config_github.js",
+    "build:github": "npx webpack --config webpack_config_github.js && node github-page/cname.js"
+  },
+  "devDependencies": {
+    "@babel/core": "^7.26.0",
+    "@babel/preset-env": "^7.26.0",
+    "babel-loader": "^9.2.1",
+    "copy-webpack-plugin": "^12.0.2",
+    "core-js": "3",
+    "css-loader": "^7.1.2",
+    "eslint": "^8.38.0",
+    "eslint-config-prettier": "^8.8.0",
+    "eslint-plugin-prettier": "^4.2.1",
+    "extract-loader": "^5.1.0",
+    "file-loader": "^6.2.0",
+    "html-loader": "^5.1.0",
+    "html-webpack-plugin": "^5.6.3",
+    "jquery": "^3.7.1",
+    "mini-css-extract-plugin": "^2.9.2",
+    "normalize.css": "^8.0.1",
+    "postcss": "^8.5.1",
+    "postcss-loader": "^8.1.1",
+    "prettier": "^2.8.7",
+    "sass": "^1.83.4",
+    "sass-loader": "^16.0.4",
+    "terser-webpack-plugin": "^5.3.11",
+    "url-loader": "^4.1.1",
+    "webpack": "^5.97.1",
+    "webpack-cli": "^6.0.1",
+    "webpack-dev-server": "^5.2.0"
+  }
+}

+ 1 - 0
public/.__ignore__

@@ -0,0 +1 @@
+Placeholder file, meaningless.

+ 1 - 0
public/CNAME

@@ -0,0 +1 @@
+cas.song-zh.com

+ 26 - 0
public/sponsors.json

@@ -0,0 +1,26 @@
+{
+  "data": [
+    {
+      "type": "个人",
+      "name": "宋子桓",
+      "email": "songzihuan@song-zh.com",
+      "phone": "-",
+      "website": "https://song-zh.com",
+      "sponsorDate": "2025/1/7",
+      "amount": "¥5.00",
+      "totalAmount": "¥10.00",
+      "remark": ""
+    },
+    {
+      "type": "个人",
+      "name": "宋子桓",
+      "email": "songzihuan@song-zh.com",
+      "phone": "-",
+      "website": "https://song-zh.com",
+      "sponsorDate": "2025/1/7",
+      "amount": "¥5.00",
+      "totalAmount": "¥5.00",
+      "remark": ""
+    }
+  ]
+}

BIN
src/assets/image/logo.png


BIN
src/assets/image/logo_big.png


BIN
src/assets/image/songzihuan.jpg


BIN
src/assets/image/touxiang.png


BIN
src/assets/image/wangan.png


+ 31 - 0
src/common.js

@@ -0,0 +1,31 @@
+// 清理状态
+import 'normalize.css'
+import "./style/body.css"
+import './style/a.css'
+import './style/button.css'
+import './utils.js'
+
+import jQuery from 'jquery'
+
+import Logo from './assets/image/logo.png'
+import WangAn from './assets/image/wangan.png'
+import SongZihuan from './assets/image/songzihuan.jpg'
+import LogoBin from './assets/image/logo_big.png'
+
+window.Logo = Logo
+window.WangAn = WangAn
+window.SongZihuan = SongZihuan
+window.LogoBig = LogoBin
+
+window.jQuery = jQuery
+window.$ = jQuery
+
+function setIcon() {
+  // 动态设置favicon
+  const link = document.createElement('link')
+  link.rel = 'shortcut icon'
+  link.href = Logo // 或者 favicon.png 对于PNG格式
+  document.head.appendChild(link)
+}
+
+document.addEventListener('DOMContentLoaded', setIcon)

+ 29 - 0
src/html/index.html

@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="zh">
+<head>
+    <meta charset="UTF-8">
+    <title>宋子桓的项目贡献与赞助主页</title>
+</head>
+<body>
+<header>
+    <h1>宋子桓(Song Zihuan)的项目贡献与赞助平台</h1>
+</header>
+<main>
+    <p>欢迎来到我的项目贡献者与赞助商记录网站。这里,我衷心感谢所有为我的项目做出贡献的朋友和支持我的赞助商。</p>
+    <p>目前,我们的赞助主要通过 <a href="https://afdian.com/a/SongZihuan" target="_blank">爱发电</a>
+        进行。如果您愿意支持我的工作,非常欢迎您加入赞助行列。</p>
+    <p>我的项目通常采用 <a href="https://mit-license.song-zh.com" target="_blank">MIT开源协议</a>,鼓励共享与创新。</p>
+    <div class="buttons">
+        <a href="sponsors.html" class="button">赞助商页面</a>
+        <a href="contributors.html" class="button">贡献者页面</a>
+    </div>
+</main>
+<footer>
+    <div id="copyright-container"></div>
+    <div id="tcp-container"></div>
+    <div id="wangan-container"></div>
+</footer>
+<script src="../js/copyright.js"></script>
+<script src="../js/beian.js"></script>
+</body>
+</html>

+ 47 - 0
src/html/sponsors.html

@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html lang="zh">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>赞助商列表</title>
+
+    <style>
+        /* Main content styles */
+        main {
+            width: 95%;
+            margin: 3rem auto;
+            padding: 2rem;
+            background-color: #fff;
+            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+        }
+    </style>
+</head>
+<body>
+
+<header>
+    <h1>赞助商列表</h1>
+</header>
+
+<main>
+    <table id="sponsor-table">
+        <thead>
+        <tr>
+            <th>Logo</th>
+            <th>类型</th>
+            <th>名称</th>
+            <th>邮箱</th>
+            <th>联系电话</th>
+            <th>联系网站</th>
+            <th>赞助时间</th>
+            <th>赞助金额</th>
+            <th>累计赞助金额</th>
+            <th>备注</th>
+        </tr>
+        </thead>
+        <tbody>
+        </tbody>
+    </table>
+</main>
+<script src="../js/sponsors.js"></script>
+</body>
+</html>

+ 2 - 0
src/index.js

@@ -0,0 +1,2 @@
+import "./style/header.css"
+import "./style/index.css"

+ 54 - 0
src/js/beian.js

@@ -0,0 +1,54 @@
+fetch("/CONFIG.json")
+    .then(response => {
+        if (!response.ok) {
+            throw new Error('Network response was not ok');
+        }
+
+        return response.text().then(text => {
+            const data = JSON.parse(text);
+            if (typeof data !== "object" || data === null) {
+                throw new Error('Config data error');
+            }
+            return data
+        })
+    })
+    .then(CONFIG => {
+        if (CONFIG && CONFIG.ICP) {
+            const container = document.getElementById('tcp-container');
+            if (container !== null) {
+                const p = document.createElement('p');
+                const a = document.createElement('a');
+                a.href = "https://beian.miit.gov.cn/";
+                a.target = "_blank"
+                a.textContent = CONFIG.ICP;
+                p.appendChild(a);
+                container.appendChild(p);
+            }
+        }
+
+        if (window.WangAn && CONFIG && CONFIG.WANGAN) {
+            const container = document.getElementById('wangan-container');
+            if (container !== null) {
+                const p = document.createElement('p');
+                const img = document.createElement('img');
+                const a = document.createElement('a');
+
+                img.alt = "网络安全图标"
+                img.src = window.WangAn;
+                img.style = "vertical-align: middle"
+
+                CONFIG.WANGAN_NUM = window.utils.stringTool.extractNumbersFromString(CONFIG.WANGAN)
+
+                a.href = `https://www.beian.gov.cn/portal/registerSystemInfo?recordcode=${CONFIG.WANGAN_NUM}`;
+                a.target = "_blank";
+                a.textContent = CONFIG.WANGAN;
+
+                p.appendChild(img)
+                p.appendChild(a);
+                container.appendChild(p);
+            }
+        }
+    })
+    .catch(error => {
+        console.error('There has been a problem with your fetch operation:', error);
+    });

+ 10 - 0
src/js/copyright.js

@@ -0,0 +1,10 @@
+const currentYear = new Date().getFullYear();
+const copyrightTemplate = `<p>&copy; ${currentYear} 宋子桓(Song Zihuan). All rights reserved.</p>`;
+
+const containerElement = document.getElementById('copyright-container');
+// 将生成的版权信息插入到页面指定位置
+if (containerElement) {
+    containerElement.innerHTML = copyrightTemplate;
+}
+
+console.log("containerElement", containerElement)

+ 34 - 0
src/js/sponsors.js

@@ -0,0 +1,34 @@
+async function fetchSponsors() {
+    try {
+        const response = await fetch('/sponsors.json');
+        if (!response.ok) {
+            throw new Error('网络错误');
+        }
+        const sponsorsData = await response.json();
+        populateTable(sponsorsData);
+    } catch (error) {
+        console.error('获取赞助商数据时出错:', error);
+    }
+}
+
+function populateTable(sponsors) {
+    const tableBody = document.querySelector('#sponsor-table tbody');
+    sponsors.data.forEach(sponsor => {
+        const row = document.createElement('tr');
+        row.innerHTML = `
+                <td><img class="logo" src="${sponsor.logo || window.defaultLogo}" alt="Logo"></td>
+                <td>${sponsor.type || "匿名"}</td>
+                <td>${sponsor.name || "匿名"}</td>
+                <td>${sponsor.email || "-"}</td>
+                <td>${sponsor.phone || "-"}</td>
+                <td><a href="${sponsor.website}" target="_blank">访问网站</a></td>
+                <td>${sponsor.sponsorDate}</td>
+                <td>¥${sponsor.amount}</td>
+                <td>¥${sponsor.totalAmount}</td>
+                <td>${sponsor.remark}</td>`;
+        tableBody.appendChild(row);
+    });
+}
+
+// 页面加载完成后执行
+document.addEventListener('DOMContentLoaded', fetchSponsors);

+ 5 - 0
src/sponsors.js

@@ -0,0 +1,5 @@
+import "./style/header.css"
+import "./style/sponsors.css"
+import defaultLogo from "./assets/image/touxiang.png"
+
+window.defaultLogo = defaultLogo

+ 9 - 0
src/style/a.css

@@ -0,0 +1,9 @@
+/* Link styles */
+a {
+    color: #007BFF;
+    text-decoration: none;
+}
+
+a:hover {
+    text-decoration: underline;
+}

+ 13 - 0
src/style/body.css

@@ -0,0 +1,13 @@
+/*Reset some default browser styles*/
+body, h1, p {
+    margin: 0;
+    padding: 0;
+}
+
+/* Basic styling for the whole document */
+body {
+    font-family: Arial, sans-serif;
+    line-height: 1.6;
+    color: #333;
+    background-color: #f4f4f4;
+}

+ 17 - 0
src/style/button.css

@@ -0,0 +1,17 @@
+/* Button styles */
+.button {
+    display: inline-block;
+    padding: 0.8rem 1.6rem;
+    font-size: 1rem;
+    background-color: #007BFF;
+    color: white;
+    border: none;
+    cursor: pointer;
+    text-decoration: none;
+    border-radius: 4px;
+    transition: background-color 0.3s ease;
+}
+
+.button:hover {
+    background-color: #0056b3;
+}

+ 11 - 0
src/style/header.css

@@ -0,0 +1,11 @@
+/* Header styles */
+header {
+    background-color: #333;
+    color: white;
+    text-align: center;
+    padding: 1rem;
+}
+
+header h1 {
+    margin-bottom: 0;
+}

+ 24 - 0
src/style/index.css

@@ -0,0 +1,24 @@
+/* Main content styles */
+main {
+    max-width: 800px;
+    margin: 3rem auto;
+    padding: 2rem;
+    background-color: #fff;
+    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
+}
+
+p {
+    margin-bottom: 1rem;
+}
+
+/*Footer styles */
+footer {
+    background-color: #333;
+    color: white;
+    width: 100%;
+    text-align: center;
+    padding-top: 1rem;
+    padding-bottom: 1rem;
+    position: absolute;
+    bottom: 0;
+}

+ 26 - 0
src/style/sponsors.css

@@ -0,0 +1,26 @@
+table {
+    width: 100%;
+    border-collapse: collapse;
+}
+
+th, td {
+    border: 1px solid #ccc;
+    padding: 8px;
+    text-align: left;
+}
+
+th {
+    background-color: #f2f2f2;
+    font-weight: bold;
+}
+
+tr td {
+    text-align: center;
+}
+
+img.logo {
+    max-width: 80px;
+    max-height: 80px;
+    width: auto;
+    height: auto;
+}

+ 8 - 0
src/utils.js

@@ -0,0 +1,8 @@
+import stringTool from "./utils/string.js"
+
+const utils = {
+    stringTool,
+}
+
+window.utils = utils
+export default utils

+ 19 - 0
src/utils/string.js

@@ -0,0 +1,19 @@
+export function extractNumbersFromString(str) {
+    // 正则表达式匹配非数字字符后紧跟数字,然后是更多非数字字符
+    const regex = /[^0-9]+(\d+)[^0-9]+/g
+    let matches = ""
+    let match = null
+
+    // 使用正则表达式的全局搜索来查找所有匹配项
+    while ((match = regex.exec(str)) !== null) {
+        // 提取数字部分并添加到结果数组
+        matches += match[1].toString()
+    }
+    return matches
+}
+
+
+const stringTool = {
+    extractNumbersFromString
+}
+export default stringTool

+ 145 - 0
webpack_config_dev.js

@@ -0,0 +1,145 @@
+import path from 'path'
+import HtmlWebpackPlugin from 'html-webpack-plugin'
+import MiniCssExtractPlugin from 'mini-css-extract-plugin'
+import CopyWebpackPlugin from 'copy-webpack-plugin'
+import { fileURLToPath } from 'url'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+
+const mode = 'development'
+const dist_name = 'dist-dev'
+
+const config = {
+  mode: mode,
+
+  context: __dirname,
+
+  performance: {
+    hints: 'warning', // 或者 'error',取决于你希望如何处理超出限制的情况
+    maxAssetSize: 5000000, // 设置单个资源的最大尺寸,例如5MB
+    maxEntrypointSize: 10000000 // 设置入口起点的最大尺寸,例如10MB
+  },
+
+  entry: {
+    common: path.resolve(__dirname, 'src/common.js'),
+    index: path.resolve(__dirname, 'src/index.js'),
+    sponsors: path.resolve(__dirname, 'src/sponsors.js'),
+  },
+
+  output: {
+    path: path.resolve(__dirname, dist_name), //打包后的文件存放的地方
+    filename: 'js/[name].[fullhash].bundle.js', //打包后输出文件的文件名
+    chunkFilename: '[name].bundle.js',
+    clean: true,
+    charset: true,
+    publicPath: '/'
+  },
+
+  resolve: {
+    alias: {
+      '@': path.join(__dirname, 'src')
+    }
+  },
+
+  module: {
+    rules: [
+      {
+        test: /\.(js|mjs|cjs)$/,
+        exclude: /(node_modules|bower_components)/,
+        use: {
+          loader: 'babel-loader'
+        }
+      },
+      {
+        test: /\.(css|scss|sass)$/,
+        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
+      },
+      {
+        test: /\.(png|jpg|jpeg|svg|gif)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'images', // 类似于 file-loader 的配置
+              name: '[name].[hash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.(mp4|m4v|avi|mov|qt|wmv|mkv|flv|webm|mpeg|mpg|3gp|3g2)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'videos', // 类似于 file-loader 的配置
+              name: '[name].[hash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.(woff|woff2|eot|ttf|otf)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'fonts', // 类似于 file-loader 的配置
+              name: '[name].[hash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.html$/i,
+        loader: 'html-loader'
+      }
+    ]
+  },
+
+  plugins: [
+    new CopyWebpackPlugin({
+      patterns: [
+        { from: 'public', to: './' },
+        { from: './config.json', to: './CONFIG.json' },
+      ]
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/index.html'), //指定模板文件
+      filename: 'index.html',
+      chunks: ['common', 'index'],
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/sponsors.html'), //指定模板文件
+      filename: 'sponsors.html',
+      chunks: ['common', 'sponsors'],
+      publicPath: './'
+    }),
+    new MiniCssExtractPlugin({
+      filename: 'style/[name].[fullhash].bundle.css',
+      chunkFilename: 'css/[id].bundle.css'
+    })
+  ],
+
+  devServer: {
+    static: {
+      directory: path.join(__dirname, dist_name)
+    },
+    compress: true,
+    port: 1001,
+    open: true,
+    hot: true
+  }
+}
+
+export default config

+ 304 - 0
webpack_config_github.js

@@ -0,0 +1,304 @@
+import path from 'path'
+import HtmlWebpackPlugin from 'html-webpack-plugin'
+import MiniCssExtractPlugin from 'mini-css-extract-plugin'
+import CopyWebpackPlugin from 'copy-webpack-plugin'
+import TerserPlugin from 'terser-webpack-plugin'
+import filetool from 'huan-file-tool'
+import { fileURLToPath } from 'url'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+
+const mode = 'production'
+const dist_name = 'docs'
+
+const html_minify = {
+  collapseWhitespace: true,
+  removeComments: true,
+  removeRedundantAttributes: true,
+  useShortDoctype: true,
+  removeEmptyAttributes: true,
+  removeStyleLinkTypeAttributes: true,
+  keepClosingSlash: true,
+  minifyJS: true,
+  minifyCSS: true,
+  minifyURLs: true
+}
+
+const HTMMLPlugin = []
+
+const { localPathResult: AllHTMLLocalFile4xx } = filetool.filewaalk.getAllFilePaths(
+  path.resolve(__dirname, 'src/html/error/4xx')
+)
+AllHTMLLocalFile4xx.forEach((filePath) => {
+  if (!filePath.endsWith('.html')) {
+    return
+  }
+
+  if (filePath.includes('signal')) {
+    HTMMLPlugin.push(
+      new HtmlWebpackPlugin({
+        inject: 'body',
+        template: path.resolve(__dirname, 'src/html/error/4xx', filePath), //指定模板文件
+        filename: path.join('error/4xx', filePath),
+        chunks: ['signal'],
+        publicPath: '../../'
+      })
+    )
+    return
+  }
+
+  if (filePath.includes('404')) {
+    HTMMLPlugin.push(
+      new HtmlWebpackPlugin({
+        inject: 'body',
+        template: path.resolve(__dirname, 'src/html/error/4xx', filePath), //指定模板文件
+        filename: path.join('error/4xx', filePath),
+        chunks: ['common', 'err404'],
+        publicPath: '../../'
+      })
+    )
+    return
+  }
+
+  HTMMLPlugin.push(
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/error/4xx', filePath), //指定模板文件
+      filename: path.join('error/4xx', filePath),
+      chunks: ['common', 'err4xx'],
+      publicPath: '../../'
+    })
+  )
+})
+
+const { localPathResult: AllHTMLLocalFile5xx } = filetool.filewaalk.getAllFilePaths(
+  path.resolve(__dirname, 'src/html/error/5xx')
+)
+AllHTMLLocalFile5xx.forEach((filePath) => {
+  if (!filePath.endsWith('.html')) {
+    return
+  }
+
+  if (filePath.includes('signal')) {
+    HTMMLPlugin.push(
+      new HtmlWebpackPlugin({
+        inject: 'body',
+        template: path.resolve(__dirname, 'src/html/error/5xx', filePath), //指定模板文件
+        filename: path.join('error/5xx', filePath),
+        chunks: ['signal'],
+        publicPath: '../../'
+      })
+    )
+    return
+  }
+
+  HTMMLPlugin.push(
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/error/5xx', filePath), //指定模板文件
+      filename: path.join('error/5xx', filePath),
+      chunks: ['common', 'err5xx'],
+      publicPath: '../../'
+    })
+  )
+})
+
+const config = {
+  mode: mode,
+
+  context: __dirname,
+
+  performance: {
+    hints: 'warning', // 或者 'error',取决于你希望如何处理超出限制的情况
+    maxAssetSize: 5000000, // 设置单个资源的最大尺寸,例如5MB
+    maxEntrypointSize: 10000000 // 设置入口起点的最大尺寸,例如10MB
+  },
+
+  entry: {
+    common: path.resolve(__dirname, 'src/common.js'),
+    index: path.resolve(__dirname, 'src/index.js'),
+    signal: path.resolve(__dirname, 'src/signal.js'),
+    new: path.resolve(__dirname, 'src/new.js'),
+    license: path.resolve(__dirname, 'src/license.js'),
+    mitorg: path.resolve(__dirname, 'src/mitorg.js'),
+    err4xx: path.resolve(__dirname, 'src/4xx.js'),
+    err404: path.resolve(__dirname, 'src/404.js'),
+    err5xx: path.resolve(__dirname, 'src/5xx.js')
+  },
+
+  output: {
+    path: path.resolve(__dirname, dist_name), //打包后的文件存放的地方
+    filename: 'js/[name].[fullhash].bundle.js', //打包后输出文件的文件名
+    chunkFilename: '[name].bundle.js',
+    clean: true,
+    charset: true,
+    publicPath: '/'
+  },
+
+  resolve: {
+    alias: {
+      '@': path.join(__dirname, 'src')
+    }
+  },
+
+  optimization: {
+    minimize: true,
+    minimizer: [
+      new TerserPlugin({
+        terserOptions: {
+          compress: {
+            drop_console: true, // 移除console.log (Github/发布版专属)
+            drop_debugger: true // 移除debugger (Github/发布版专属)
+          }
+        }
+      })
+    ]
+  },
+
+  module: {
+    rules: [
+      {
+        test: /\.(js|mjs|cjs)$/,
+        exclude: /(node_modules|bower_components)/,
+        use: {
+          loader: 'babel-loader'
+        }
+      },
+      {
+        test: /\.(css|scss|sass)$/,
+        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
+      },
+      {
+        test: /\.(png|jpg|jpeg|svg|gif)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'images', // 类似于 file-loader 的配置
+              name: '[name].[fullhash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.(mp4|m4v|avi|mov|qt|wmv|mkv|flv|webm|mpeg|mpg|3gp|3g2)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'videos', // 类似于 file-loader 的配置
+              name: '[name].[fullhash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.(woff|woff2|eot|ttf|otf)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'fonts', // 类似于 file-loader 的配置
+              name: '[name].[fullhash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.html$/i,
+        loader: 'html-loader'
+      }
+    ]
+  },
+
+  plugins: [
+    new CopyWebpackPlugin({
+      patterns: [
+        { from: 'public', to: './' },
+        { from: './config.json', to: './SH_CONFIG.json' },
+        { from: './LICENSE', to: './' },
+        { from: './LICENSE_CN', to: './' }
+      ]
+    }),
+    ...HTMMLPlugin,
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'index.html'), //指定模板文件
+      filename: 'index.html',
+      chunks: ['common', 'index'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'LICENSE_US.html'), //指定模板文件
+      filename: 'LICENSE_US.html',
+      chunks: ['common', 'license'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'LICENSE_CN.html'), //指定模板文件
+      filename: 'LICENSE_CN.html',
+      chunks: ['common', 'license'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'mitorg.html'), //指定模板文件
+      filename: 'mitorg.html',
+      chunks: ['common', 'mitorg'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'index.new.signal.html'), //指定模板文件
+      filename: 'index.new.signal.html',
+      chunks: ['common', 'new', 'signal'], // 此signal要设置common
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'index.new.html'), //指定模板文件
+      filename: 'index.new.html',
+      chunks: ['common', 'new'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/error/4xx/404.signal.html'), //指定模板文件
+      filename: '404.html',
+      chunks: ['common', 'signal'], // 此signal要设置common
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new MiniCssExtractPlugin({
+      filename: 'style/[name].[hash].bundle.css',
+      chunkFilename: 'css/[id].bundle.css'
+    })
+  ],
+
+  devServer: {
+    static: {
+      directory: path.join(__dirname, dist_name)
+    },
+    compress: true,
+    port: 1001,
+    open: true,
+    hot: false
+  }
+}
+
+export default config

+ 289 - 0
webpack_config_prod.js

@@ -0,0 +1,289 @@
+import path from 'path'
+import HtmlWebpackPlugin from 'html-webpack-plugin'
+import MiniCssExtractPlugin from 'mini-css-extract-plugin'
+import CopyWebpackPlugin from 'copy-webpack-plugin'
+import filetool from 'huan-file-tool'
+import { fileURLToPath } from 'url'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)
+
+const mode = 'production'
+const dist_name = 'dist-prod'
+
+const html_minify = {
+  collapseWhitespace: true,
+  removeComments: true,
+  removeRedundantAttributes: true,
+  useShortDoctype: true,
+  removeEmptyAttributes: true,
+  removeStyleLinkTypeAttributes: true,
+  keepClosingSlash: true,
+  minifyJS: true,
+  minifyCSS: true,
+  minifyURLs: true
+}
+
+const HTMMLPlugin = []
+
+const { localPathResult: AllHTMLLocalFile4xx } = filetool.filewaalk.getAllFilePaths(
+  path.resolve(__dirname, 'src/html/error/4xx')
+)
+AllHTMLLocalFile4xx.forEach((filePath) => {
+  if (!filePath.endsWith('.html')) {
+    return
+  }
+
+  if (filePath.includes('signal.html')) {
+    HTMMLPlugin.push(
+      new HtmlWebpackPlugin({
+        inject: 'body',
+        template: path.resolve(__dirname, 'src/html/error/4xx', filePath), //指定模板文件
+        filename: path.join('error/4xx', filePath),
+        chunks: ['signal'],
+        publicPath: '../../'
+      })
+    )
+    return
+  }
+
+  if (filePath.includes('400.html')) {
+    HTMMLPlugin.push(
+      new HtmlWebpackPlugin({
+        inject: 'body',
+        template: path.resolve(__dirname, 'src/html/error/4xx', filePath), //指定模板文件
+        filename: path.join('error/4xx', filePath),
+        chunks: ['common', 'err404'],
+        publicPath: '../../'
+      })
+    )
+    return
+  }
+
+  HTMMLPlugin.push(
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/error/4xx', filePath), //指定模板文件
+      filename: path.join('error/4xx', filePath),
+      chunks: ['common', 'err4xx'],
+      publicPath: '../../'
+    })
+  )
+})
+
+const { localPathResult: AllHTMLLocalFile5xx } = filetool.filewaalk.getAllFilePaths(
+  path.resolve(__dirname, 'src/html/error/5xx')
+)
+AllHTMLLocalFile5xx.forEach((filePath) => {
+  if (!filePath.endsWith('.html')) {
+    return
+  }
+
+  if (filePath.includes('signal.html')) {
+    HTMMLPlugin.push(
+      new HtmlWebpackPlugin({
+        inject: 'body',
+        template: path.resolve(__dirname, 'src/html/error/5xx', filePath), //指定模板文件
+        filename: path.join('error/5xx', filePath),
+        chunks: ['signal'],
+        publicPath: '../../'
+      })
+    )
+    return
+  }
+
+  HTMMLPlugin.push(
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/error/5xx', filePath), //指定模板文件
+      filename: path.join('error/5xx', filePath),
+      chunks: ['common', 'err5xx'],
+      publicPath: '../../'
+    })
+  )
+})
+
+const config = {
+  mode: mode,
+
+  context: __dirname,
+
+  performance: {
+    hints: 'warning', // 或者 'error',取决于你希望如何处理超出限制的情况
+    maxAssetSize: 5000000, // 设置单个资源的最大尺寸,例如5MB
+    maxEntrypointSize: 10000000 // 设置入口起点的最大尺寸,例如10MB
+  },
+
+  entry: {
+    common: path.resolve(__dirname, 'src/common.js'),
+    index: path.resolve(__dirname, 'src/index.js'),
+    signal: path.resolve(__dirname, 'src/signal.js'),
+    new: path.resolve(__dirname, 'src/new.js'),
+    license: path.resolve(__dirname, 'src/license.js'),
+    mitorg: path.resolve(__dirname, 'src/mitorg.js'),
+    err4xx: path.resolve(__dirname, 'src/4xx.js'),
+    err404: path.resolve(__dirname, 'src/404.js'),
+    err5xx: path.resolve(__dirname, 'src/5xx.js')
+  },
+
+  output: {
+    path: path.resolve(__dirname, dist_name), //打包后的文件存放的地方
+    filename: 'js/[name].[fullhash].bundle.js', //打包后输出文件的文件名
+    chunkFilename: '[name].bundle.js',
+    clean: true,
+    charset: true,
+    publicPath: '/'
+  },
+
+  resolve: {
+    alias: {
+      '@': path.join(__dirname, 'src')
+    }
+  },
+
+  module: {
+    rules: [
+      {
+        test: /\.(js|mjs|cjs)$/,
+        exclude: /(node_modules|bower_components)/,
+        use: {
+          loader: 'babel-loader'
+        }
+      },
+      {
+        test: /\.(css|scss|sass)$/,
+        use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
+      },
+      {
+        test: /\.(png|jpg|jpeg|svg|gif)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'images', // 类似于 file-loader 的配置
+              name: '[name].[fullhash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.(mp4|m4v|avi|mov|qt|wmv|mkv|flv|webm|mpeg|mpg|3gp|3g2)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'videos', // 类似于 file-loader 的配置
+              name: '[name].[fullhash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.(woff|woff2|eot|ttf|otf)$/i,
+        use: [
+          {
+            loader: 'url-loader',
+            options: {
+              limit: 8192, // 8KB 以下的文件将被转换为 Data URL
+              fallback: 'file-loader',
+              outputPath: 'fonts', // 类似于 file-loader 的配置
+              name: '[name].[fullhash].[ext]'
+            }
+          }
+        ]
+      },
+      {
+        test: /\.html$/i,
+        loader: 'html-loader'
+      }
+    ]
+  },
+
+  plugins: [
+    new CopyWebpackPlugin({
+      patterns: [
+        { from: 'public', to: './' },
+        { from: './config.json', to: './SH_CONFIG.json' },
+        { from: './LICENSE', to: './' },
+        { from: './LICENSE_CN', to: './' }
+      ]
+    }),
+    ...HTMMLPlugin,
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'index.html'), //指定模板文件
+      filename: 'index.html',
+      chunks: ['common', 'index'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'LICENSE_US.html'), //指定模板文件
+      filename: 'LICENSE_US.html',
+      chunks: ['common', 'license'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/LICENSE_CN.html'), //指定模板文件
+      filename: 'LICENSE_CN.html',
+      chunks: ['common', 'license'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'mitorg.html'), //指定模板文件
+      filename: 'mitorg.html',
+      chunks: ['common', 'mitorg'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'index.new.signal.html'), //指定模板文件
+      filename: 'index.new.signal.html',
+      chunks: ['common', 'new', 'signal'], // 此signal要设置common
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src', 'html', 'index.new.html'), //指定模板文件
+      filename: 'index.new.html',
+      chunks: ['common', 'new'],
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new HtmlWebpackPlugin({
+      inject: 'body',
+      template: path.resolve(__dirname, 'src/html/error/4xx/404.signal.html'), //指定模板文件
+      filename: '404.html',
+      chunks: ['common', 'signal'], // 此signal要设置common
+      minify: html_minify,
+      publicPath: './'
+    }),
+    new MiniCssExtractPlugin({
+      filename: 'style/[name].[hash].bundle.css',
+      chunkFilename: 'css/[id].bundle.css'
+    })
+  ],
+
+  devServer: {
+    static: {
+      directory: path.join(__dirname, dist_name)
+    },
+    compress: true,
+    port: 1001,
+    open: true,
+    hot: true
+  }
+}
+
+export default config