├── .github ├── CONTRIBUTING.md └── ISSUE_TEMPLATE │ ├── ------feature-request-.md │ └── -----bug-report-.md ├── .gitignore ├── .husky └── pre-commit ├── .npmrc ├── .vscode ├── extensions.json ├── global.code-snippets └── settings.json ├── README.md ├── app.config.ts ├── app.vue ├── assets ├── img │ ├── aside │ │ ├── design.png │ │ └── document.png │ └── beam │ │ ├── docs_bg.png │ │ ├── fill.jpg │ │ ├── home_bg.jpg │ │ ├── pink.jpg │ │ └── sky.jpg └── style │ └── base.css ├── components ├── AppHeader.vue ├── content │ ├── Card.vue │ ├── Image.vue │ └── Tabs.vue └── navigation │ ├── NavigationAside.vue │ └── NavigationToc.vue ├── composables ├── useDevice.ts ├── useFormatHash.ts ├── useHeaderInfo.ts ├── useLocale.ts ├── useOrganizeAside.ts ├── useSetAppHead.ts └── useToc.ts ├── content ├── concept │ ├── 10.documentation.md │ ├── 100.html │ │ └── _dir.yml │ ├── 200.css │ │ ├── 1.attribute-calc.md │ │ └── _dir.yml │ ├── 300.js │ │ ├── 1.es5.md │ │ ├── 2.prototype-chain.md │ │ ├── 3.event-loop.md │ │ ├── 5.cjs-esm.md │ │ ├── 7.design-pattern.md │ │ └── _dir.yml │ ├── 400.browser │ │ ├── 1.rendering-principle.md │ │ └── _dir.yml │ ├── 500.network │ │ └── _dir.yml │ ├── 600.cli │ │ └── _dir.yml │ └── 700.project │ │ └── _dir.yml └── docs │ ├── 10.documentation.md │ ├── 100.standard-directory │ ├── 1.fe-directory.md │ ├── 3.linux-directory.md │ └── _dir.yml │ ├── 1000.standard-analyse │ ├── 1.chrome.md │ ├── 2.user-traffic.md │ └── _dir.yml │ ├── 20.design.md │ ├── 200.standard-code │ ├── .5.tsconfig.md │ ├── 1.vscode.md │ ├── 2.eslint.md │ ├── 3.prettier.md │ ├── 4.stylelint.md │ └── _dir.yml │ ├── 2000.toolbox │ ├── 1.mac.md │ ├── 2.windows.md │ ├── 3.tv.md │ └── _dir.yml │ ├── 300.standard-commit │ ├── 1.husky-lintstaged.md │ ├── 2.commitizen-commitlint.md │ ├── 3.changelog.md │ ├── 4.git.md │ └── _dir.yml │ ├── 400.standard-dev │ ├── 0.html.md │ ├── 1.var.md │ ├── 2.notes.md │ ├── 3.mock.md │ └── _dir.yml │ ├── 500.stanard-buiild │ ├── 1.package.md │ ├── 2.build.md │ └── _dir.yml │ ├── 600.standard-monitor │ ├── 1.buried.md │ └── _dir.yml │ ├── 700.standard-optimize │ ├── 1.css.md │ ├── 2.js.md │ ├── 3.resource.md │ ├── 3.vue.md │ ├── 4.mini-program.md │ ├── 6.webpack.md │ ├── 7.vite.md │ ├── 9.network.md │ └── _dir.yml │ ├── 800.standard-test │ ├── 1.unit.md │ ├── 2.automation.md │ ├── 3.e2e.md │ └── _dir.yml │ └── 900.standard-deploy │ ├── 1.server.md │ ├── 14.node.md │ ├── 15.cicd.md │ ├── 16.devops.md │ ├── 2.applet.md │ ├── 3.app.md │ └── _dir.yml ├── error.vue ├── eslint.config.mjs ├── layouts └── default.vue ├── license ├── middleware ├── analytics.global.ts └── auth.ts ├── nuxt.config.ts ├── package.json ├── pages ├── concept │ └── [...slug].vue ├── docs │ └── [...slug].vue └── index.vue ├── pnpm-lock.yaml ├── public ├── content │ └── concept │ │ └── js_prototype_chain.png ├── favicon.ico └── logo.png ├── tsconfig.json ├── types └── navigation.ts └── uno.config.ts /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献指南 2 | 3 | ## 先决条件 4 | - [Nuxt prerequisites](https://nuxt.com/docs/getting-started/installation#prerequisites) 5 | 6 | ## 开发 7 | ### markdown 8 | - 可参考 [.vscode/global.code-snippets](/.vscode/global.code-snippets) 快捷生成代码文件 9 | 10 | ## 是否通过代码提交规范 11 | - [x] eslint 校验 12 | 13 | ## 提交 PR 14 | - fork 本仓库,在自己仓库基于 master 分支创建专用分支用于提交更改。 15 | - commit 规范遵循 Vue 仓库 [Git Commit Message Convention](https://github.com/vuejs/vue/blob/dev/.github/COMMIT_CONVENTION.md)。 16 | - 提交之前确保进行了完善的测试。 17 | - 确保 PR 提交到 master 分支。 18 | - 修复 Bug 请提供详细的描述信息,或链接到对应的 issue。 19 | - 提交新功能请阐明起用途以及提交到主仓库的必要性,最好事先仓库主要成员商议后再进行。 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/------feature-request-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 建议新功能(Feature Request) 3 | about: 对 系统 提出改善建议 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | --- 8 | 9 | **新功能描述** 简洁描述你希望补充完善的增强功能 10 | 11 | **现状及问题** [当前现状及由此导致的不便] 12 | 13 | **尝试方案** [如果你有尝试绕开或其它解决方案,在这里描述你的建议方案] 14 | 15 | **补充信息** [其它你认为有参考价值的信息] 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/-----bug-report-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 报告问题(Bug report) 3 | about: 详细描述你遇到的问题并寻求社区帮助 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **问题描述** [问题描述:尽可能简洁清晰地把问题描述清楚] 10 | 11 | **复现步骤** [复现问题的步骤] 12 | 13 | 1. 启动 '...' 14 | 2. 点击 '....' 15 | 3. 查看 16 | 17 | [或者可以直接贴源代码] 18 | 19 | **预期结果** [使用简洁清晰的语言描述你希望生效的预期结果] 20 | 21 | **实际结果** [这里请贴上你的报错截图或文字] 22 | 23 | **系统信息:** 24 | 25 | - 操作系统 [如 Mac 12.5] 26 | - 系统版本 [如 Version 1.0.0] 27 | - 设备信息 [如 Google Chrome 104.0.5112.101] 28 | 29 | **补充信息** [可选] [根据你的分析,出现这个问题的原因可能在哪里?] 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | # .env 23 | # .env.* 24 | # !.env.example 25 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | // themes & icons 4 | "antfu.theme-vitesse", 5 | "antfu.icons-carbon", 6 | "file-icons.file-icons", 7 | "Catppuccin.catppuccin-vsc-icons", 8 | 9 | // essential 10 | "Vue.Official", 11 | "octref.vetur", 12 | // "Nuxtr.nuxtr-vscode", 13 | "nuxt.mdc", 14 | "antfu.vite", 15 | "antfu.unocss", 16 | "antfu.iconify", 17 | "dbaeumer.vscode-eslint", 18 | 19 | // life savers! 20 | "GitHub.copilot", 21 | "github.copilot-chat", 22 | "intellsmi.comment-translate", 23 | "ms-ceintl.vscode-language-pack-zh-hans", 24 | "eamodio.gitlens", 25 | "EditorConfig.EditorConfig", 26 | 27 | // project tool 28 | "jock.svg", 29 | "lokalise.i18n-ally", 30 | 31 | // up to you 32 | "antfu.file-nesting", 33 | "antfu.browse-lite", 34 | "ritwickdey.liveserver", 35 | "usernamehw.errorlens", 36 | "streetsidesoftware.code-spell-checker", 37 | "wayou.vscode-todo-highlight", 38 | "vincaslt.highlight-matching-tag" 39 | // "naumovs.color-highlight", 40 | // "WakaTime.vscode-wakatime", 41 | // "github.vscode-github-actions", 42 | // "GitHub.vscode-pull-request-github", 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /.vscode/global.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "uniapp-vue2-template": { 3 | "scope": "vue", 4 | "prefix": "vue", 5 | "description": "Uniapp Vue2 Template", 6 | "body": [ 7 | "", 10 | "", 11 | "", 12 | "", 21 | "", 22 | "", 23 | "", 24 | ] 25 | }, 26 | "vue2-template": { 27 | "scope": "vue", 28 | "prefix": "vue", 29 | "description": "Vue2 Template", 30 | "body": [ 31 | "", 34 | "", 35 | "", 36 | "", 45 | "", 46 | "", 47 | "", 48 | ] 49 | }, 50 | "vue3-template": { 51 | "scope": "vue", 52 | "prefix": "vue", 53 | "description": "Vue3 Template", 54 | "body": [ 55 | "", 62 | "", 63 | "", 64 | "", 67 | "", 68 | "", 69 | "", 70 | ] 71 | }, 72 | "vue2-mixins": { 73 | "scope": "javascript,typescript", 74 | "prefix": "mixins", 75 | "description": "Vue2 Mixins", 76 | "body": [ 77 | "export default {", 78 | " data() {", 79 | " return {}", 80 | " },", 81 | "", 82 | " methods: {},", 83 | "}", 84 | ] 85 | }, 86 | "markdown-blog-template": { 87 | "scope": "markdown", 88 | "prefix": "md", 89 | "description": "Blog Template", 90 | "body": [ 91 | "---", 92 | "title: ''", 93 | "description: ''", 94 | "navigation:", 95 | " icon: ''", 96 | " title: ''", 97 | "---", 98 | "" 99 | ] 100 | }, 101 | "markdown-readme-template": { 102 | "scope": "markdown", 103 | "prefix": "md", 104 | "description": "README Template", 105 | "body": [ 106 | "

Welcome to X 👋

", 107 | "

", 108 | " \"Version\"", 109 | "

", 110 | "", 111 | "> Description of the X", 112 | "", 113 | "### 🏠 [Homepage]()", 114 | "", 115 | "### ✨ [Demo]()", 116 | "", 117 | "## Install", 118 | "", 119 | "```sh", 120 | "```", 121 | "", 122 | "## Usage", 123 | "", 124 | "```sh", 125 | "```", 126 | "", 127 | "## Run tests", 128 | "", 129 | "```sh", 130 | "```", 131 | "", 132 | "## 📝 License", 133 | "", 134 | "Copyright © 2024 []().
", 135 | "This project is [MIT]() licensed." 136 | ] 137 | }, 138 | "markdown-api-table": { 139 | "scope": "markdown", 140 | "prefix": "md", 141 | "description": "Markdown Api Table", 142 | "body": [ 143 | "", 144 | "", 145 | "", 152 | "", 159 | "", 160 | "
", 146 | "", 147 | "### API", 148 | "", 149 | "Description", 150 | "", 151 | "
", 153 | "", 154 | "```ts", 155 | "// code block", 156 | "```", 157 | "", 158 | "
", 161 | ], 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // ========== Visuals ========== 3 | "editor.cursorSmoothCaretAnimation": "on", 4 | "editor.fontFamily": "Input Mono, monospace", 5 | "editor.guides.bracketPairs": "active", 6 | "editor.lineNumbers": "interval", 7 | "editor.renderWhitespace": "boundary", 8 | "window.autoDetectColorScheme": true, 9 | "workbench.colorTheme": "Vitesse Dark", 10 | "workbench.editor.tabActionLocation": "left", 11 | "workbench.fontAliasing": "antialiased", 12 | "workbench.iconTheme": "catppuccin-mocha", 13 | "workbench.list.smoothScrolling": true, 14 | "workbench.preferredDarkColorTheme": "Vitesse Dark", 15 | "workbench.preferredLightColorTheme": "Vitesse Light", 16 | "workbench.productIconTheme": "icons-carbon", 17 | "workbench.sideBar.location": "left", 18 | "workbench.startupEditor": "newUntitledFile", 19 | "workbench.tree.expandMode": "singleClick", 20 | "workbench.tree.indent": 10, 21 | 22 | // ========== Editor ========== 23 | "debug.onTaskErrors": "debugAnyway", 24 | "diffEditor.ignoreTrimWhitespace": false, 25 | "editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?", 26 | "editor.find.addExtraSpaceOnTop": false, 27 | "editor.inlineSuggest.enabled": true, 28 | "editor.multiCursorModifier": "ctrlCmd", 29 | "editor.suggestSelection": "first", 30 | "editor.tabSize": 2, 31 | "editor.unicodeHighlight.invisibleCharacters": false, 32 | "editor.stickyScroll.enabled": true, 33 | "editor.hover.sticky": true, 34 | "editor.codeActionsOnSave": { 35 | "source.fixAll": "never", 36 | "source.fixAll.eslint": "explicit", 37 | "source.organizeImports": "never" 38 | }, 39 | "explorer.confirmDelete": false, 40 | "explorer.confirmDragAndDrop": false, 41 | "files.eol": "\n", 42 | "files.insertFinalNewline": true, 43 | "files.simpleDialog.enable": true, 44 | "git.autofetch": true, 45 | "git.confirmSync": false, 46 | "git.enableSmartCommit": true, 47 | "git.untrackedChanges": "separate", 48 | "scm.diffDecorationsGutterWidth": 2, 49 | "terminal.integrated.cursorBlinking": true, 50 | "terminal.integrated.cursorStyle": "line", 51 | "terminal.integrated.fontWeight": "300", 52 | "terminal.integrated.persistentSessionReviveProcess": "never", 53 | "terminal.integrated.tabs.enabled": true, 54 | "workbench.editor.closeOnFileDelete": true, 55 | "workbench.editor.highlightModifiedTabs": true, 56 | "workbench.editor.limit.enabled": true, 57 | "workbench.editor.limit.perEditorGroup": true, 58 | "workbench.editor.limit.value": 5, 59 | "search.exclude": { 60 | "**/*.snap": true, 61 | "**/*.svg": true, 62 | "**/.git": true, 63 | "**/.github": false, 64 | "**/.nuxt": true, 65 | "**/.output": true, 66 | "**/.pnpm": true, 67 | "**/.vscode": true, 68 | "**/.yarn": true, 69 | "**/assets": true, 70 | "**/bower_components": true, 71 | "**/dist/**": true, 72 | "**/logs": true, 73 | "**/node_modules": true, 74 | "**/out/**": true, 75 | "**/package-lock.json": true, 76 | "**/pnpm-lock.yaml": true, 77 | "**/public": true, 78 | "**/temp": true, 79 | "**/yarn.lock": true, 80 | "**/CHANGELOG*": true, 81 | "**/LICENSE*": true 82 | }, 83 | "[markdown]": { 84 | "editor.quickSuggestions": { 85 | "other": true, 86 | "comments": true, 87 | "strings": true 88 | } 89 | }, 90 | 91 | // ========== Global Level Config, needs to put in User Settings ========== 92 | "window.dialogStyle": "custom", 93 | "window.nativeTabs": true, // this is great, macOS only 94 | "window.title": "${rootName}", // this make tabs more readable 95 | "window.titleBarStyle": "custom", 96 | "extensions.autoUpdate": "onlyEnabledExtensions", 97 | 98 | // ========== Extension configs ========== 99 | "emmet.showSuggestionsAsSnippets": true, 100 | "emmet.triggerExpansionOnTab": false, 101 | "errorLens.enabledDiagnosticLevels": [ 102 | "warning", 103 | "error" 104 | ], 105 | "errorLens.excludeBySource": [ 106 | "cSpell", 107 | "Grammarly", 108 | "eslint" 109 | ], 110 | 111 | // ESLint config: https://github.com/antfu/eslint-config 112 | "eslint.experimental.useFlatConfig": true, 113 | "eslint.codeAction.showDocumentation": { 114 | "enable": true 115 | }, 116 | "eslint.quiet": true, 117 | // Silent the stylistic rules in you IDE, but still auto fix them 118 | "eslint.rules.customizations": [ 119 | { "rule": "style/*", "severity": "off" }, 120 | { "rule": "format/*", "severity": "off" }, 121 | { "rule": "*-indent", "severity": "off" }, 122 | { "rule": "*-spacing", "severity": "off" }, 123 | { "rule": "*-spaces", "severity": "off" }, 124 | { "rule": "*-order", "severity": "off" }, 125 | { "rule": "*-dangle", "severity": "off" }, 126 | { "rule": "*-newline", "severity": "off" }, 127 | { "rule": "*quotes", "severity": "off" }, 128 | { "rule": "*semi", "severity": "off" } 129 | ], 130 | "eslint.validate": [ 131 | "javascript", 132 | "javascriptreact", 133 | "typescript", 134 | "typescriptreact", 135 | "vue", 136 | "html", 137 | "markdown", 138 | "json", 139 | "jsonc", 140 | "yaml", 141 | "toml" 142 | ], 143 | 144 | "github.copilot.enable": { 145 | "*": true, 146 | "markdown": true, 147 | "plaintext": false 148 | }, 149 | "cSpell.allowCompoundWords": true, 150 | "cSpell.language": "en,en-US", 151 | "css.lint.hexColorLength": "ignore", 152 | // "githubIssues.workingIssueFormatScm": "#${issueNumberLabel}", 153 | // "githubPullRequests.fileListLayout": "tree", 154 | "gitlens.codeLens.authors.enabled": false, 155 | "gitlens.codeLens.enabled": false, 156 | "gitlens.codeLens.recentChange.enabled": false, 157 | "gitlens.menus": { 158 | "editor": { 159 | "blame": false, 160 | "clipboard": true, 161 | "compare": true, 162 | "history": false, 163 | "remote": false 164 | }, 165 | "editorGroup": { 166 | "blame": true, 167 | "compare": false 168 | }, 169 | "editorTab": { 170 | "clipboard": true, 171 | "compare": true, 172 | "history": true, 173 | "remote": true 174 | }, 175 | "explorer": { 176 | "clipboard": true, 177 | "compare": true, 178 | "history": true, 179 | "remote": true 180 | }, 181 | "scm": { 182 | "authors": true 183 | }, 184 | "scmGroup": { 185 | "compare": true, 186 | "openClose": true, 187 | "stash": true 188 | }, 189 | "scmGroupInline": { 190 | "stash": true 191 | }, 192 | "scmItem": { 193 | "clipboard": true, 194 | "compare": true, 195 | "history": true, 196 | "remote": false, 197 | "stash": true 198 | } 199 | }, 200 | "i18n-ally.autoDetection": false, 201 | "i18n-ally.displayLanguage": "en", 202 | "i18n-ally.ignoredLocales": [], 203 | "iconify.annotations": true, 204 | "iconify.inplace": true, 205 | "svg.preview.mode": "svg", 206 | 207 | // I only use Prettier for manually formatting 208 | // "prettier.enable": false, 209 | // "prettier.printWidth": 200, 210 | // "prettier.semi": false, 211 | // "prettier.singleQuote": true, 212 | 213 | // ========== File Nesting ========== 214 | // this might not be up to date with the repo, please check yourself 215 | // https://github.com/antfu/vscode-file-nesting-config 216 | "explorer.fileNesting.enabled": true, 217 | "explorer.fileNesting.expand": false, 218 | "explorer.fileNesting.patterns": { 219 | "*.asax": "$(capture).*.cs, $(capture).*.vb", 220 | "*.ascx": "$(capture).*.cs, $(capture).*.vb", 221 | "*.ashx": "$(capture).*.cs, $(capture).*.vb", 222 | "*.aspx": "$(capture).*.cs, $(capture).*.vb", 223 | "*.bloc.dart": "$(capture).event.dart, $(capture).state.dart", 224 | "*.c": "$(capture).h", 225 | "*.cc": "$(capture).hpp, $(capture).h, $(capture).hxx", 226 | "*.cjs": "$(capture).cjs.map, $(capture).*.cjs, $(capture)_*.cjs", 227 | "*.component.ts": "$(capture).component.html, $(capture).component.spec.ts, $(capture).component.css, $(capture).component.scss, $(capture).component.sass, $(capture).component.less", 228 | "*.cpp": "$(capture).hpp, $(capture).h, $(capture).hxx", 229 | "*.cs": "$(capture).*.cs", 230 | "*.cshtml": "$(capture).cshtml.cs", 231 | "*.csproj": "*.config, *proj.user, appsettings.*, bundleconfig.json", 232 | "*.css": "$(capture).css.map, $(capture).*.css", 233 | "*.cxx": "$(capture).hpp, $(capture).h, $(capture).hxx", 234 | "*.dart": "$(capture).freezed.dart, $(capture).g.dart", 235 | "*.ex": "$(capture).html.eex, $(capture).html.heex, $(capture).html.leex", 236 | "*.go": "$(capture)_test.go", 237 | "*.java": "$(capture).class", 238 | "*.js": "$(capture).js.map, $(capture).*.js, $(capture)_*.js", 239 | "*.jsx": "$(capture).js, $(capture).*.jsx, $(capture)_*.js, $(capture)_*.jsx", 240 | "*.master": "$(capture).*.cs, $(capture).*.vb", 241 | "*.mjs": "$(capture).mjs.map, $(capture).*.mjs, $(capture)_*.mjs", 242 | "*.module.ts": "$(capture).resolver.ts, $(capture).controller.ts, $(capture).service.ts", 243 | "*.pubxml": "$(capture).pubxml.user", 244 | "*.resx": "$(capture).*.resx, $(capture).designer.cs, $(capture).designer.vb", 245 | "*.tex": "$(capture).acn, $(capture).acr, $(capture).alg, $(capture).aux, $(capture).bbl, $(capture).blg, $(capture).fdb_latexmk, $(capture).fls, $(capture).glg, $(capture).glo, $(capture).gls, $(capture).idx, $(capture).ind, $(capture).ist, $(capture).lof, $(capture).log, $(capture).lot, $(capture).out, $(capture).pdf, $(capture).synctex.gz, $(capture).toc, $(capture).xdv", 246 | "*.ts": "$(capture).js, $(capture).d.ts.map, $(capture).*.ts, $(capture)_*.js, $(capture)_*.ts", 247 | "*.tsx": "$(capture).ts, $(capture).*.tsx, $(capture)_*.ts, $(capture)_*.tsx", 248 | "*.vbproj": "*.config, *proj.user, appsettings.*, bundleconfig.json", 249 | "*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue", 250 | "*.xaml": "$(capture).xaml.cs", 251 | "+layout.svelte": "+layout.ts,+layout.ts,+layout.js,+layout.server.ts,+layout.server.js,+layout.gql", 252 | "+page.svelte": "+page.server.ts,+page.server.js,+page.ts,+page.js,+page.gql", 253 | ".clang-tidy": ".clang-format, .clangd, compile_commands.json", 254 | ".env": "*.env, .env.*, .envrc, env.d.ts", 255 | ".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*", 256 | ".project": ".classpath", 257 | "//": "Last update at 4/29/2023, 2:04:58 PM", 258 | "BUILD.bazel": "*.bzl, *.bazel, *.bazelrc, bazel.rc, .bazelignore, .bazelproject, WORKSPACE", 259 | "CMakeLists.txt": "*.cmake, *.cmake.in, .cmake-format.yaml, CMakePresets.json", 260 | "I*.cs": "$(capture).cs", 261 | "artisan": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, server.php, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, webpack.mix.js, windi.config.*", 262 | "astro.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 263 | "cargo.toml": ".clippy.toml, .rustfmt.toml, cargo.lock, clippy.toml, cross.toml, rust-toolchain.toml, rustfmt.toml", 264 | "composer.json": ".php*.cache, composer.lock, phpunit.xml*, psalm*.xml", 265 | "default.nix": "shell.nix", 266 | "deno.json*": "*.env, .env.*, .envrc, api-extractor.json, deno.lock, env.d.ts, import-map.json, import_map.json, jsconfig.*, tsconfig.*, tsdoc.*", 267 | "dockerfile": ".dockerignore, docker-compose.*, dockerfile*", 268 | "flake.nix": "flake.lock", 269 | "gatsby-config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, gatsby-browser.*, gatsby-node.*, gatsby-ssr.*, gatsby-transformer.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 270 | "gemfile": ".ruby-version, gemfile.lock", 271 | "go.mod": ".air*, go.sum", 272 | "go.work": "go.work.sum", 273 | "mix.exs": ".credo.exs, .dialyzer_ignore.exs, .formatter.exs, .iex.exs, .tool-versions, mix.lock", 274 | "next.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, next-env.d.ts, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 275 | "nuxt.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 276 | "package.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*", 277 | "pubspec.yaml": ".metadata, .packages, all_lint_rules.yaml, analysis_options.yaml, build.yaml, pubspec.lock, pubspec_overrides.yaml", 278 | "pyproject.toml": ".pdm.toml, pdm.lock, pyproject.toml", 279 | "quasar.conf.js": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, quasar.extensions.json, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 280 | "readme*": "authors, backers*, changelog*, citation*, code_of_conduct*, codeowners, contributing*, contributors, copying, credits, governance.md, history.md, license*, maintainers, readme*, security.md, sponsors*", 281 | "remix.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, remix.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 282 | "rush.json": ".browserslist*, .circleci*, .commitlint*, .cz-config.js, .czrc, .dlint.json, .dprint.json, .editorconfig, .eslint*, .firebase*, .flowconfig, .github*, .gitlab*, .gitpod*, .huskyrc*, .jslint*, .lintstagedrc*, .markdownlint*, .node-version, .nodemon*, .npm*, .nvmrc, .pm2*, .pnp.*, .pnpm*, .prettier*, .releaserc*, .sentry*, .simple-git-hooks*, .stackblitz*, .styleci*, .stylelint*, .tazerc*, .textlint*, .tool-versions, .travis*, .versionrc*, .vscode*, .watchman*, .xo-config*, .yamllint*, .yarnrc*, Procfile, apollo.config.*, appveyor*, azure-pipelines*, bower.json, build.config.*, commitlint*, crowdin*, dangerfile*, dlint.json, dprint.json, eslint*, firebase.json, grunt*, gulp*, jenkins*, lerna*, lint-staged*, nest-cli.*, netlify*, nodemon*, npm-shrinkwrap.json, nx.*, package-lock.json, package.nls*.json, phpcs.xml, pm2.*, pnpm*, prettier*, pullapprove*, pyrightconfig.json, release-tasks.sh, release.config.*, renovate*, rollup.config.*, rspack*, simple-git-hooks*, stylelint*, tslint*, tsup.config.*, turbo*, typedoc*, unlighthouse*, vercel*, vetur.config.*, webpack*, workspace.json, xo.config.*, yarn*", 283 | "shims.d.ts": "*.d.ts", 284 | "svelte.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, houdini.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, mdsvex.config.js, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vite.config.*, vitest.config.*, webpack.config.*, windi.config.*", 285 | "vite.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*", 286 | "vue.config.*": "*.env, .babelrc*, .codecov, .cssnanorc*, .env.*, .envrc, .htmlnanorc*, .lighthouserc.*, .mocha*, .postcssrc*, .terserrc*, api-extractor.json, ava.config.*, babel.config.*, contentlayer.config.*, cssnano.config.*, cypress.*, env.d.ts, formkit.config.*, formulate.config.*, histoire.config.*, htmlnanorc.*, jasmine.*, jest.config.*, jsconfig.*, karma*, lighthouserc.*, playwright.config.*, postcss.config.*, puppeteer.config.*, rspack.config.*, svgo.config.*, tailwind.config.*, tsconfig.*, tsdoc.*, uno.config.*, unocss.config.*, vitest.config.*, webpack.config.*, windi.config.*" 287 | }, 288 | "todohighlight.include": [ 289 | "**/*.js", 290 | "**/*.jsx", 291 | "**/*.ts", 292 | "**/*.tsx", 293 | "**/*.html", 294 | "**/*.css", 295 | "**/*.scss", 296 | "**/*.vue" 297 | ], 298 | "todohighlight.keywords": [ 299 | { 300 | "text": "TODO:", 301 | "backgroundColor": "#FCD34D" 302 | }, 303 | { 304 | "text": "FIXME:", 305 | "backgroundColor": "#F87171" 306 | }, 307 | { 308 | "text": "NOTE:", 309 | "backgroundColor": "#FEE2E2" 310 | }, 311 | { 312 | "text": "HACK:", 313 | "backgroundColor": "#C7D2FE" 314 | }, 315 | { 316 | "text": "REVIEW:", 317 | "backgroundColor": "#A7F3D0" 318 | } 319 | ], 320 | "todohighlight.defaultStyle": { 321 | "color": "#ffffff", 322 | "cursor": "pointer", 323 | "borderRadius": "2px" 324 | }, 325 | "highlight-matching-tag.styles": { 326 | "opening": { 327 | "left": { 328 | "custom": { 329 | "borderWidth": "0 0 3px 0", 330 | "borderStyle": "solid", 331 | "borderColor": "#fca5a5", 332 | "borderRadius": "3px", 333 | "content": "''", 334 | "position": "absolute", 335 | "top": "0", 336 | "bottom": "0", 337 | "left": "0", 338 | "right": "0", 339 | "pointerEvents": "none", 340 | "zIndex": "-1", 341 | "animation": "highlight-matching-tag 1s ease-in-out infinite" 342 | } 343 | }, 344 | "right": { 345 | "custom": { 346 | "borderWidth": "0 0 3px 0", 347 | "borderStyle": "solid", 348 | "borderColor": "#fca5a5", 349 | "borderRadius": "3px", 350 | "content": "''", 351 | "position": "absolute", 352 | "top": "0", 353 | "bottom": "0", 354 | "left": "0", 355 | "right": "0", 356 | "pointerEvents": "none", 357 | "zIndex": "-1", 358 | "animation": "highlight-matching-tag 1s ease-in-out infinite" 359 | } 360 | } 361 | } 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Welcome to fe-workflow 👋

2 | 3 | ## Introduce 4 | 5 | ### 📚 An operation guide for FE development engineers 6 | 7 |
8 | 9 | ![Project Overview](https://s3.uuu.ovh/imgs/2022/12/08/30bcaa81410e828a.webp) 10 | -------------------------------------------------------------------------------- /app.config.ts: -------------------------------------------------------------------------------- 1 | export default defineAppConfig({ 2 | TITLE_EN: 'FE Workflow', 3 | TITLE_ZH: '前端工程化指南', 4 | DESCRIPTION_EN: 'design、build、specifications、develop、test、monitor、deploy、analyze、optimize', 5 | DESCRIPTION_ZH: '设计、搭建、规范、开发、测试、监控、部署、分析、优化', 6 | }) 7 | -------------------------------------------------------------------------------- /app.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 21 | -------------------------------------------------------------------------------- /assets/img/aside/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/assets/img/aside/design.png -------------------------------------------------------------------------------- /assets/img/aside/document.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/assets/img/aside/document.png -------------------------------------------------------------------------------- /assets/img/beam/docs_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/assets/img/beam/docs_bg.png -------------------------------------------------------------------------------- /assets/img/beam/fill.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/assets/img/beam/fill.jpg -------------------------------------------------------------------------------- /assets/img/beam/home_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/assets/img/beam/home_bg.jpg -------------------------------------------------------------------------------- /assets/img/beam/pink.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/assets/img/beam/pink.jpg -------------------------------------------------------------------------------- /assets/img/beam/sky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/assets/img/beam/sky.jpg -------------------------------------------------------------------------------- /assets/style/base.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | --at-apply: mt-8 tracking-tight text-3xl font-extrabold text-slate-900; 3 | } 4 | h2 { 5 | --at-apply: mb-2 tracking-normal whitespace-pre-wrap text-sm font-semibold text-sky-500; 6 | } 7 | h3 { 8 | --at-apply: mb-4 whitespace-pre-wrap text-xl font-semibold text-slate-900; 9 | } 10 | h4 { 11 | --at-apply: mb-4 whitespace-pre-wrap text-base text-slate-700; 12 | } 13 | p { 14 | --at-apply: mb-4 whitespace-pre-wrap text-base text-slate-700; 15 | } 16 | 17 | br { 18 | --at-apply: mt-1; 19 | } 20 | hr { 21 | --at-apply: my-8 border-t-2 border-slate-100; 22 | } 23 | 24 | pre { 25 | --at-apply: p-4 my-8 overflow-x-auto bg-slate-800 rounded-lg shadow-sm; 26 | } 27 | p > code, 28 | li > code { 29 | --at-apply: m-0 px-2 py-1 text-sm font-medium text-sky-500 bg-slate-900/20 rounded-md; 30 | } 31 | 32 | .doclink { 33 | @apply: !block !mt-1 !w-fit !text-slate-700 !font-semibold !underline !decoration-1 !underline-offset-4 !decoration-sky-500 !hover:text-sky-500; 34 | } 35 | 36 | ul, 37 | ol { 38 | @apply: !mt-2 !mb-4 !list-inside !text-slate-600; 39 | } 40 | ul { 41 | @apply: !list-disc; 42 | } 43 | li > ul { 44 | @apply: !mb-0 !py-0 !pb-2 !pl-8 !pr-4 !list-disc !text-slate-500; 45 | } 46 | ol { 47 | @apply: !mt-1 !list-decimal; 48 | } 49 | 50 | table { 51 | @apply: !mb-8 !text-sm !border-b !border-slate-400 !border-collapse; 52 | } 53 | thead { 54 | @apply: !bg-slate-50; 55 | } 56 | tr > th { 57 | @apply: !p-4 !text-left !border-b !border-slate-300 !text-slate-900 !font-semibold; 58 | } 59 | tr > td { 60 | @apply: !p-4 !border-b !border-slate-300 !text-slate-600; 61 | } 62 | 63 | ::-webkit-scrollbar { 64 | --at-apply: hidden; 65 | } 66 | ::-webkit-scrollbar-thumb { 67 | --at-apply: bg-slate-300 rounded-md; 68 | } 69 | -------------------------------------------------------------------------------- /components/AppHeader.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 128 | -------------------------------------------------------------------------------- /components/content/Card.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 36 | -------------------------------------------------------------------------------- /components/content/Image.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /components/content/Tabs.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 34 | -------------------------------------------------------------------------------- /components/navigation/NavigationAside.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 60 | -------------------------------------------------------------------------------- /components/navigation/NavigationToc.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 40 | -------------------------------------------------------------------------------- /composables/useDevice.ts: -------------------------------------------------------------------------------- 1 | export const useUseDevice = () => { 2 | if (process.client) { 3 | const isMobile = ref(false) 4 | isMobile.value = /mobile/i.test(window.navigator.userAgent) || window.innerWidth <= 768 5 | 6 | return isMobile 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /composables/useFormatHash.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 生成规范锚点链接 3 | * 1、解码链接 4 | * 2、去除首尾空格 5 | * 3、空格替换为'-' 6 | * 4、去除特殊字符 7 | * 5、小写 8 | * 6、如果首字符为数字,则在前面加上'_' 9 | */ 10 | export const useFormatHash = (hashLink: string) => { 11 | const pattern = /[\!\@\#\$\%\^\&\*\(\)\+\{\[\}\]\|\:\;\"\'\<\,\>\.\?\`\~\~\·\!\@\#\¥\%\…\…\&\*\(\)\+\=\「\【\」\】\|\、\/\\\:\;\“\‘\《\,\》\。\?]/g; 12 | hashLink = hashLink 13 | .trim() 14 | .replace(/\s/g, '-') 15 | .replace(pattern, '') 16 | .replace(/--/g, '-') 17 | .toLowerCase(); 18 | 19 | if (!isNaN(Number(hashLink[0]))) { 20 | hashLink = `_${hashLink}` 21 | } 22 | 23 | return `#${hashLink}` 24 | } 25 | -------------------------------------------------------------------------------- /composables/useHeaderInfo.ts: -------------------------------------------------------------------------------- 1 | export const useHeaderInfo = () => { 2 | const repoGitHub = computed(() => { 3 | return { 4 | text: 'GitHub', 5 | icon: 'i-carbon-logo-github', 6 | link: 'https://github.com/LOUSANPANG/fe-workflow', 7 | target: '_blank' 8 | } 9 | }) 10 | 11 | const headerLinks = computed(() => { 12 | return [ 13 | { 14 | text: 'Docs', 15 | link: '/docs/documentation', 16 | target: '_self' 17 | }, 18 | { 19 | text: 'Concept', 20 | link: '/concept/documentation', 21 | target: '_self' 22 | }, 23 | { 24 | text: 'Blog', 25 | link: 'https://lousanpang.github.io', 26 | target: '_blank' 27 | } 28 | ] 29 | }) 30 | 31 | return { 32 | repoGitHub, 33 | headerLinks, 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /composables/useLocale.ts: -------------------------------------------------------------------------------- 1 | export const useLocale = () => { 2 | return useState('locale', () => useDefaultLocale().value) 3 | } 4 | 5 | export const useDefaultLocale = (fallback = 'en-ZH') => { 6 | const locale = ref(fallback) 7 | if (process.server) { 8 | const reqLocale = useRequestHeaders()['accept-language']?.split(',')[0] 9 | if (reqLocale) { 10 | locale.value = reqLocale 11 | } 12 | } else if (process.client) { 13 | const navLang = navigator.language 14 | if (navLang) { 15 | locale.value = navLang 16 | } 17 | } 18 | return locale 19 | } 20 | -------------------------------------------------------------------------------- /composables/useOrganizeAside.ts: -------------------------------------------------------------------------------- 1 | import type { NavItem } from '@nuxt/content/dist/runtime/types' 2 | import type { RouteType } from '~/types/navigation' 3 | 4 | 5 | export const useOrganizeAside = (navigation: Ref) => { 6 | const route = useRoute() 7 | const targetRoutName = ref('') 8 | if (route.fullPath.includes('docs')) { 9 | targetRoutName.value = 'docs' 10 | } else if (route.fullPath.includes('concept')) { 11 | targetRoutName.value = 'concept' 12 | } 13 | 14 | const routes: Array = navigation.value.filter((item) => (item.title.toLowerCase() === targetRoutName.value)) 15 | const asideEarlyDev: RouteType[] = routes[0]?.children.filter((route: RouteType) => !route.children) 16 | const asideGuide: RouteType[] = routes[0]?.children.filter((route: RouteType) => route.children) 17 | 18 | return { 19 | asideEarlyDev, 20 | asideGuide 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /composables/useSetAppHead.ts: -------------------------------------------------------------------------------- 1 | export const useSetAppHead = () => { 2 | const { TITLE_EN, DESCRIPTION_EN } = useAppConfig() 3 | 4 | useHead({ 5 | title: TITLE_EN, 6 | titleTemplate: title => title === TITLE_EN ? title : `${title} · ${TITLE_EN}`, 7 | meta: [ 8 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 9 | { name: 'description', content: DESCRIPTION_EN }, 10 | ], 11 | link: [ 12 | { 13 | rel: 'icon', type: 'image/x-icon', href: `/favicon.ico`, 14 | }, 15 | ], 16 | script: [ 17 | { 18 | src: 'https://www.googletagmanager.com/gtag/js?id=G-L4BS2P1L41', 19 | async: true, 20 | }, 21 | { 22 | innerHTML: ` 23 | window.dataLayer = window.dataLayer || []; 24 | function gtag(){dataLayer.push(arguments);} 25 | gtag('js', new Date()); 26 | gtag('config', 'G-L4BS2P1L41'); 27 | `, 28 | type: 'text/javascript', 29 | } 30 | ] 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /composables/useToc.ts: -------------------------------------------------------------------------------- 1 | import type { linkType, tocType } from '~/types/navigation' 2 | 3 | export const useToc = (toc: tocType) => { 4 | const links: linkType[] = toc.links 5 | 6 | return links 7 | } 8 | -------------------------------------------------------------------------------- /content/concept/10.documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Documentation' 3 | description: '概念' 4 | navigation: 5 | icon: '/aside/document.png' 6 | title: 'Documentation' 7 | --- 8 | 9 | ## 令人难忘的知识概念 10 | 11 |
12 | 13 | 属性值计算过程、浏览器的渲染原理、事件循环机制、网络性能优化、工程化讨论... 14 | -------------------------------------------------------------------------------- /content/concept/100.html/_dir.yml: -------------------------------------------------------------------------------- 1 | title: HTML 2 | -------------------------------------------------------------------------------- /content/concept/200.css/1.attribute-calc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '属性值计算过程' 3 | --- 4 | 5 | ## 属性值计算过程 6 | 7 | ### `CSS无属性值`到`有属性值` 8 | - 确定声明值:合并作者该元素的样式表和浏览器默认样式 9 | - 层叠冲突 10 | - 比较重要性:作者样式表 > 浏览器默认样式表 11 | - 比较特殊性:权重(选择器) 12 | - 比较源次序:代码靠后的 > 代码靠前的 13 | - 使用继承:没有值得属性,若可以继承,继承父元素的值 14 | - 使用默认值:最终仍然没有值的,继承默认值 15 | -------------------------------------------------------------------------------- /content/concept/200.css/_dir.yml: -------------------------------------------------------------------------------- 1 | title: CSS 2 | -------------------------------------------------------------------------------- /content/concept/300.js/1.es5.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'ES5 基础' 3 | --- 4 | 5 | ## 非严格相等 6 | 7 | ### 两端类型一致 8 | - NaN 与 NaN 比较为 false 9 | - 除 NaN 外,两端类型一致时正常比较 10 | 11 | ```bash 12 | # 一种特殊情况 NaN 13 | console.log(NaN == NaN) # false 14 | 15 | # 除NaN外,两端类型一致时正常比较 16 | console.log(1 == 2) # false 17 | console.log('abc' == 'abc') # true 18 | console.log(null == null) # true 19 | console.log(undefined == undefined) # true 20 | console.log([] == []) # false 21 | ``` 22 | 23 | ### 两端类型不一致 24 | - 一种特殊情况:null 和 undefined 比较 25 | - 两种规则:两端为原始类型转数字;两端一端为对象,**对象转原始**; 26 | ```bash 27 | # 一种特殊情况,null和undefined比较为true 28 | null == undefined # true 29 | null == 1 # false 30 | 31 | # 两种规则,两端为原始类型转数字 32 | 1 == '1' # true 33 | 1 == true # true 34 | false == '0' # true 35 | 36 | # 两种规则,两端一端为对象,对象转原始 37 | # 对象转原始类型分三步: 38 | # 1、查看对象有没有 [][Symbol.toPrimitive] 函数 39 | # 2、查看对象有没有 [].valueOf 函数 40 | # 3、调用对象的 [].toString 函数 41 | [] == 2 # false 42 | ['1'] == 1 # true 43 | ``` 44 | -------------------------------------------------------------------------------- /content/concept/300.js/2.prototype-chain.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '原型链' 3 | --- 4 | 5 | ## 原型链全貌图 6 | 7 | ```js 8 | /** 9 | * 函数A产生对象a:new A() => a 10 | * 函数A本身自带原型对象:A.prototype 11 | * 对象a有个隐式原型指向函数A原型对象:a.__proto__ === A.prototype 12 | * 13 | * 函数A的原型对象 A.prototype => {} <= new Object() 14 | * 函数Object本子自带原型对象:Object.prototype 15 | * 函数A原型对象A.prototype有个隐式原型指向函数Object原型对象:A.prototype.__proto__ === Object.prototype 16 | * Object.prototype对象有个隐式原型指向null 17 | * 18 | * new Function => Object // typeof Object => 'function' 19 | * Object.__proto__ => Function.prototype 20 | * new Object => Function.prototype 21 | * 22 | * new Function => A 23 | * A.__proto__ => Function.prototype 24 | */ 25 | ``` 26 | 27 | ::Image{src="/content/concept/js_prototype_chain.png"} 28 | :: 29 | -------------------------------------------------------------------------------- /content/concept/300.js/3.event-loop.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '事件循环机制' 3 | --- 4 | 5 | ## 事件循环机制 6 | 7 | ### 原理 8 | js 是一门单线程语言,它运行在浏览器的渲染主线程中,而浏览器主线程只有一个。而主线程承担着诸多的工作,渲染页面、执行js等都在其中。 9 | 10 | 如果使用同步,极有可能导致主线程产生堵塞,从而导致消息队列中的其他任务无法得到执行。这样的话一方面导致繁忙的主线程白白的浪费时间,另一方面导致页面无法及时更新,给用户一种页面卡死的现象。 11 | 12 | 所以浏览器采用异步的方式来避免,具体做法是当某些任务发生时,比如计时器、网络、事件监听。主线程交给其他线程来处理,自身立即结束任务的执行,转而执行后续的代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到消息队列的末尾排队,等待主线程调度执行。 13 | 14 | 这种异步模式下,浏览器不会阻塞,从而最大限度的保证了单线程的流畅运行。 15 | 16 | ### 解释 17 | 事件循环又叫消息循环,是浏览器渲染主线程的工作方式。 18 | 19 | 在 Chrome 的源码中,它开启一个不会结束的 for 循环,每次循环从消息队列中取出第一个任务执行,而其他线程只需要在合适的时候将任务加入到队列末尾即可。 20 | 过去把消息队列简单分为宏队列和微队列,这种说法目前已无法满足复杂的浏览器环境,取而代之的是一种更加灵活多变的处理方式。 21 | 22 | 根据 W3C 官方的解释,每个任务有不同的类型,同类型的任务必须在同一个队列,不同的任务可以属于不同的队列。不同任务队列有不同的优先级,在一次事件循环中,由浏览器自行决定取哪一个队列的任务。 23 | 24 | 但浏览器必须有一个微队列,微队列的任务一定具有最高的优先级,必须优先调度执行。 25 | 渲染主线程 -> 微队列(promise) -> 交互队列(事件点击、浏览器滚动) -> 延时队列(定时器) -> ...队列 26 | 27 | ## js 中的计时器能做到精确计时吗? 28 | 1、计算机硬件没有原子钟,无法做到精确计时 29 | 2、操作系统的计时函数本身就有少量偏差,由于 js 的计时器最终调用的是操作系统的函数,也就携带了这些偏差 30 | 3、按照 W3C 的标准,浏览器实现计时器时,如果嵌套层级超过 5 层,并且有延时小于 4ms,那么延时会被设置为 4ms 31 | 4、受事件循环的影响,计时器的回调函数只能在主线程空闲时运行,因此又带来了偏差 32 | -------------------------------------------------------------------------------- /content/concept/300.js/5.cjs-esm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Commonjs和ESModule' 3 | --- 4 | 5 | ## Commonjs和ESModule区别 6 | 7 | ### Common js 8 | 9 | - 社区标准 10 | - 使用函数实现 11 | - 仅node环境支持 12 | - 动态依赖 13 | - 动态依赖同步执行 14 | 15 | ```js 16 | // require 函数原理 17 | /** 18 | * 一个模块(js文件)就是一个 {},隐形代表的是 module.exports 19 | * 在模块中直接打印 this,其实就是 module.exports 20 | * 不管是 this.xx exports.xx 其实都是往 module.exports 的对象挂载 21 | */ 22 | 23 | function require(path) { 24 | // 第一步 25 | if (该模块有缓存) { 26 | return 缓存结果 27 | } 28 | 29 | function _run(exports, require, module, __filename, __dirname) { 30 | // js文件代码 31 | } 32 | 33 | // 第二步 34 | const module = { 35 | exports: {}, 36 | } 37 | 38 | // 第三步 39 | _run.call( 40 | module.exports, // this 指向 41 | module.exports, 42 | require, 43 | module 44 | .模块路径, 45 | 模块所在目录, 46 | ) 47 | 48 | // 第四步把 module.exports 加入到缓存中 49 | 50 | // 第五步 51 | return module.exports 52 | } 53 | ``` 54 | 55 | ### ES Module 56 | - 官方标准 57 | - 使用新语法实现 58 | - 所有环境均支持 59 | - 静态依赖:在代码运行前就要确定依赖关系 60 | - 动态依赖是异步的 61 | - 符号绑定(引用地址传递) 62 | 63 |
64 | 65 | ## 经典题 66 | 67 | ### require 函数导出相关问题 68 | 69 | ```js 70 | // 1.js 71 | this.a = 1 72 | exports.b = 2 73 | module.exports.c = 3 74 | 75 | // 2.js 76 | const m = require('./1') 77 | console.log(m) // { a: 1, b: 2, c: 3 } 78 | ``` 79 | 80 | ### ESModule 符号绑定相关问题 81 | 82 | ```js 83 | // a.js 84 | export var count = 0 85 | export function increase() { 86 | count ++ 87 | } 88 | 89 | // b.js 90 | import { count, increase } from 'a.js'; 91 | console.log(count) // 0 92 | increase() 93 | console.log(count) // 1 94 | ``` 95 | -------------------------------------------------------------------------------- /content/concept/300.js/7.design-pattern.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '设计模式' 3 | --- 4 | -------------------------------------------------------------------------------- /content/concept/300.js/_dir.yml: -------------------------------------------------------------------------------- 1 | title: JS 2 | -------------------------------------------------------------------------------- /content/concept/400.browser/1.rendering-principle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '浏览器渲染原理' 3 | --- 4 | 5 | ## 浏览器是如何渲染页面 6 | 7 | ### 阐述 8 | 9 | 当浏览器的网络线程收到 HTML 文档后,会产生一个渲染任务,并将其传递给渲染主线程的消息队列。 10 | 在事件循环机制的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程。 11 | 12 | 整个渲染流程分为多个阶段,分别是:HTML 解析、样式计算、布局、分层、绘制、分块、光栅化和合成。 13 | 每个阶段都有明确的输入和输出,上一个阶段的输出会成为下一个阶段的输入。 14 | 这样整个渲染流程就形成了一套组织严密的生产流水线。 15 | 16 | ### 渲染阶段 17 | 18 | HTML 解析 - Parse html 19 | - 解析过程中遇到 CSS 解析 CSS,遇到 JS 执行 JS。为了提高解析效率,浏览器在开始解析前,会启动一个预解析的线程,率先下载 HTML 中的外部 CSS 文件和外部的 JS 文件。 20 | - 如果主线程解析到 link 位置,此时外部的 css 文件还没有下载好,主线程不会等待,继续解析后续的 HTML。这是因为下载和解析 CSS 的工作是在预解析线程中进行的。这就是 CSS 不会阻塞 HTML 解析的根本原因。 21 | - 如果主线程解析到 script 位置,会停止解析 HTML,转而等待 JS 文件下载好,并将全局代码解析执行完成后,才能继续解析 HTML。这是因为 jS 代码的执行过程可能会修改当前的 DOM 树,所有 DOM 树的生成必须暂停。这就是 JS 会阻塞 HTML 解析的根本原因。 22 | - 完成后,会得到 DOM 树和 CSSOM 树,浏览器的默认样式、内部样式、行内样式均会包含在 CSSOM 树中。 23 | 24 | 样式计算 25 | - 主线程会遍历得到的 DOM 树,依次为树中的每个节点计算出它最终的样式,称之为 Computed Style。在这一过程中,很多预设值会变成绝对值,比如 red 会变成 rgb(255,0,0);相对单位会变成绝对单位,比如 em 会变成 px。 26 | - 完成后,会得到一颗带有样式的 DOM 树。 27 | 28 | 布局 29 | - 布局阶段会依次遍历 DOM 树的每一个节点,计算每个节点的几何信息。例如节点的宽高、相对包含块的位置。大部分时候,DOM 树和布局树并非一一对应。比如 dispaly:none 的节点没有几何信息,因此不会生成到布局树;又比如使用伪元素选择器,虽然 DOM 树中不存在这些伪元素节点,但他们拥有集合信息,所以会生成到布局树中。还有匿名行盒、匿名块盒等等都会导致 DOM 树和布局树无法一一对应。 30 | - 完成后,会得到布局树 31 | 32 | 分层 33 | 主线程会使用一套复杂的策略对整个布局树中进行分层。分层的好处在于,将来某一个层改变后,仅会对该层进行后续处理,从而提升效率。滚动条、堆叠上下文、transfrom、opacity等样式都会或多或少的影响分层结果,也可以通过 will-change 属性更大程度的影响分层结果。 34 | 35 | 绘制 36 | 主线程会为每个层单独产生绘制指令集,用于描述这一层的内容该如何画出来。完成绘制后,主线程将每个图层的绘制信息提交给合成线程,剩余工作将由合成线程完成。 37 | 38 | 分块 39 | 合成线程首先对每个图层进行分块,将其划分为更多的小区域。它会从线程池中拿取多个线程来完成分块工作。 40 | 41 | 光栅化 42 | 合成线程会将块信息交给 GPU 进程,以极高的速度完成光栅化。GPU 进程会开启多个线程来完成光栅化,并且优先处理靠近视口区域的块。光栅化的结果就是一块一块的位图。 43 | 44 | 画 45 | - 合成线程拿到每个层、每个块的位图后,生成一个个 指引 quad 信息。指引会标识出每个位图应该画到屏幕的哪个位置,以及会考虑到旋转、缩放等变形。变形发生在合成线程、与渲染中线程无关,这就是 transform 效率高的本质原因。 46 | - 合成线程会把 quad 提交给 GPU 进程,由 GPU 进程产生系统调用,提交给 GPU 硬件,完成最终的屏幕成像。 47 | 48 |
49 | 50 | ## 什么是 reflow 51 | 52 | - 重排,属于渲染阶段的布局阶段,本质是重新计算layout树、布局树。 53 | - 当进行了会影响布局树的操作后,需要重新计算布局树,会引发 layout。 54 | - 为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 js 代码全部完成后再进行统一计算。所以改动属性造成的 reflow 是异步完成的。 55 | - 也同样因为如此,当 js 获取布局属性时,就可能造成无法获取到最新的布局信息。浏览器在反复权衡下,最终决定获取属性立即 reflow。 56 | 57 |
58 | 59 | ## 什么是 repaint 60 | 61 | - 重绘,属于渲染阶段的绘制阶段,本质是重新根据分层信息计算了绘制指令。 62 | - 当改动了可见样式后,就需要重新计算,会引发 repaint。 63 | - 由于元素的布局信息也属于可见样式,所以 reflow 一定会引起 repaint。 64 | 65 |
66 | 67 | ## 为什么 transform 效率高 68 | 69 | - 因为 transform 既不会影响布局也不会影响绘制指令,它影响的只是渲染流程的最后一个 draw 阶段 70 | - 由于 draw 阶段在合成线程中,所以 transform 的变化几乎不会影响渲染主线程。反之渲染主线程无论如何忙碌,也不会影响 transform 的变化。 71 | -------------------------------------------------------------------------------- /content/concept/400.browser/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 浏览器 2 | -------------------------------------------------------------------------------- /content/concept/500.network/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 网络 2 | -------------------------------------------------------------------------------- /content/concept/600.cli/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 工程化 2 | -------------------------------------------------------------------------------- /content/concept/700.project/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 项目 2 | -------------------------------------------------------------------------------- /content/docs/10.documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Documentation' 3 | description: '介绍' 4 | navigation: 5 | icon: '/aside/document.png' 6 | title: 'Documentation' 7 | --- 8 | 9 | ## 前端工程化指南文档 10 | 11 |
12 | 13 | 针对UI设计适配、工程构建、目录规范、代码质量、提交约定、性能优化、代码测试、埋点监控、项目部署、数据分析等方面的前端工程化指南文档。 14 | -------------------------------------------------------------------------------- /content/docs/100.standard-directory/1.fe-directory.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '前端目录规范' 3 | --- 4 | 5 | ## 文件命名规范 6 | 7 | ### 项目名 8 | 9 | ```bash 10 | # kebab-case 11 | my-project-name 12 | ``` 13 | 14 | ### 文件夹 15 | 16 | ```bash 17 | # kebab-case 18 | aa-bb/ 19 | ``` 20 | 21 | ### 公共组件 22 | 23 | ```bash 24 | # 始终 PascalCase,或始终使用 kebab-case。 25 | # 高级别的(一般化描述的) + 描述性的修饰词 26 | components/ 27 | |- SearchButtonClear.vue 28 | |- SearchButtonRun.vue 29 | |- SearchInputQuery.vue 30 | |- SearchInputExcludeGlob.vue 31 | |- SettingsCheckboxTerms.vue 32 | |- SettingsCheckboxLaunchOnStartup.vue 33 | ``` 34 | 35 | ### 静态文件 36 | 37 | ```bash 38 | # 图像文件 39 | img/ 40 | |- banner_sina.gif 41 | |- logo_police.gif 42 | 43 | # HTML 44 | # 小写、优先使用单个单词 45 | # 多个单词使用 下划线 46 | |- success_report.html 47 | 48 | # CSS 49 | # 小写、优先使用单个单词、下划线开头 50 | # 多个单词使用 kebab-case 51 | assets/css/ 52 | |- _color.scss 53 | |- xxx-ui.css 54 | 55 | # 源码脚本 56 | lib/ 57 | |- aa_bb.ts 58 | ``` 59 | 60 | ### 编译文件 61 | 62 | ```bash 63 | # 单文件组件 64 | |- hello-word.vue 65 | 66 | # 工具函数 JS 67 | # 小写、优先使用单个单词 68 | # 多个单词使用 kebab-case 69 | |- index.js 70 | |- date-util.js 71 | ``` 72 | 73 |
74 | 75 | ## 特殊单词命名 76 | 77 | ### 单例组件名 78 | 79 | ```bash 80 | # 每个页面只使用一次 81 | # 不接受任何 prop 82 | # `The` 前缀命名 83 | components/ 84 | |- TheHeading.vue 85 | |- TheSidebar.vue 86 | ``` 87 | 88 | ### 基础组件名 89 | 90 | ```bash 91 | # 展示类的、无逻辑、无状态、不掺杂业务逻辑 92 | # 页面内可使用多次,不同页面也可复用,是高可复用组件 93 | # `Base` 前缀命名 94 | components/ 95 | |- BaseButton.vue 96 | |- BaseTable.vue 97 | |- BaseIcon.vue 98 | ``` 99 | 100 | ### 业务组件 101 | 102 | ```bash 103 | # 只在当前项目中会用到,不具有通用性 104 | # 掺杂了复杂业务的组件,拥有自身 data、prop 的相关处理 105 | # `Custom` 前缀命名 106 | components/ 107 | |- CustomCard.vue 108 | ``` 109 | 110 | ### 紧密耦合的组件名 111 | 112 | ```bash 113 | # 和父组件紧密耦合的子组件应该以父组件名作为前缀命名 114 | # `以父组件` 前缀命名 115 | components/ 116 | |- TodoList.vue # 父组件 117 | |- TodoListItem.vue # 子组件 118 | |- TodoListItemButton.vue # 子组件 119 | ``` 120 | -------------------------------------------------------------------------------- /content/docs/100.standard-directory/3.linux-directory.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Linux目录规范' 3 | --- 4 | 5 | ### Linux 目录结构 6 | 7 | ```bash 8 | |- /opt # 第三方软件安装包 9 | |- java # java 安装包 10 | |- ... 11 | |- /usr # 用户软件 12 | |- local # 本地软件 13 | |- java # java软件 14 | |- /home # 用户目录 15 | |- /bin # 常用指令 16 | |- /boot # 启动文件 17 | |- /dev # 设备文件 18 | |- /etc # 配置文件 19 | |- /lib # 库文件 20 | |- /media # 可移动设备 21 | |- /mnt # 挂载目录 22 | |- /proc # 进程信息 23 | |- /root # root 用户目录 24 | |- /run # 运行时信息 25 | |- /sbin # 管理员常用指令 26 | |- /srv # 服务数据 27 | |- /sys # 系统信息 28 | |- /tmp # 临时文件 29 | |- /var # 日志 30 | |- /lost # 文件系统恢复 31 | ``` 32 | -------------------------------------------------------------------------------- /content/docs/100.standard-directory/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 目录规范 2 | -------------------------------------------------------------------------------- /content/docs/1000.standard-analyse/1.chrome.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '性能优化分析' 3 | --- 4 | 5 | ## 速度性能检测工具 6 | 7 | [PageSpeed Insights 网站各项 RUM 数据](https://pagespeed.web.dev/?utm_source=psi&utm_medium=redirect){.doclink} 8 | [WebPageTest 网站速度测试](https://www.webpagetest.org/){.doclink} 9 | -------------------------------------------------------------------------------- /content/docs/1000.standard-analyse/2.user-traffic.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '用户数据分析' 3 | --- 4 | 5 | ## 参考链接 6 | [友盟](https://www.umeng.com/){.doclink} 7 | [google analytics](https://analytics.google.com/){.doclink} 8 | [Umami](https://github.com/umami-software/umami){.doclink} 9 | -------------------------------------------------------------------------------- /content/docs/1000.standard-analyse/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 数据分析 2 | -------------------------------------------------------------------------------- /content/docs/20.design.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Design' 3 | description: '设计响应适配' 4 | navigation: 5 | icon: '/aside/design.png' 6 | title: 'Design' 7 | --- 8 | 9 | ## 响应适配 10 | 11 | ### 早期方案:UI设计宽度为980px 12 | ```html 13 | 18 | 19 | ``` 20 | 21 | ### 过渡方案:viewport 缩放比 22 | 23 | ```js 24 | // 动态设置 viewport 缩放比 25 | (function (designWidth) { 26 | const dEl = document.documentElement 27 | let meta = document.querySelector('meta[name=viewport]') 28 | 29 | if (!meta) { 30 | meta = document.createElement('meta') 31 | meta.setAttribute('name', 'viewport') 32 | document.head.appendChild(meta) 33 | } 34 | 35 | function setMetaContent() { 36 | const deviceWidth = dEl.clientWidth 37 | const scale = deviceWidth / designWidth 38 | const content = `width=${deviceWidth}, initial-scale=${scale}` 39 | meta.setAttribute('content', content) 40 | } 41 | setMetaContent() 42 | 43 | window.addEventListener('resize', setMetaContent) 44 | })(750) 45 | ``` 46 | 47 | ### 过渡方案:flexible + rem 48 | 49 | [lib-flexible 动态设置根字体](https://github.com/amfe/lib-flexible){.doclink} 50 | [postcss-pxtorem px转rem](https://github.com/cuth/postcss-pxtorem){.doclink} 51 | 52 | ::tabs 53 | --- 54 | tabs: ['bash', 'index.html', 'postcss.config.js', 'main.js'] 55 | --- 56 | 57 | #bash 58 | ```bash 59 | pnpm add amfe-flexible 60 | pnpm add -D postcss postcss-pxtorem 61 | ``` 62 | 63 | #index.html 64 | ```html 65 | 66 | ``` 67 | 68 | #postcss.config.js 69 | ```js 70 | module.exports = { 71 | plugins: { 72 | 'postcss-pxtorem': { 73 | // 设计稿的 1/10,750 -> 75 375 -> 37.5 74 | rootValue: 37.5, 75 | // 需要被转换的属性 76 | propList: ['*'], 77 | // 不进行px转换的选择器 78 | selectorBlackList: [], 79 | }, 80 | }, 81 | } 82 | ``` 83 | 84 | #main.js 85 | ```js 86 | import 'amfe-flexible/index.js' 87 | ``` 88 | :: 89 | 90 | ### 方案:autofit.js 自适应工具 91 | 92 | [autofit.js 自适应工具](https://github.com/LarryZhu-dev/autofit.js){.doclink} 93 |
94 | 95 | ### 方案:px转vw 96 | 97 | [postcss-px-to-viewport px转vw](https://github.com/evrone/postcss-px-to-viewport){.doclink} 98 | [vw 兼容方案](https://github.com/rodneyrehm/viewport-units-buggyfill?spm=ata.13261165.0.0.5c016ef2PzyaPL){.doclink} 99 |
100 | 101 | ### 方案:Tailwind CSS ⭐️ 102 | 103 | [Tailwind CSS](https://tailwindcss.com/){.doclink} 104 | [Responsive Design](https://tailwindcss.com/docs/responsive-design){.doclink} 105 |
106 | 107 | ### 方案:UnoCSS ⭐️ 108 | 109 | [UnoCSS](https://unocss.dev/){.doclink} 110 | [theme breakpoints](https://unocss.dev/config/theme#breakpoints){.doclink} 111 | 112 |
113 | 114 | ## 特殊场景情况 115 | 116 | ### 场景一:适配 Retina 屏 117 | 118 | ::tabs 119 | --- 120 | tabs: ['html', 'css'] 121 | --- 122 | 123 | #html 124 | ```html 125 | 129 | ``` 130 | 131 | #css 132 | ```css 133 | /* 关于图片 */ 134 | [data-dpr="1"] .logo { 135 | background-image: url(image@1x.jpg); 136 | } 137 | [data-dpr="2"] .logo { 138 | background-image: url(image@2x.jpg); 139 | } 140 | [data-dpr="3"] .logo { 141 | background-image: url(image@3x.jpg); 142 | } 143 | /* 1px 的问题 */ 144 | .u-border { 145 | position: relative; 146 | &::after { 147 | content: ""; 148 | position: absolute; 149 | bottom: 0px; 150 | left: 0px; 151 | right: 0px; 152 | border-top: 1px solid #666; 153 | transform: scaleY(0.5); 154 | } 155 | } 156 | ``` 157 | 158 | :: 159 | 160 | ### 场景二:适配图片不失真 161 | 162 | ```html 163 | 174 | 183 | 184 | 189 | 204 | ``` 205 | 206 | ### 场景三:适配 iPhoneX 安全区域 207 | 208 | ::tabs 209 | --- 210 | tabs: ['html', 'css'] 211 | --- 212 | 213 | #html 214 | ```html 215 | 216 | 217 | ``` 218 | 219 | #css 220 | ```css 221 | /* fixed 完全吸底元素场景的适配 */ 222 | /* 通过加内边距 padding 扩展高度 */ 223 | .container { 224 | padding-bottom: constant(safe-area-inset-bottom); 225 | padding-bottom: env(safe-area-inset-bottom); 226 | } 227 | /* fixed 非完全吸底元素场景的适配 */ 228 | .container { 229 | margin-bottom: constant(safe-area-inset-bottom); 230 | margin-bottom: env(safe-area-inset-bottom); 231 | } 232 | ``` 233 | :: 234 | 235 |
236 | 237 | ## 主题切换方案 238 | 239 | ### 方案一:CSS变量 + 类名切换 240 | 241 | ::tabs 242 | --- 243 | tabs: ['js', 'css'] 244 | --- 245 | 246 | #js 247 | ```js 248 | // 更改根目录类名 249 | function changeTheme(theme) { 250 | document.body.className = theme 251 | } 252 | ``` 253 | 254 | #css 255 | ```css 256 | /* 定义根作用域下默认变量 */ 257 | :root { 258 | --theme-color: #333; 259 | --theme-background: #eee; 260 | } 261 | /* 暗夜模式下变量 */ 262 | .dark { 263 | --theme-color: #eee; 264 | --theme-background: #333; 265 | } 266 | 267 | .container { 268 | color: var(--theme-color); 269 | background: var(--theme-background); 270 | } 271 | ``` 272 | :: 273 | 274 | ### 方案二:v-bind 275 | 276 | ```vue 277 | 282 | 283 | 286 | 287 | 292 | ``` 293 | 294 | ### 方案三:SCSS变量 + 类名切换 295 | 296 | ::tabs 297 | --- 298 | tabs: ['theme-default.scss', 'theme-red.scss', 'index.scss', 'js'] 299 | --- 300 | 301 | #theme-default.scss 302 | ```css 303 | [data-theme=default] { 304 | --color-primary: #516BD9; 305 | } 306 | ``` 307 | 308 | #theme-red.scss 309 | ```css 310 | [data-theme=red] { 311 | --color-primary: #DF291E; 312 | } 313 | ``` 314 | 315 | #index.scss 316 | ```css 317 | $--color-primary: var(--color-primary) !default; 318 | ``` 319 | 320 | #js 321 | ```js 322 | document.documentElement.setAttribute('data-theme', 'default') 323 | ``` 324 | :: 325 | 326 | ### 方案四:CSS变量 + 动态setProperty 327 | 328 | ::tabs 329 | --- 330 | tabs: ['css', 'js'] 331 | --- 332 | 333 | #css 334 | ```css 335 | /* 全局中设置好预设的全局CSS变量样式 */ 336 | :root { 337 | --theme-color: #333; 338 | --theme-background: #eee; 339 | } 340 | ``` 341 | 342 | #js 343 | ```js 344 | /** 345 | * attr 预设变量属性 eg. --theme-color --theme-background ... 346 | * val 设置的值 eg. #fff 100px ... 347 | */ 348 | function setCssVar(attr, val, dom = document.documentElement) { 349 | dom.style.setProperty(prop, val) 350 | } 351 | // 调用函数修改指定的CSS变量值 352 | setCssVar('--theme-color', '#fff') 353 | ``` 354 | :: 355 | 356 | ### 方案五:filter 357 | 358 | ```css 359 | body { 360 | /* 改变整体色调 */ 361 | filter: hue-rotate(45deg); 362 | /* 悼念色 */ 363 | /* filter: grayscale(1); */ 364 | } 365 | ``` 366 | 367 |
368 | 369 | ## ICON 370 | 371 | ### 方案一:Iconfont 372 | 373 | [Iconfont](https://www.iconfont.cn/){.doclink} 374 | [Web 端使用](https://www.iconfont.cn/help/detail?spm=a313x.help_detail.i1.d8d11a391.24b33a81WeTzjy&helptype=code){.doclink} 375 |
376 | 377 | ### 方案二:UnoCSS Icons ⭐️ 378 | 379 | [UnoCSS Icons](https://unocss.dev/presets/icons){.doclink} 380 | [all available icons](https://icones.js.org/){.doclink} 381 | 382 |
383 | 384 | ## 参考 385 | 386 | ### 设计工具 387 | 388 | [Figma](https://www.figma.com/){.doclink} 389 | [摹客](https://www.mockplus.cn/){.doclink} 390 | [Sketch](https://www.sketch.com/){.doclink} 391 |
392 | 393 | ### 屏幕尺寸 394 | 395 | [尺寸直观图](https://screensizemap.com/){.doclink} 396 | [尺寸参数大全](https://uiiiuiii.com/screen/index.htm){.doclink} 397 | [纸张尺寸转换](https://www.papersizes.org/a-paper-sizes.htm){.doclink} 398 |
399 | 400 | ### 设计规范 401 | 402 | [超人的电话亭UI设计师知识库](https://weeks-fix-dzb.craft.me/QtMOVu7kcubeUf){.doclink} 403 |
404 | 405 | ### 设计资源及灵感 406 | 407 | [cbc.design](https://uxchi.notion.site/Hey-I-m-Chi-8e9115aa3de44ae0857d402ace47d076){.doclink} 408 | [优设](https://hao.uisdc.com/){.doclink} 409 | [saaspo](https://www.saaspo.com/){.doclink} 410 | [refto](https://refto.one/){.doclink} 411 | [MFSC123.COM](https://www.mfsc123.com/){.doclink} 412 |
413 | -------------------------------------------------------------------------------- /content/docs/200.standard-code/.5.tsconfig.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'tsconfig' 3 | description: 'TypeScript配置指南' 4 | --- 5 | -------------------------------------------------------------------------------- /content/docs/200.standard-code/1.vscode.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'vscode' 3 | description: 'vscode配置及拓展' 4 | --- 5 | 6 | ## vscode 7 | 8 | ### settings and extensions 9 | 10 | [LOUSANPANG's VS Code Settings](https://github.com/LOUSANPANG/vscode-settings){.doclink} 11 | [Anthony's VS Code Settings](https://github.com/antfu/vscode-settings){.doclink} 12 | 13 | ```bash 14 | .vscode/ 15 | |- extensions.json # 插件 16 | |- setting.json # 配置 17 | |- global.code-snippets # 代码片段 18 | .editorconfig # 跨编辑器代码配置 19 | ``` 20 | 21 |
22 | 23 | ## .editorconfig 24 | 25 | [EditorConfig](http://EditorConfig.org){.doclink} 26 | 27 | ```bash 28 | # EditorConfig is awesome: http://EditorConfig.org 29 | 30 | # top-most EditorConfig file 31 | root = true 32 | 33 | [*.md] 34 | insert_final_newline = false 35 | trim_trailing_whitespace = false 36 | 37 | # Unix-style newlines with a newline ending every file 38 | [*] 39 | charset = utf-8 40 | indent_style = space 41 | indent_size = 2 42 | trim_trailing_whitespace = true # 去除行首的任意空白字符 43 | end_of_line = lf # 控制换行类型(lf | cr | crlf) 44 | insert_final_newline = true # 始终在文件末尾插入一个新行 45 | max_line_length = 100 46 | ``` 47 | -------------------------------------------------------------------------------- /content/docs/200.standard-code/2.eslint.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'ESlint' 3 | description: 'ESlint配置使用指南' 4 | --- 5 | 6 | ## 他人配置方案 7 | 8 | ### 方案一:@antfu/eslint-config 9 | 10 | [Anthony's ESLint config](https://github.com/antfu/eslint-config){.doclink} 11 | 12 |
13 | 14 | ## 手动配置方案 15 | 16 | ::tabs 17 | --- 18 | tabs: [ 'bash', 'package.json', 'eslint.config.js', 'vscode' ] 19 | --- 20 | 21 | #bash 22 | ```bash 23 | pnpm add -D eslint 24 | 25 | npx eslint --init 26 | ``` 27 | 28 | #package.json 29 | ```json 30 | { 31 | "scripts": { 32 | "lint": "npx eslint --ext .js,.jsx,.ts,.tsx src", 33 | "lint-fix": "npx eslint --fix --ext .js,.jsx,.ts,.tsx src" 34 | } 35 | } 36 | ``` 37 | 38 | #eslint.config.js 39 | ```js 40 | // https://eslint.org/docs/latest/use/configure/ 41 | module.exports = { 42 | root: true, 43 | env: {}, 44 | globals: {}, 45 | parser: '', 46 | parserOptions: { 47 | ecmaFeatures: { 48 | jsx: true, 49 | }, 50 | }, 51 | plugins: [], 52 | extends: [], 53 | rules: { 54 | 'semi': 'off', 55 | 'comma-dangle': 'off', 56 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 57 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 58 | }, 59 | ignores: ['dist', 'node_modules'], 60 | } 61 | ``` 62 | 63 | #vscode 64 | ```json 65 | // 添加 vscode ESLint 插件 66 | // "dbaeumer.vscode-eslint" 67 | 68 | // 配置setting.json 69 | { 70 | "editor.formatOnSave": true, 71 | "editor.codeActionsOnSave": { 72 | "source.fixAll.eslint": true 73 | } 74 | } 75 | ``` 76 | 77 | :: 78 | -------------------------------------------------------------------------------- /content/docs/200.standard-code/3.prettier.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Prettier' 3 | description: 'Prettier配置使用指南' 4 | --- 5 | 6 | ## 手动配置方案 7 | 8 | [prettier](https://prettier.io/){.doclink} 9 | 10 | ::tabs 11 | --- 12 | tabs: [ 'bash', 'eslintrc', 'prettierrc', 'vscode' ] 13 | --- 14 | 15 | #bash 16 | ```bash 17 | pnpm add -D prettier 18 | 19 | # eslint-config-prettier 禁用掉所有和 prettier 冲突的规则 20 | pnpm add -D eslint-config-prettier 21 | 22 | # eslint-plugin-prettier 以符合 eslint 规则的方式格式化代码并提示对应的修改建议 23 | pnpm add -D eslint-plugin-prettier 24 | ``` 25 | 26 | #eslintrc 27 | ```json 28 | // .eslintrc 29 | { 30 | "extends": ["plugin:prettier/recommended"] 31 | } 32 | ``` 33 | 34 | #prettierrc 35 | ```json 36 | { 37 | "bracketSpacing": true, 38 | "semi": false, 39 | "tabWidth": 2, 40 | "proseWrap": "never", 41 | "endOfLine": "auto", 42 | "printWidth": 100, 43 | "singleQuote": true, 44 | "trailingComma": "none", 45 | "vueIndentScriptAndStyle": true, 46 | "htmlWhitespaceSensitivity": "strict" 47 | } 48 | ``` 49 | 50 | #vscode 51 | ```bash 52 | # 添加 Prettier 插件 53 | # esbenp.prettier-vscode 54 | ``` 55 | 56 | :: 57 | -------------------------------------------------------------------------------- /content/docs/200.standard-code/4.stylelint.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Stylelint' 3 | description: 4 | --- 5 | 6 | ## 手动配置方案 7 | 8 | [Stylelint](https://stylelint.io/){.doclink} 9 | 10 | ::tabs 11 | --- 12 | tabs: [ 'bash', 'stylelintrc', 'package.json', 'vscode' ] 13 | --- 14 | 15 | #bash 16 | ```bash 17 | # stylelint-config-standard 标准配置 18 | pnpm add stylelint stylelint-config-standard -D 19 | 20 | # 【可选】排序扩展 21 | pnpm add stylelint-order -D 22 | # 【可选】规范的排序扩展 23 | pnpm add stylelint-config-rational-order -D 24 | 25 | # 【可选】支持校验scss语法的插件 26 | pnpm add stylelint-scss -D 27 | ``` 28 | 29 | #stylelintrc 30 | ```json 31 | { 32 | "extends": [ 33 | "stylelint-config-standard", 34 | "stylelint-config-rational-order" // 可选 35 | ], 36 | "plugins": [ 37 | "stylelint-scss" // 可选 38 | ], 39 | "rules": { 40 | // stylelint-config-rational-order 规则 41 | // 1.Positioning 位置属性 42 | // 2.Box Model 盒子属性 43 | // 3.Typography 文字属性 44 | // 4.Visual 视觉属性 45 | // 5.Animation Misc 其他 46 | 47 | // 与 prettier 规则冲突 48 | "declaration-block-trailing-semicolon": null 49 | }, 50 | "ignoreFiles": ["build", "dist", "node_modules"] 51 | } 52 | ``` 53 | 54 | #package.json 55 | ```json 56 | { 57 | "scripts": { 58 | "lint:style": "stylelint {components,src}**/*.{vue,html,css,sss,less,scss,sass}", 59 | "fix:style": "stylelint {components,src}**/*.{vue,html,css,sss,less,scss,sass} --fix" 60 | } 61 | } 62 | ``` 63 | 64 | #vscode 65 | ```json 66 | // 添加 stylelint 插件 67 | // stylelint.vscode-stylelint 68 | 69 | // 配置 setting.json 自动格式化 70 | { 71 | "editor.formatOnSave": true, 72 | "editor.codeActionsOnSave": { 73 | "source.fixAll.stylelint": true 74 | } 75 | } 76 | ``` 77 | 78 | :: 79 | -------------------------------------------------------------------------------- /content/docs/200.standard-code/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 编码规范 2 | -------------------------------------------------------------------------------- /content/docs/2000.toolbox/1.mac.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Mac 工具箱' 3 | --- 4 | 5 | ## 工程师 Mac 工具箱 6 | 7 | ### 网络安全 8 | 9 | [魔戒(科学上网工具)](https://mojie.app/dashboard){.doclink} 10 | [西游(科学上网工具)](https://sunwk.fun/i/){.doclink} 11 | [1Password(密码管理工具)](https://1password.com/){.doclink} 12 | 13 | ### 开发 14 | 15 | [Warp(终端)](https://www.warp.dev/){.doclink} 16 | [Homebrew(命令行包管理器工具)](https://brew.sh/){.doclink} 17 | [Oh My Zsh(命令行工具)](https://ohmyz.sh/){.doclink} 18 | [Git](https://git-scm.com/){.doclink} 19 | [Node.js](https://nodejs.org/){.doclink} 20 | [nvm(Node.js 版本管理工具)](https://github.com/nvm-sh/nvm){.doclink} 21 | [volta(代替 nvm 的node版本管理工具)](https://github.com/volta-cli/volta){.doclink} 22 | [Navicat(数据库管理工具)](https://www.navicat.com.cn/){.doclink} 23 | [Termius(SSH工具)](https://termius.com/){.doclink} 24 | [VSCode](https://code.visualstudio.com/){.doclink} 25 | [IDEA](https://www.jetbrains.com/idea/){.doclink} 26 | [HBuilderX](https://www.dcloud.io/hbuilderx.html){.doclink} 27 | [Charles(抓包工具)](https://www.charlesproxy.com/){.doclink} 28 | 29 | ### 生产力 30 | 31 | [Chrome](https://www.google.com/chrome/){.doclink} 32 | [Bob(翻译工具)](https://github.com/ripperhe/Bob){.doclink} 33 | [snipaste](https://zh.snipaste.com/){.doclink} 34 | 35 | ### 设计 36 | 37 | [Sketch(设计工具)](https://www.sketch.com/){.doclink} 38 | [Figma(设计工具)](https://www.figma.com/){.doclink} 39 | [Adobe(Adobe全家桶)](https://www.superso.top/Adobe/){.doclink} 40 | 41 | ### 影像相关 42 | 43 | [Downie(视频下载工具)](https://software.charliemonroe.net/downie/){.doclink} 44 | [IINA(视频播放器)](https://iina.io/){.doclink} 45 | [Kap(屏幕录制工具)](https://getkap.co/){.doclink} 46 | 47 | ### 生活 48 | 49 | [同花顺](https://www.10jqka.com.cn/){.doclink} 50 | 51 | ## 参考链接 52 | 53 | [终极一站式教程](https://44maker.github.io/wiki/Mac/index.html){.doclink} 54 | -------------------------------------------------------------------------------- /content/docs/2000.toolbox/2.windows.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'windows 工具箱' 3 | --- 4 | 5 | ## 工程师 Windows 工具箱 6 | 7 | ### 网络安全 8 | 9 | [魔戒(科学上网工具)](https://mojie.app/dashboard){.doclink} 10 | [西游(科学上网工具)](https://sunwk.fun/i/){.doclink} 11 | 12 | ### 开发 13 | 14 | [Oh My Zsh](https://ohmyz.sh/){.doclink} 15 | [Git](https://git-scm.com/){.doclink} 16 | [Node.js](https://nodejs.org/){.doclink} 17 | [nvm(Node.js 版本管理工具)](https://github.com/nvm-sh/nvm){.doclink} 18 | [Navicat(数据库管理工具)](https://www.navicat.com.cn/){.doclink} 19 | [XShell(SSH工具)](https://www.xshell.com/zh/xshell/){.doclink} 20 | [XFtp(网络传输文件)](https://www.xshell.com/zh/xftp/){.doclink} 21 | [Redis Desktop Manager(Redis 可视化管理工具)](https://github.com/uglide/RedisDesktopManager){.doclink} 22 | [VSCode](https://code.visualstudio.com/){.doclink} 23 | [IDEA](https://www.jetbrains.com/idea/){.doclink} 24 | [HBuilderX](https://www.dcloud.io/hbuilderx.html){.doclink} 25 | [Charles(抓包工具)](https://www.charlesproxy.com/){.doclink} 26 | 27 | ### 生产力 28 | 29 | [Chrome](https://www.google.com/chrome/){.doclink} 30 | [snipaste](https://zh.snipaste.com/){.doclink} 31 | 32 | ### 设计 33 | 34 | [Sketch(设计工具)](https://www.sketch.com/){.doclink} 35 | [Figma(设计工具)](https://www.figma.com/){.doclink} 36 | [Adobe(Adobe全家桶)](https://www.superso.top/Adobe/){.doclink} 37 | 38 | ### 生活 39 | 40 | [同花顺](https://www.10jqka.com.cn/){.doclink} 41 | -------------------------------------------------------------------------------- /content/docs/2000.toolbox/3.tv.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'tv 工具箱' 3 | --- 4 | 5 | ## 工程师 Tv 工具箱 6 | 7 | ### 网络安全 8 | 9 | [魔戒(科学上网工具)](https://mojie.app/dashboard){.doclink} 10 | [西游(科学上网工具)](https://sunwk.fun/i/){.doclink} 11 | 12 | ### 影像相关 13 | 14 | [一席(演讲类)](https://yixi.tv/#/home){.doclink} 15 | [netflix()](https://www.netflix.com/){.doclink} 16 | 17 | ### 电视直播 18 | 19 | [IPTV](https://iptv-org.github.io/iptv/index.m3u){.doclink} 20 | [my-tv](https://github.com/lizongying/my-tv){.doclink} 21 | -------------------------------------------------------------------------------- /content/docs/2000.toolbox/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 软件工具箱 2 | -------------------------------------------------------------------------------- /content/docs/300.standard-commit/1.husky-lintstaged.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'husky&lintstaged' 3 | --- 4 | 5 | ## Husky、lint-staged 6 | 7 | ::tabs 8 | --- 9 | tabs: [ 'bash', 'package.json', 'husky' ] 10 | --- 11 | 12 | #bash 13 | ```bash 14 | pnpm add -D husky lint-staged 15 | 16 | pnpm exec husky init 17 | 18 | echo "npx lint-staged" > .husky/pre-commit 19 | ``` 20 | 21 | #package.json 22 | ```json 23 | { 24 | "scripts": { 25 | "prepare": "husky" 26 | }, 27 | "lint-staged": { 28 | "*": "eslint --fix" 29 | } 30 | } 31 | ``` 32 | 33 | #husky 34 | ```bash 35 | # .husky/pre-commit 36 | npx lint-staged 37 | ``` 38 | 39 | :: 40 | 41 |
42 | 43 | ## 参考链接 44 | 45 | [Husky](https://github.com/typicode/husky){.doclink} 46 | 47 | [lint-staged](https://github.com/lint-staged/lint-staged){.doclink} 48 | 49 | [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks){.doclink} 50 | -------------------------------------------------------------------------------- /content/docs/300.standard-commit/2.commitizen-commitlint.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'commitizen&commitlint' 3 | --- 4 | 5 | ## 检测commit备注规范 6 | 7 | ### commitlint 8 | 9 | ::tabs 10 | --- 11 | tabs: [ 'bash', 'commitlint.config.js', 'husky' ] 12 | --- 13 | 14 | #bash 15 | ```bash 16 | # lint commit messages 17 | pnpm add @commitlint/cli -D 18 | 19 | # 一份符合 Angular 团队规范校验的配置 20 | pnpm add @commitlint/config-conventional -D 21 | 22 | # 配置husky监听commit-msg 23 | npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"' 24 | ``` 25 | 26 | #commitlint.config.js 27 | ```js 28 | // commitlint.config.js 29 | module.exports = { 30 | extends: ['@commitlint/config-conventional'], 31 | rules: { 32 | 'type-enum': [ 33 | 2, 34 | 'always', 35 | [ 36 | 'feat', // 新功能 feature 37 | 'fix', // 修复 bug 38 | 'docs', // 文档注释 39 | 'style', // 代码格式(不影响代码运行的变动) 40 | 'refactor', // 重构(既不增加新功能,也不是修复bug) 41 | 'perf', // 性能优化 42 | 'test', // 增加测试 43 | 'chore', // 构建过程或辅助工具的变动 44 | 'revert', // 回退 45 | 'build', // 打包 46 | ], 47 | ], 48 | // subject 大小写不做校验 49 | 'subject-case': [0], 50 | }, 51 | } 52 | ``` 53 | 54 | #husky 55 | ```bash 56 | # .husky/commit-msg 57 | npx --no-install commitlint --edit "$1" 58 | ``` 59 | :: 60 | 61 |
62 | 63 | ## 添加commit辅助备注信息 64 | 65 | ### commitizen 66 | 67 | ::tabs 68 | --- 69 | tabs: [ 'bash', 'package.json', 'cz-config.js' ] 70 | --- 71 | 72 | #bash 73 | ```bash 74 | # git cz 替代 git commit,生成符合规范的 commit message。 75 | pnpm add -D commitizen 76 | 77 | # 指定一套符合自己团队的规范代替 Angular 规范 78 | pnpm add -D cz-customizable 79 | ``` 80 | 81 | #package.json 82 | ```json 83 | { 84 | "config": { 85 | "commitizen": { 86 | "path": "node_modules/cz-customizable" 87 | } 88 | } 89 | } 90 | ``` 91 | 92 | #cz-config.js 93 | ```js 94 | // .cz-config.js 95 | 'use strict' 96 | module.exports = { 97 | messages: { 98 | type: '选择你要提交的类型:', 99 | scope: '选择一个提交范围(可选):', 100 | customScope: '请输入自定义的提交范围(可选):', 101 | subject: '填写简短精炼的变更描述:\n', 102 | // body: '填写更加详细的变更描述(可选)。使用 "|" 换行:\n', 103 | // breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行:\n', 104 | // footerPrefixsSelect: '选择关联issue前缀(可选):', 105 | // customFooterPrefixs: '输入自定义issue前缀:', 106 | // footer: '列举关联issue (可选) 例如: #31, #I3244:\n', 107 | confirmCommit: '是否提交或修改commit?', 108 | }, 109 | 110 | types: [ 111 | { value: 'feat', name: 'feat: 新增功能' }, 112 | { value: 'fix', name: 'fix: 修复 bug' }, 113 | { value: 'docs', name: 'docs: 文档变更' }, 114 | { value: 'style', name: 'style: 代码格式(不影响功能,例如空格、分号等格式修正)' }, 115 | { value: 'refactor', name: 'refactor: 代码重构(不包括 bug 修复、功能新增)' }, 116 | { value: 'perf', name: 'perf: 性能优化' }, 117 | { value: 'test', name: 'test: 添加、修改测试用例' }, 118 | { value: ' build', name: 'build: 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)' }, 119 | { value: 'ci', name: 'ci: 修改 CI 配置、脚本' }, 120 | { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' }, 121 | { value: 'revert', name: 'revert: 回滚 commit' }, 122 | ], 123 | 124 | scopes: [ 125 | ['view', '页面相关'], 126 | ['components', '组件相关'], 127 | ['utils', 'utils 相关'], 128 | ['styles', '样式相关'], 129 | ['deps', '项目依赖'], 130 | ['workflows', '部署相关'], 131 | ['md', '文档相关'], 132 | ['other', '其他修改'], 133 | ['custom', '以上都不是?我要自定义'], // 如果选择 custom,后面会让你再输入一个自定义的 scope。也可以不设置此项,把后面的 allowCustomScopes 设置为 true 134 | ].map(([value, description]) => { 135 | return { 136 | value, 137 | name: `${value.padEnd(30)} (${description})`, 138 | } 139 | }), 140 | 141 | subjectLimit: 100, // subject 限制长度 142 | skipQuestions: ['body', 'footer'], // 跳过问题:详细描述 issue相关 143 | } 144 | ``` 145 | :: 146 | 147 |
148 | 149 | ## 指定规范生成CHANGELOG 150 | 151 | ### conventional-changelog 152 | 153 | ::tabs 154 | --- 155 | tabs: [ 'bash', 'package.json' ] 156 | --- 157 | 158 | #bash 159 | ```bash 160 | # 一个符合 Angular 团队规范的 preset,按照我们指定的规范生成 commit message。 161 | pnpm add -D cz-conventional-changelog 162 | 163 | # 【可选】全局模式下, 需要 ~/.czrc 配置文件, 为 commitizen 指定 Adapter。 164 | echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc 165 | ``` 166 | 167 | #package.json 168 | ```json 169 | { 170 | "config": { 171 | "commitizen": { 172 | "path": "node_modules/cz-conventional-changelog" 173 | } 174 | } 175 | } 176 | ``` 177 | :: 178 | -------------------------------------------------------------------------------- /content/docs/300.standard-commit/3.changelog.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'changelog' 3 | --- 4 | 5 | ### 生成提交日志 6 | 7 | ::tabs 8 | --- 9 | tabs: [ 'bash', 'package.json' ] 10 | --- 11 | 12 | #bash 13 | ```bash 14 | pnpm add standard-version -D 15 | ``` 16 | 17 | #package.json 18 | ```json 19 | { 20 | "scirpt": { 21 | "release": "standard-version", // 默认 更新patch 22 | // --release-as === -r 指定版本号 23 | // standard-version -r 2.0.0-test // 自定义修改版本 24 | "release:major": "standard-version -r major -n", // 更新主版本 1.0.0 -> 2.0.0 25 | "release:minor": "standard-version -r minor -n", // 更新次版本 1.0.0 -> 1.1.0 26 | "release:patch": "standard-version -r patch -n", // 更新修订版 1.0.0 -> 1.0.1 27 | // --prerelease === -p 预发版本命名 28 | "prerelease:alpha": "standard-version -p alpha -n", // 更新alpha 1.0.0 -> 1.0.0-alpha.0 【再次执行 -alpha.0 -> -alpha.1】 29 | "prerelease:beta": "standard-version -p beta -n", // 更新beta 1.0.0 -> 1.0.0-beta.0 30 | "prerelease:rc": "standard-version -p rc -n" // 更新rc 1.0.0 -> 1.0.0-rc.0 31 | // --tag-prefix === -t 版本 tag 前缀 32 | // standard-version --tag-prefix "stable-" // 1.0.0 -> stable-v1.0.0 33 | // 查看更多命令 34 | // standard-version --help 35 | } 36 | } 37 | ``` 38 | 39 | :: 40 | 41 | ### 语义化版本规范 42 | 43 | [语义化版本 semver](https://semver.org/){.doclink} 44 | 45 | ```bash 46 | # alpha: 内部测试版本, 一般不向外部公开, 会有很多 bug, 也可能随时删除 47 | # beta: 公测版本, 会有一些 bug, 但是基本上可以在 API 不大变的情况下进行升级 48 | # rc: 也叫做 gamma, 代表发行候选版本, 也就是在 beta 版本中没有发现 bug, 随时都可能发布正式版本 49 | # stable: 稳定版本, 一般不再对这个版本进行功能性修改, 只修复 bug 50 | 51 | Example: 52 | 1.0.0 53 | 1.0.0-stable 54 | 1.0.0-rc.1 55 | 1.0.0-rc 56 | 1.0.0-beta.1 57 | 1.0.0-beta 58 | 1.0.0-alpha.beta 59 | 1.0.0-alpha.985211 60 | 1.0.0-alpha.1 61 | 1.0.0-alpha 62 | ``` 63 | -------------------------------------------------------------------------------- /content/docs/300.standard-commit/4.git.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Git技巧' 3 | description: 'Git实战技巧' 4 | --- 5 | 6 | ## 账户配置 7 | 8 | ### 配置全局账户 9 | 10 | ```bash 11 | git config --global user.name "xxx" 12 | git config --global user.email "" 13 | ``` 14 | 15 | ### 配置本地账户 16 | 17 | ```bash 18 | git config user.name "xxx" 19 | git config user.email "" 20 | ``` 21 | 22 | ### SSH 本地配置多个Git账户 23 | 24 | ```bash 25 | # 步骤一:为每个Git账号生成一个SSH密钥对 26 | ssh-keygen -t rsa -C "youremail_github@example.com" -f ~/.ssh/id_rsa_github_user1 27 | ssh-keygen -t rsa -C "youremail_github@example.com" -f ~/.ssh/id_rsa_github_user2 28 | 29 | # 步骤二:配置SSH客户端 30 | # 编辑~/.ssh/config文件: 31 | touch ~/.ssh/config 32 | open ~/.ssh/config 33 | 34 | # 在~/.ssh/config文件中,为每个Git服务添加配置: 35 | # GitHub account 36 | Host github_user1 37 | HostName github.com 38 | User git 39 | IdentityFile ~/.ssh/id_rsa_github_user1 40 | Host github_user2 41 | HostName github.com 42 | User git 43 | IdentityFile ~/.ssh/id_rsa_github_user2 44 | 45 | # 步骤三:将公钥添加到对应的Git账号中 46 | # 复制到对应 GitHub Gitee GitLab 的SSH key设置页面中 47 | cat ~/.ssh/id_rsa_github_user1.pub 48 | cat ~/.ssh/id_rsa_github_user2.pub 49 | 50 | # 测试SSH连接: ssh -T [config文件配置的User]@[config文件配置的Host] 51 | ssh -T git@github_user1 52 | ssh -T git@github_user2 53 | 54 | # clone 远程仓库 55 | SSH远程地址:git@github.com:[用户名]/[仓库地址].git 56 | 改成:git@[ssh config 配置的 HOST]:[用户名]/[仓库地址].git 57 | 58 | # 多账号使用问题:指向SSH仓库地址 59 | git remote set-url origin git@gitee.com:[用户名]/[仓库地址].git 60 | ``` 61 | 62 |
63 | 64 | ## 命名&操作 65 | 66 | ### 分支命名 67 | 68 | ```bash 69 | feature/xxx # 功能分支 70 | bugfix/xxx # bug修复分支 71 | hotfix/xxx # 紧急修复分支 72 | release/xxx # 发布分支 73 | ``` 74 | 75 | ### 查看日志 76 | 77 | ```bash 78 | git log # 查看提交历史,包括所有分支和标签的提交记录 79 | git log --oneline # 查看简约版历史记录 80 | git log --graph # 查看分支合并图 81 | git reflog # 查看 git 引用日志,查看 HEAD 移动和操作 82 | ``` 83 | 84 | ### vim 编辑器 85 | 86 | ```bash 87 | # 按 i 进入编辑模式,按 ESC 退出编辑模式 88 | # :wq 保存并退出 89 | # :q! 不保存退出 90 | # 修改commit的记录 91 | ``` 92 | 93 |
94 | 95 | ## commit 96 | 97 | ### 文件名大小写敏感问题 98 | 99 | ```bash 100 | git config core.ignorecase false 101 | ``` 102 | 103 | ### 暂存区存储、恢复 104 | 105 | ```bash 106 | git stash # 把当前工作现场“储藏”起来 107 | git stash pop # 恢复储藏内容 108 | git stash list # 查看储存列表 109 | git stash apply stash@{0} # 多次stash后,恢复指定的stash 110 | ``` 111 | 112 | ### 合并 commit 113 | 114 | ```bash 115 | # 1、使用命令打开文本编辑器,会出现最近的commit历史(顶部为旧记录) 116 | git rebase -i HEAD~2 # 合并最近两次commit 117 | # 2、将需要合并的commit前面的pick改为s 118 | # 3、保存退出 :wq 119 | # 4、会出现一个新的文本编辑器,将需要合并的commit信息合并 120 | # 5、保存退出 :wq 121 | # 6、会出现冲突,可以强制push 122 | $ git push -f 123 | ``` 124 | 125 |
126 | 127 | ## 分支 128 | 129 | ### 分支操作 130 | 131 | ```bash 132 | git branch # 创建分支 133 | git checkout || git switch # 切换分支 134 | git checkout -b || git switch -c # 创建并切换分支 135 | git branch -d # 删除分支 136 | git branch -D # 强行删除分支 137 | git push origin --delete # 删除远程分支 138 | ``` 139 | 140 | ### 合并分支 141 | 142 | ```bash 143 | git cherry-pick # 复制一个特定的提交到当前分支 144 | 145 | # 合并方式一:merge 146 | # merge 会把合并前的分支的提交历史原封不动的拷贝过来 147 | git merge # 合并分支 148 | git merge --no-ff -m # 在合并分支时添加合并描述 149 | 150 | # 合并方式二:rebase merge 151 | # 保留提交的作者信息,同时可以合并commit历史 152 | # 完美的解决了 squash merge 定位不到原开发者的问题 153 | git checkout dev 154 | git rebase -i master # 通过 vi 手动调整commit历史 155 | git checkout master 156 | git merge dev 157 | ``` 158 | 159 | ### 撤销最近的一次合并 160 | 161 | ```bash 162 | git reflog # 查看 Git 操作历史 163 | git reset --hard HEAD~1 # 方式一:完全丢弃你的更改 164 | git reset --soft HEAD~1 # 方式二:保留你的更改,并将它们移回工作区 165 | git push -f origin # 强制推送你的更改到远程仓库 166 | ``` 167 | 168 |
169 | 170 | ## 发布 171 | 172 | ### 打 tag 标签 173 | 174 | ```bash 175 | git tag # 列出所有 tag 176 | git tag -a stable-v1.0.0 -m 'xx功能需求稳定版本1.0.0' # 添加 tag 177 | git tag -d # 删除某个标签 178 | git show # 显示标签对应提交记录的具体信息 179 | git push # 推送某个标签到远程仓库 180 | git push --delete # 删除远程仓库中的某个标签 181 | ``` 182 | -------------------------------------------------------------------------------- /content/docs/300.standard-commit/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 提交规范 2 | -------------------------------------------------------------------------------- /content/docs/400.standard-dev/0.html.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'html' 3 | description: '关于 HTML5 标签元素、api' 4 | --- 5 | 6 | ## 元素语义化 7 | 8 | ### 元素语义化好处 9 | 10 | - 利于 SEO(搜索引擎优化) 11 | - 利于无障碍访问 12 | - 利于浏览器的插件分析网页 13 | 14 | [HTML5 标签含义之元素周期表](https://www.xuanfengge.com/funny/html5/element/){.doclink} 15 | 16 | ### 资源提示符 17 | 18 | 优化网页性能,减少加载时间 19 | 20 | - async:异步加载 JS,加载完立即执行(适用于独立、不依赖 DOM 的脚本) 21 | - defer:异步加载 JS,DOM 解析后按顺序执行(适用于需要按顺序执行的 JS) 22 | - preload:预加载当前页面关键资源(字体、CSS、JS、视频) 23 | - prefetch:预取未来可能需要的资源(下一页的 JS、CSS、图片等) 24 | - dns-prefetch:提前解析域名(适用于跨域资源,如 CDN) 25 | - preconnect:提前建立连接(适用于远程 API、CDN 资源) 26 | - prerender:预渲染整个页面(适用于高概率访问的下一页) 27 | ```html 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ``` 43 | -------------------------------------------------------------------------------- /content/docs/400.standard-dev/1.var.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'var' 3 | description: '关于变量、参数、函数、类名等命名规范' 4 | --- 5 | 6 | ## CSS 7 | 8 | ### BEM 命名规范 9 | 10 | ::card 11 | BEM:块(block)、元素(element)、修饰符(modifier)。 12 | 中划线(-):块与块、元素与元素,多个单词之间的连接。 13 | 单下划线(_):块、元素的状态。 14 | 双下划线(__):块与元素之间的连接。 15 | 16 | 布局(.g-)、模块(.m-)、元件(.u-)、功能(.f-)、皮肤(.f-)、状态(.z-) 17 | :: 18 | 19 | ### 属性规范 20 | 21 | ::card 22 | 布局定位属性:display / position / float / clear / visibility / overflow 23 | 自身属性:width / height / margin / padding / border / background 24 | 文本属性:color / font / text-decoration / text-align / vertical-align / white- space / break-word 25 | 其他属性(CSS3):content / cursor / border-radius / box-shadow / text-shadow / background: linear-gradient 26 | :: 27 | 28 |
29 | 30 | ## JS 31 | 32 | ### 变量 33 | 34 | ```js 35 | // 命名方法:camelCase 36 | // 命名规范:类型 + 对象描述或属性的方式 37 | 38 | // bad 39 | const getTitle = 'LoginTable' 40 | // good 41 | const tableTitle = 'LoginTable' 42 | ``` 43 | 44 | ### 常量 45 | 46 | ```js 47 | // 命名方法:全部大写下划线分割 48 | const MAX_COUNT = 10 49 | const URL = 'http://test.host.com' 50 | ``` 51 | 52 | ### 方法 53 | 54 | ```bash 55 | # 命名方法:camelCase 56 | # 命名规范:动词 + 名词形式 57 | # can has is get set 58 | 59 | # 1、普通情况下,使用动词 + 名词形式 60 | # bad 61 | go、nextPage、show、open、login 62 | # good 63 | jumpPage、openCarInfoDialog 64 | 65 | # 2、请求数据方法,以 data 结尾 66 | # bad 67 | takeData、confirmData、getList、postForm 68 | # good 69 | getListData、postFormData 70 | 71 | # 3、单个动词的情况 72 | init、refresh 73 | ``` 74 | -------------------------------------------------------------------------------- /content/docs/400.standard-dev/2.notes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '注释规范' 3 | --- 4 | 5 | ## 文档注释 6 | 7 | [vscode 插件](https://marketplace.visualstudio.com/items?itemName=OBKoro1.korofileheader){.doclink} 8 | 9 | ```js 10 | /* 11 | * 简述当前文件功能 12 | * @author 作者名称 13 | * @version 版本号 最近编辑时间 14 | * @description 该版本改动信息 15 | */ 16 | ``` 17 | 18 |
19 | 20 | ## HTML 注释规范 21 | 22 | ### 模块注释 23 | ```html 24 | 25 |
26 | ... 27 |
28 | 29 | 30 | 31 |
32 | ... 33 |
34 | 35 | ``` 36 | 37 | ### 嵌套模块 38 | ```html 39 | 40 |
41 | 42 |
43 | ... 44 |
45 | 46 | 47 |
48 | ... 49 |
50 | 51 | 52 |
53 | 54 | ``` 55 | 56 | ### 条件注释 57 | ```html 58 | 59 | 60 | 浏览器 不是 IE 61 | 62 | 63 | 66 | 67 | 70 | 71 | 74 | 75 | ``` 76 | 77 |
78 | 79 | ## CSS 文件注释 80 | 81 | ### 单行注释 82 | ```css 83 | /* Comment Text */ 84 | .jdc {} 85 | 86 | /* Comment Text */ 87 | .jdc {} 88 | ``` 89 | 90 | ### 模块注释 91 | ```css 92 | /* Module A 93 | ---------------------------------------------------------------- */ 94 | .mod_a {} 95 | 96 | /* Module B 97 | ---------------------------------------------------------------- */ 98 | .mod_b {} 99 | ``` 100 | 101 |
102 | 103 | ## JS 注释规范 104 | 105 | ### 单行注释.js 106 | ```js 107 | // is current tab 108 | const active = true 109 | 110 | // 注释行上面是一个块的顶部时不需要空行 111 | function getType() { 112 | // set the default type to 'no type' 113 | const type = this.type || 'no type' 114 | return type 115 | } 116 | 117 | function fn() { 118 | console.log('fetching type...') 119 | 120 | // set the default type to 'no type' 121 | const type = this.type || 'no type' 122 | return type 123 | } 124 | ``` 125 | 126 | ### 特殊标记注释 127 | [Better Comments vscode 注释分类插件](https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments){.doclink} 128 | [TODO Highlight vscode 注释关键字高亮插件](https://marketplace.visualstudio.com/items?itemName=wayou.vscode-todo-highlight){.doclink} 129 | 130 | ```js 131 | // TODO:功能未完成,待完善 132 | // FIXME:待修复 133 | // XXX:实现方法待确认 134 | // NOTE:代码功能说明 135 | // HACK:此处写法有待优化 136 | // BUG:此处有 Bug 137 | ``` 138 | 139 | ### 函数注释 140 | [JSDoc](http://yuri4ever.github.io/jsdoc/){.doclink} 141 | 142 | ```js 143 | /** 144 | * 方法说明 145 | * @func 146 | * @desc xx函数 147 | * @param {string} a - 参数a 148 | * @param {number} b=1 - 参数b默认值为1 149 | * @param {string} c=1 - 参数c有两种支持的取值 1—表示x 2—表示xx 150 | * @param {object} d - 参数d为一个对象 151 | * @param {string} d.e - 参数d的e属性 152 | * @param {object[]} g - 参数g为一个对象数组 153 | * @param {string} g.h - 参数g数组中一项的h属性 154 | * @param {string} [j] - 参数j是一个可选参数 155 | * @return {返回值类型} 返回值说明 156 | */ 157 | ``` 158 | 159 | ### 变量注释 160 | ```js 161 | /** 162 | * @type {string | null} 163 | * @desc string或者null 164 | */ 165 | let foo 166 | ``` 167 | -------------------------------------------------------------------------------- /content/docs/400.standard-dev/3.mock.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Mock' 3 | description: 'Mock开发使用指南' 4 | --- 5 | 6 | ## 方案一:使用接口管理平台 7 | 8 | [apifox 🌟](https://www.apifox.cn/?utm_source=zhihu&utm_medium=article_10001&utm_content=141425111){.doclink} 9 | [easy-mock 🌟](https://mock.presstime.cn/){.doclink} 10 | [yapi 接口文档](https://hellosean1025.github.io/yapi/documents/index.html){.doclink} 11 | [Postman 接口测试](https://www.postman.com/){.doclink} 12 | 13 |
14 | 15 | ## 方案二:MockJs 16 | 17 | [mock.js](http://mockjs.com/){.doclink} 18 | 19 | ::tabs 20 | --- 21 | tabs: [ 'bash', 'js' ] 22 | --- 23 | 24 | #bash 25 | ```bash 26 | # 安装 27 | pnpm add -D mockjs 28 | # OR 29 | 30 | 31 | # 目录 32 | ├─mock 33 | │ ├─test 34 | │ │ └─index.ts 35 | ``` 36 | 37 | #js 38 | ```js 39 | import Mock from 'mockjs' 40 | 41 | const { newsList } = Mock.mock({ 42 | 'newsList|80': [{ 43 | id: '@increment()', 44 | title: '@ctitle()', 45 | date: '@date("yyyy-MM-dd")', 46 | }], 47 | }) 48 | 49 | // 数据随机规则 http://mockjs.com/examples.html 50 | Mock.mock(/\/api\/news\/list/, 'get', (params) => { 51 | console.log(params.url) // '/api/news/list?pageSize=10&pageIndex=1' 52 | const pageIndex = getQuery(params.url, 'pageIndex') 53 | const pageSize = getQuery(params.url, 'pageSize') 54 | const start = (pageIndex - 1) * pageSize 55 | const end = pageIndex * pageSize 56 | const totalPage = Math.ceil(newsList.length / pageSize) 57 | const list = pageIndex > totalPage ? [] : newsList.slice(start, end) 58 | return { 59 | status: 200, 60 | list, 61 | total: newsList.length, 62 | message: '获取新闻列表数据成功', 63 | } 64 | }) 65 | 66 | Mock.mock('/api/add/news', 'post', (params) => { 67 | console.log(params.body) // "{title:''}" 68 | const body = JSON.pase(params.body) 69 | newsList.push(Mock.mock({ 70 | 'id|+1': '@increment()', 71 | 'title': body.title, 72 | 'date': '@date("yyyy-MM-dd")', 73 | })) 74 | 75 | return { 76 | status: 200, 77 | list: newsList, 78 | total: newsList.length, 79 | message: '添加新闻数据成功', 80 | } 81 | }) 82 | 83 | // 使用 84 | axios.get('/api/news/list', { 85 | params: { pageSize: 10, pageIndex: 1 }, 86 | }) 87 | .then(res => console.log(res)) 88 | 89 | axios.post('/api/add/news', { title: '' }) 90 | .then(res => console.log(res)) 91 | ``` 92 | 93 | :: 94 | 95 |
96 | 97 | ## 参考链接 98 | 99 | ### 关于抓包工具 100 | 101 | [Charles](https://www.charlesproxy.com/){.doclink} 102 | [Whistle](http://wproxy.org/whistle/){.doclink} 103 | [Proxyman](https://proxyman.io/){.doclink} 104 | 105 |
106 | 107 | ### 关于服务接口API 108 | 109 | [json-server](https://github.com/typicode/json-server){.doclink} 110 | -------------------------------------------------------------------------------- /content/docs/400.standard-dev/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 开发规范 2 | -------------------------------------------------------------------------------- /content/docs/500.stanard-buiild/1.package.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'package' 3 | --- 4 | 5 | [packagejson](https://docs.npmjs.com/cli/v9/configuring-npm/package-json){.doclink} 6 | 7 | ::tabs 8 | --- 9 | tabs: [ 'bash', 'package.json' ] 10 | --- 11 | 12 | #bash 13 | ```bash 14 | # 初始化 15 | npm init 16 | 17 | # 一键初始化 18 | npm init -y 19 | ``` 20 | 21 | #package.json 22 | ```json 23 | { 24 | "name": "", // 项目名称 25 | "version": "", // 项目版本(semver) 26 | 27 | "description": "", // 项目描述 28 | "keywords": "", // 关键词 29 | "license": "", // 许可证 30 | 31 | "homepage": "", // 包的项目主页或者文档首页 32 | "bugs": "", // 项目问题跟踪器的 url 和/或应报告问题的电子邮件地址 33 | "repository": "", // 代码托管的位置 34 | 35 | "author": "", // 作者 36 | "contributors": "", // 贡献者 37 | 38 | "files": [], // 设置需要推送到npm的文件 39 | "main": "", // 入口文件 40 | "bin": "", // 自定义命令 41 | "directories": "", // 包安装时,你可以指定确切的位置来放pages、文档、例子等 42 | "types": "", // index.d.ts 位于包的根目录,则不需要标记 types 属性 43 | 44 | "browser": "", // 浏览器 45 | 46 | "scripts": "", // 指定运行脚本命令的 npm 命令行缩写 47 | "config": "", // 用于添加命令行的环境变量 48 | 49 | "dependencies": {}, // 项目运行所依赖的模块 50 | "devDependencies": {}, // 项目开发所需要的模块 51 | "peerDependencies": {}, // 平行依赖允许你说明你的包和其他包版本的兼容性 52 | "optionalDependencies": {}, // 可选依赖项 53 | "bundledDependencies": {}, // 包依赖是发布你的包时将会一起打包的一个包名数组 54 | 55 | "engines": [], // 指定项目 node、npm 版本 56 | "os": [], // 指定模块适用系统 57 | "cpu": [], // 指定模块适用 cpu 架构 58 | 59 | "private": "", // 如果你不想你的包发布到包管理器(npm 或者 私有包管理),设置为 true 60 | "publishConfig": "" // 包名有@符号,例如@username/component,默认为私有包,需配置 { "access": "public" } 61 | } 62 | ``` 63 | 64 | :: 65 | -------------------------------------------------------------------------------- /content/docs/500.stanard-buiild/2.build.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '构建工具' 3 | --- 4 | 5 | ## 配置构建 6 | 7 | ::tabs 8 | --- 9 | tabs: [ 'base', 'dev', 'prod' ] 10 | --- 11 | 12 | #base 13 | ```md 14 | 15 | 配置 output 输出 16 | 配置 entry 入口 17 | 配置 resolve 18 | 配置 loader:ts、js兼容、vue、css、sass、图片、字体、媒体文件 19 | 配置 plugin:静态资源注入html文件、清理dist目录、热更新 20 | 配置环境变量 21 | ``` 22 | 23 | #dev 24 | ```md 25 | 26 | 配置 mode 模式 27 | 配置 devtool 调试工具 28 | 配置 devServer:开发服务器、代理、热更新 29 | ``` 30 | 31 | #prod 32 | ```md 33 | 34 | 配置 mode 模式 35 | 依赖构建分析:分析项目体积、测量打包速度 36 | 提取项目依赖、使用CDN 37 | 静态资源优化 38 | 剔除日志、Code Splitting、Tree Shaking、开启GZIP压缩 39 | 查询优化:定向查找、减少执行构建的模块 40 | 构建速度优化:预编译资源模块、多进程多实例打包构建、多进程多实例并行压缩、基础包CDN、持久化缓存 41 | ``` 42 | :: 43 | 44 |
45 | 46 | ## 参考链接 47 | 48 | [webpack](https://webpack.js.org/){.doclink} 49 | [vue-cli4-config 配置清单](https://github.com/staven630/vue-cli4-config){.doclink} 50 | [Vite](https://vitejs.dev/){.doclink} 51 | [Rollup](https://rollupjs.org/){.doclink} 52 | -------------------------------------------------------------------------------- /content/docs/500.stanard-buiild/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 打包 2 | -------------------------------------------------------------------------------- /content/docs/600.standard-monitor/1.buried.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '埋点、监控' 3 | --- 4 | 5 | ## 埋点 6 | 7 | ### 手动埋点 8 | 9 | ### 自动埋点 10 | 11 | ### 可视化埋点 12 | 13 |
14 | 15 | ## 监控 16 | 17 | ### 性能监控 18 | 19 | ### 异常监控 20 | 21 | ### 用户体验 22 | 23 |
24 | 25 | ## 参考链接 26 | 27 | [应用实时监控服务ARMS](https://www.alibabacloud.com/help/zh/arms/application-monitoring/developer-reference/arms-sdks){.doclink} 28 | [神策](https://www.sensorsdata.cn/){.doclink} 29 | [sentry](https://github.com/getsentry/sentry){.doclink} 30 | [小程序实时日志](https://developers.weixin.qq.com/miniprogram/dev/framework/realtimelog/){.doclink} 31 | -------------------------------------------------------------------------------- /content/docs/600.standard-monitor/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 埋点监控 2 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/1.css.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'css' 3 | --- 4 | 5 | ## 代码层面 6 | 7 | - 利用浏览器渲染过程的 分层 优化 8 | - 元素提升为图层,动画在 GPU 中完成,例如 `transform`、`filter`、`position`、`opacity` 9 | - css属性 `will-change` 提高性能 10 | - 降低 reflow 重排(本质是重新计算layout树及后边渲染流程,如布局、分层、绘制) 11 | - 布局耗时 - 几何计算(宽高、margin、padding、字体大小等) 12 | - 修改 dom 结构 13 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/2.js.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'JS' 3 | --- 4 | 5 | ## 代码层面 6 | 7 | ### 执行 8 | - 避免内存泄漏(全局变量、闭包、DOM 元素的引用、定时器、控制台打印) 9 | - 有繁重计算的代码抽离到 Web Worker 10 | 11 | ### 渲染 12 | - 分批渲染使用 `requestAnimationFrame` 代替 `setTimeout` 13 | - 页面添加多个元素时,使用 `DocumentFragment` 组装后一次性添加到页面 14 | - 页面添加多个元素时,使用 `requestIdleCallback` 函数将在浏览器空闲时期被调用 15 | ```js 16 | function performanceChunk(data) { 17 | let i = 0 18 | function _run() { 19 | if (i >= data.length) 20 | return 21 | requestIdleCallback((idle) => { 22 | while (idle.timeRemaining() > 0 && i < data.length) { 23 | const div = document.createElement('div') 24 | div.textContent = data[i] 25 | document.body.appendChild(div) 26 | i++ 27 | } 28 | _run() 29 | }) 30 | } 31 | _run() 32 | } 33 | ``` 34 | ### 脚本 35 | - 使用 `async` 或 `defer` 属性加载脚本 36 | - 使用 `preload` 或 `prefetch` 属性加载脚本 37 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/3.resource.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '静态资源' 3 | --- 4 | 5 | ### 资源优先级 6 | - 预取回 Prefetch 7 | - 预加载 Preload 8 | - 预连接 Preconnect 9 | - DNS预取回 DNS-Prefetch 10 | 11 | ### 图片 12 | - 加载:懒加载、预加载 13 | - 图片分割 & 雪碧图 14 | - 图片格式 15 | - 建议使用循环播放的 video 或者 WebP 代替 gif 16 | - 使用 WebP 将减少图像大小,使用 JPEG 将提高图像的可感知性 17 | - 为不同 DPR 屏幕提供最适合的图片尺寸 18 | - 使用图片时尽可能使用具有 srcset,sizes 和 元素的响应式图像 19 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/3.vue.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Vue' 3 | --- 4 | 5 | ### 代码层面 6 | - v-for 使用 key(有利于列表变动时,尽量少的删除、新增、改动元素) 7 | - 合理使用冻结对象(提升效率 Object.freeze(obj),冻结的对象不会响应式) 8 | - 使用函数式组件(减少组件初始化的过程,内存更少,不会创建实例对象) 9 | - 使用计算属性(某个数据多次使用,并且数据时通过计算得到的,通过计算属性进行缓存) 10 | - 非实时绑定的表单项(v-modal会导致数据实时变化,会导致重渲染,合理使用lazy避免) 11 | - 保持对象引用稳定(避免获取到的新数据重新赋值给对象,导致引用变化,页面重新渲染) 12 | - 合理使用 v-show 和 v-if 13 | - 使用延迟装载defer(利用 requestAnimationFrame 事件分批渲染内容) 14 | ```js 15 | // 定义 16 | export default function deferMixins (maxFrameCount) { 17 | return { 18 | data() { 19 | return { 20 | frameCount: 0 21 | } 22 | }, 23 | }, 24 | mounted() { 25 | function refreshFrameCount() { 26 | requestAnimationFrame(() => { 27 | this.frameCount++ 28 | if (this.frameCount < maxFrameCount) 29 | refreshFrameCount() 30 | }) 31 | } 32 | refreshFrameCount() 33 | }, 34 | methods: { 35 | defer(showInFrameCount) { 36 | return this.frameCount >= showInFrameCount 37 | } 38 | } 39 | } 40 | 41 | // 使用 42 | deferMixins(10) // 分是个片段 43 |
// 片段1时渲染 44 |
// 片段10时渲染 45 | ``` 46 | - 使用 KeepAlive 复用组件(避免组件重复的创建、销毁带来的性能损耗) 47 | - 长列表优化 48 | - 及时清除组件中的副作用(比如 setInterval 等) 49 | 50 | ### 配置构建 51 | - 打包体积优化 52 | - 组件按需加载 53 | - 组件异步加载 54 | - 路由懒加载 55 | - 生产环境排除打包使用CDN 56 | - 打包移除日志打印 57 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/4.mini-program.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '小程序' 3 | --- 4 | 5 | ### 界面 6 | 7 | - 图片:避免使用大图; 8 | - 图片:避免滥用 image 组件的 widthFix/heightFix 模式; 9 | - 组件:骨架屏、占位组件、虚拟组件 10 | - 节点:减少组件数量、减少节点嵌套层级,总页面节点数少于1000个,节点树深度层级少于30层,子节点数不大于60个 11 | - 滚动组件:开启惯性滚动 `-webkit-overflow-scrolling: touch;` 12 | - 交互通信:使用hover-class实现按钮的单击态、`使用recycle-view & recycle-item 虚拟DOM组件` 13 | - 交互通信:防止用户的左滑或者按键返回误操作,导致整个页面回退的问题 14 | - 交互通信:scroll-view尤其注意视图层和逻辑层频繁进行通讯; 15 | - 交互通信:长列表使用ulist,具有自动回收机制; 16 | - 提取组件:微博长列表页面,点击一个点赞图标,赞数要立即+1,此时这个点赞按钮一定要做成组件。否则这个+1会引发页面级所有数据的从js层向视图层的同步; 17 | - 宽屏适配:leftWindow 18 | - 宽屏适配:topWindow 19 | - 宽屏适配:rightWindow 20 | 21 | ### 加载 22 | 23 | - 新页面渲染和窗体进入动画抢资源,造成页面切换卡顿、掉帧。建议延时100ms~300ms渲染图片或复杂原生组件,分批进行数据通讯,以减少一次性渲染的节点数量; 24 | - 生命周期:提前发起数据请求; 25 | - 生命周期:首屏渲染优化; 26 | 27 | ### 逻辑 28 | 29 | - 列表:动态列表渲染里优化wx:key的使用 30 | - data数据:避免data对象无用数据、合理使用优化数据、减少一次性节点数量,延迟setdata 31 | - 垃圾数据:清理定时器、有一个监听,必须有一个反监听,并及时移除销毁 32 | - 高性能操作:适当监听页面或组件的 scroll 事件; 33 | - 高性能操作:选择高性能的动画实现方式; 34 | - 高性能操作:使用 IntersectionObserver 监听元素曝光; 35 | - 生命周期:避免在 onHide/onUnload 执行耗时操作; 36 | - 启用多线程worker:一些异步处理的任务 37 | 38 | ### 系统 39 | 40 | - 打包:开启摇树优化; 41 | - 打包:页面初始渲染缓存配置 initialRenderingCache; 42 | - 分包:分包预下载; 43 | - 分包:分包异步化(允许通过一些配置和新的接口,使部分跨分包的内容可以等待下载后异步使用,从而一定程度上解决这个限制); 44 | - 代码注入优化(按需注入和用时注入):避免启动页面所在的主包或者分包文件全部加载; 45 | - 代码注入优化(按需注入和用时注入):{"lazyCodeLoading": "requiredComponents"}; 46 | - 初始渲染缓存:使视图层不需要等待逻辑层初始化完毕,而直接提前将页面初始 data 的渲染结果展示给用户 47 | - 系统分析:内存分析 48 | - 系统分析:处理内存告警 49 | - 周期性更新:能够在用户未打开小程序的情况下,也能从服务器提前拉取数据 50 | - 数据预拉取:在小程序冷启动的时候通过微信后台提前向第三方服务器拉取业务数据 51 | 52 | ### 实用工具 53 | 54 | - 高性能渲染优先选用 `wxs` 55 | - 高性能渲染优先选用 `renderjs` 56 | 57 | ### 网络层面 58 | 59 | - 减少图片的请求次数 & 压缩图片大小 60 | - 尽可能使用CDN图片或图片链接 & 尽可能使用webp格式图片 61 | - 减少不必要的网络请求,使用本地缓存数据 62 | - 优化网络请求参数,提高网络请求效率 63 | - 优化网络请求的并发数,分优先级 64 | 65 | ### 主包优化 66 | 67 | - 尽可能除tabbar页面外,所有页面都将其放入分包中 68 | - 公共样式提取到主包中,避免重复打包 69 | - 公共样式会被打入每个文件的样式中 70 | - 分包 71 | - 避免多个分包共用一个分包的文件,小程序会默认将公共引用的文件打成主包文件 72 | - 分包引用UI组件,该UI组件将被打入主包 73 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/6.webpack.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Webpack' 3 | --- 4 | 5 | ## 构建性能 6 | 7 | ### 热替换 8 | 9 | ```js 10 | module.exports = { 11 | devServer: { 12 | hot: true, 13 | }, 14 | } 15 | ``` 16 | 17 | ### 减少模块解析 18 | 19 | ```js 20 | // 针对没有依赖的模块进行不解析配置 21 | module.exports = { 22 | mode: 'development', 23 | module: { 24 | noParse: /jquery/, 25 | }, 26 | } 27 | ``` 28 | 29 | ### 优化 loader 30 | 31 | - 限制 loader 应用范围 32 | - 缓存 loader 结果 `cache-loader` 33 | - loader 运行开启多线程 `thread-loader` 34 | 35 | ```js 36 | module.exports = { 37 | module: { 38 | rules: [ 39 | { 40 | test: /\.js$/, 41 | // lodash 本身使用旧语法,在转化时不需要再进行解析 42 | // exclude: /lodash/, 43 | include: /src/, 44 | use: ['cache-loader', 'thread-loader', 'babel-loader'], 45 | }, 46 | ], 47 | }, 48 | } 49 | ``` 50 | 51 |
52 | 53 | ## 传输性能 54 | 55 | ### externals & CDN 56 | 57 | ::tabs 58 | --- 59 | tabs: [ 'vue.config.js', 'index.html' ] 60 | --- 61 | 62 | #vue.config.js 63 | ```js 64 | let externals = {} 65 | let cdn = {} 66 | if (process.env.NODE_ENV === 'production') { 67 | externals = { 68 | lodash: '_', 69 | echarts: 'echarts', 70 | } 71 | cdn = { 72 | js: [ 73 | 'https://cdn.bootcdn.net/ajax/libs/lodash/4.17.21/lodash.min.js', 74 | 'https://cdn.bootcdn.net/ajax/libs/echarts/5.1.2/echarts.min.js', 75 | ], 76 | } 77 | } 78 | 79 | module.exports = { 80 | configureWebpack: { 81 | externals, 82 | }, 83 | chainWebpack: (config) => { 84 | config.plugin('html').tap((args) => { 85 | args[0].cdn = cdn 86 | return args 87 | }) 88 | }, 89 | } 90 | ``` 91 | 92 | #index.html 93 | ```html 94 | 95 | 96 | 97 | 98 | 102 | 103 | <%= htmlWebpackPlugin.options.title %> 104 | 105 | 106 | 107 |
108 | 109 | <% for (var js in htmlWebpackPlugin.options.cdn.js) { %> 110 | 111 | <% } %> 112 | 113 | 114 | ``` 115 | :: 116 | 117 | ### 自动分包 118 | 119 | ::tabs 120 | --- 121 | tabs: [ 'webpack.config.js' ] 122 | --- 123 | 124 | #webpack.config.js 125 | ```js 126 | module.exports = { 127 | mode: 'production', 128 | 129 | optimization: { 130 | splitChunks: { 131 | // 分包配置 132 | 133 | chunks: 'all', 134 | // maxSize: 60000, 135 | // minChunks: 2, 136 | // minSize: 30000, 137 | 138 | cacheGroups: { 139 | // 属性名是缓存组名称,会影响到分包的chunk名 140 | // 属性值时缓存组的配置,缓存组继承所有的全局配置,也有自己特殊的配置 141 | vendors: { 142 | test: /[\\/]node_modules[\\/]/, // 匹配到相应模块时,将这些模块进行单独打包 143 | priority: -10, // 缓存组优先级,优先级越高,该策略越先进行处理,默认值0 144 | }, 145 | default: { 146 | minChunks: 2, // 覆盖全局配置,将最小的chunk引用数改为2 147 | priority: -20, // 优先级 148 | reuseExistingChunk: true, // 重用已经被分离出去的chunk 149 | }, 150 | // 举例:样式chunks 151 | style: { 152 | minChunks: 2, 153 | test: /\.css$/, 154 | priority: 0, 155 | }, 156 | }, 157 | }, 158 | }, 159 | } 160 | ``` 161 | :: 162 | 163 | ### 手动分包 164 | 165 | - 开启 output.library 暴露公共模块 166 | - 用 DllPlugin 创建资源清单 167 | - 用 DllReferencePlugin 使用资源清单 168 | 169 | ::tabs 170 | --- 171 | tabs: [ 'webpack.dll.config.js', 'webpack.config.js', 'package.json', 'index.html' ] 172 | --- 173 | 174 | #webpack.dll.config.js 175 | ```js 176 | // webpack.dll.config.js 177 | const path = require('node:path') 178 | const webpack = require('webpack') 179 | 180 | module.exclude = { 181 | mode: 'production', 182 | entry: { 183 | lodash: ['lodash'], 184 | jquery: ['jquery'], 185 | }, 186 | output: { 187 | filename: 'dll/[name].js', 188 | library: '[name]', 189 | }, 190 | plugins: [ 191 | new webpack.DllPlugin({ 192 | path: path.resolve(__dirname, 'dll', '[name].manifest.json'), 193 | name: '[name]', 194 | }), 195 | ], 196 | } 197 | ``` 198 | 199 | #webpack.config.js 200 | ```js 201 | module.exports = { 202 | plugins: [ 203 | new CleanWebpackPlugin({ 204 | cleanOnceBeforeBuildPatterns: ['**/*', '!dll', '!dll/*'], 205 | }), 206 | new webpack.DllReferencePlugin({ 207 | manifest: require('./dll/jquery.manifest.json'), 208 | }), 209 | new webpack.DllReferencePlugin({ 210 | manifest: require('./dll/lodash.manifest.json'), 211 | }), 212 | ], 213 | } 214 | ``` 215 | 216 | #package.json 217 | ```json 218 | { 219 | "script": { 220 | "dll": "webpack --config webpack.dll.config.js" 221 | } 222 | } 223 | ``` 224 | 225 | #index.html 226 | ```html 227 | 228 | 229 | ``` 230 | :: 231 | 232 | ### 单模块体积优化 233 | 234 | - 压缩代码 235 | 236 | ```js 237 | const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') 238 | const TerserPlugin = require('terser-webpack-plugin') 239 | 240 | module.exports = { 241 | mode: 'production', 242 | optimization: { 243 | // 是否启用压缩,生产环境默认启用 244 | minimize: true, 245 | minimizer: [ 246 | // 默认内置 JS 压缩 247 | new TerserPlugin({ 248 | terserOptions: { 249 | compress: { 250 | drop_console: true, 251 | }, 252 | }, 253 | }), 254 | 255 | // CSS 压缩 256 | new CssMinimizerPlugin(), 257 | ], 258 | }, 259 | } 260 | ``` 261 | 262 | - Tree Shaking 263 | - `mode: 'production'` 264 | - 使用 export {} 导出,而不是用 export default {} 导出 265 | - 使用 import {} from '..' 导出,而不是用 import from '..' 导出 266 | - 标记文件副作用 267 | ```bash 268 | { 269 | "sideEffects": true # 所有模块都有副作用 270 | "sideEffects": [ !"*.css" ] # 指定模块没有副作用 271 | } 272 | ``` 273 | 274 | ### 懒加载 275 | 276 | ::tabs 277 | --- 278 | tabs: [ 'util.js', 'index.js' ] 279 | --- 280 | 281 | #util.js 282 | ```js 283 | export { chunk } from 'lodash-es' 284 | ``` 285 | 286 | #index.js 287 | ```js 288 | async function onButtonClick() { 289 | const { chunk } = await import('./util.js') 290 | } 291 | ``` 292 | :: 293 | 294 | ### GZIP 预压缩 295 | 296 | ::tabs 297 | --- 298 | tabs: [ 'webpack', 'nginx' ] 299 | --- 300 | 301 | #webpack 302 | ```js 303 | // 移除服务器的压缩时间 304 | // npm install --save-dev compression-webpack-plugin 305 | const CompressionPlugin = require('compression-webpack-plugin') 306 | 307 | module.exports = { 308 | plugins: [ 309 | new CompressionPlugin({ 310 | filename: '[path][base].gz', // 输出文件名,可以自定义 311 | algorithm: 'gzip', // 使用的压缩算法 312 | test: /\.(js|css|html|svg)$/, // 匹配要压缩的文件类型 313 | threshold: 10240, // 只处理大于 10KB 的文件 314 | minRatio: 0.8, // 只有压缩率小于这个比例的文件才会被处理 315 | }), 316 | ], 317 | } 318 | ``` 319 | 320 | #nginx 321 | ```bash 322 | http { 323 | gzip_static on; 324 | } 325 | ``` 326 | 327 | :: 328 | 329 |
330 | 331 | ## 其他优化 332 | 333 | ### Bundle Analyzer 334 | 335 | ::tabs 336 | --- 337 | tabs: [ 'base', 'webpack', 'package' ] 338 | --- 339 | 340 | #base 341 | ```bash 342 | pnpm add -D webpack-bundle-analyzer 343 | ``` 344 | 345 | #webpack 346 | ```js 347 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 348 | 349 | module.exports = { 350 | plugins: [ 351 | new BundleAnalyzerPlugin({ 352 | analyzerMode: 'server', // 可以设置为 'static'、'server'、'disabled' 353 | openAnalyzer: true, // 是否自动打开浏览器 354 | reportFilename: 'bundle-report.html', // 报告文件名,适用于 'static' 模式 355 | }), 356 | ], 357 | } 358 | ``` 359 | 360 | #package 361 | ```json 362 | { 363 | "scripts": { 364 | "analyze": "webpack --config webpack.config.js" 365 | } 366 | } 367 | ``` 368 | :: 369 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/7.vite.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Vite' 3 | --- 4 | 5 | ## 配置方面 6 | 7 | ### 构建 & 加载 8 | - 手动分包 9 | ```ts 10 | // 将开发代码文件和公共工具文件分离 11 | // 开发代码经常改动,导致打包文件指纹有变化,用户访问会重新下载文件 12 | 13 | export default defineConfig({ 14 | build: { 15 | rollupOptions: { 16 | // manualChunks: { vendor: ['lodash', 'vue'] }, // 外部依赖少 可以手动添加 17 | manualChunks(id) { // 外部依赖多 在执行时添加 18 | if (id.includes('node_modules')) { 19 | return 'vendor' 20 | } 21 | }, 22 | }, 23 | }, 24 | }) 25 | ``` 26 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/9.network.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '网络' 3 | --- 4 | 5 | ## 服务优化 6 | 7 | - 开启 gzip 压缩 8 | - 浏览器缓存 9 | - CDN内容分发 & DNS预解析 10 | 11 |
12 | 13 | ## SEO 14 | 15 | - SSR 服务端渲染 16 | - HTML 文件 17 | - Title(标题)、Description(描述)和 Keywords(关键词) 18 | - Meta 标签使用 19 | - Open Graph 协议 20 | - 结构化数据,例如 JSON-LD 21 | - 代码方面 22 | - HTML 语义化 23 | - a 标签中 rel 属性,nofollow、external 24 | - 额外文件 25 | - 添加 sitemap.xml 站点地图 26 | - 添加 robots.txt 文件 27 | - 各搜索引擎提交站点收录 28 | 29 |
30 | 31 | ## SEO工具 32 | 33 | [xml-sitemaps](https://www.xml-sitemaps.com/){.doclink} 34 | [SEO综合查询](https://seo.chinaz.com/){.doclink} 35 | 36 |
37 | 38 | ## 性能检测工具 39 | 40 | [PageSpeed Insights 网站各项 RUM 数据](https://pagespeed.web.dev/?utm_source=psi&utm_medium=redirect){.doclink} 41 | [WebPageTest 网站速度测试](https://www.webpagetest.org/){.doclink} 42 | -------------------------------------------------------------------------------- /content/docs/700.standard-optimize/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 性能优化 2 | -------------------------------------------------------------------------------- /content/docs/800.standard-test/1.unit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '单元测试' 3 | --- 4 | 5 | ## vitest 6 | 7 | :::tabs 8 | --- 9 | tabs: [ 'install', 'package.json', 'vite.config.ts' ] 10 | --- 11 | 12 | #install 13 | ```bash 14 | pnpm add -D vitest happy-dom 15 | ``` 16 | 17 | #package.json 18 | ```json 19 | { 20 | "scripts": { 21 | "test": "vitest" 22 | } 23 | } 24 | ``` 25 | 26 | #vite.config.ts 27 | ```ts 28 | /// 29 | import { defineConfig } from 'vite' 30 | 31 | export default defineConfig({ 32 | test: { 33 | environment: 'happy-dom', 34 | }, 35 | }) 36 | ``` 37 | ::: 38 | 39 | ### 参考链接 40 | 41 | [vitest](https://github.com/vitest-dev/vitest){.doclink} 42 | 43 | [Vitest Workspaces](https://cn.vitest.dev/guide/workspace.html){.doclink} 44 | -------------------------------------------------------------------------------- /content/docs/800.standard-test/2.automation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '自动化测试' 3 | --- 4 | 5 | ## puppeteer 6 | 7 |
8 | 9 | ## 参考链接 10 | [puppeteer](https://github.com/puppeteer/puppeteer){.doclink} 11 | -------------------------------------------------------------------------------- /content/docs/800.standard-test/3.e2e.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '系统测试' 3 | --- 4 | 5 | ## cypress 6 | 7 |
8 | 9 | ## 参考链接 10 | 11 | [cypress](https://github.com/cypress-io/cypress){.doclink} 12 | -------------------------------------------------------------------------------- /content/docs/800.standard-test/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 测试 2 | -------------------------------------------------------------------------------- /content/docs/900.standard-deploy/1.server.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '服务器' 3 | --- 4 | 5 | ## 阿里云服务器 6 | 7 | ::card 8 | 服务器购买 9 | - 国内服务器:阿里云ECS、腾讯云CVM 10 | - 国外服务器:日本Vultr、美国Linode、谷歌云、微软Azure、亚马逊AWS、SiteGround 11 | :: 12 | 13 | - 实例 -> 实例详情 -> 重置密码 14 | - 安全组 -> 安全组详情 -> 添加端口 15 | 16 |
17 | 18 | ## 域名 19 | 20 | ::card 21 | 域名购买 22 | - 国内:万网(阿里)、腾讯 23 | - 国外:GoDaddy 24 | :: 25 | 26 | - 实名认证 27 | - ICP备案 28 | - 域名解析 -> 添加记录 29 | - CDN -> 添加域名 -> 云解析CDN -> 配置CNAME 30 | - SSL证书 -> 添加证书 -> 配置证书 -> 部署CDN -> 配置CDN 31 | 32 |
33 | -------------------------------------------------------------------------------- /content/docs/900.standard-deploy/14.node.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '本地部署' 3 | --- 4 | 5 | ## Express部署Vue项目 6 | 7 | ::tabs 8 | --- 9 | tabs: [ 'directory', 'bash', 'app.js' ] 10 | --- 11 | 12 | #directory 13 | ```bash 14 | Express项目 15 | ├── app.js 16 | ├── bin 17 | ├── dist # Vue打包后的文件夹 18 | ├── node_modules 19 | ├── package.json 20 | ├── public 21 | ├── routes 22 | └── views 23 | ``` 24 | 25 | #bash 26 | ```bash 27 | npm init 28 | pnpm add -D express 29 | 30 | npx express-generator 31 | 32 | # history模式 刷新页面404的问题 33 | pnpm add -S connect-history-api-fallback 34 | # 访问服务404的问题 35 | pnpm add -D http-proxy-middleware 36 | ``` 37 | 38 | #app.js 39 | ```js 40 | // Express app.js 41 | const path = require('node:path') 42 | const express = require('express') 43 | const history = require('connect-history-api-fallback') 44 | const { createProxyMiddleware } = require('http-proxy-middleware') 45 | 46 | const app = express() 47 | 48 | // 配置静态资源 49 | app.use(express.static(path.join(__dirname, 'dist'))) 50 | 51 | // history模式,刷新页面404的问题 52 | app.use(history()) 53 | 54 | // 访问服务404的问题 55 | app.use( 56 | '/api', 57 | createProxyMiddleware({ 58 | target: 'xxx', 59 | changeOrigin: true, 60 | pathRewrite: { 61 | '^/api': '', 62 | }, 63 | }), 64 | ) 65 | 66 | app.listen(3000, () => { 67 | console.log('Server is running at http://localhost:3000') 68 | }) 69 | 70 | module.exports = app 71 | ``` 72 | 73 | :: 74 | -------------------------------------------------------------------------------- /content/docs/900.standard-deploy/15.cicd.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '静态站点部署' 3 | --- 4 | 5 | ## 参考链接 6 | [GitHub Actions](https://docs.github.com/zh/actions){.doclink} 7 | [Netlify](https://www.netlify.com/){.doclink} 8 | [vercel](https://vercel.com/dashboard){.doclink} 9 | [阿里云效](https://www.aliyun.com/product/yunxiao){.doclink} 10 | -------------------------------------------------------------------------------- /content/docs/900.standard-deploy/16.devops.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'DevOps' 3 | --- 4 | 5 | ## Linux 软件安装 6 | 7 | ::tabs 8 | --- 9 | tabs: [ 'Docker', 'Nginx', 'MySQL' ] 10 | --- 11 | #Docker 12 | ```bash 13 | # CentOS Docker 安装 14 | # https://docs.docker.com/engine/install/centos/ 15 | 16 | # Docker 镜像加速 17 | # https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 18 | 19 | # 启动 Docker 服务,并让它随系统启动自动加载 20 | sudo systemctl start docker 21 | sudo systemctl enable docker 22 | ``` 23 | 24 | #Nginx 25 | ```bash 26 | # =========================== 1. 创建 nginx Dockerfile 27 | sudo mkdir -p /usr/local/nginx 28 | touch Dockerfile 29 | 30 | # =========================== 2. 编辑 Dockerfile 31 | # 使用官方最新的 Nginx 镜像作为基础镜像 32 | FROM nginx:latest 33 | # 维护者信息 34 | LABEL maintainer="LOUSANPANG<1271255653@qq.com>" 35 | # 设置环境变量,避免一些安装包提示的问题 36 | ENV DEBIAN_FRONTEND=noninteractive 37 | # 更新包索引,安装 vim,同时清理缓存以减少镜像体积 38 | RUN apt-get update && \ 39 | apt-get install -y vim && \ 40 | apt-get clean && \ 41 | rm -rf /var/lib/apt/lists/* 42 | # 创建自定义配置目录(如果需要可以修改路径) 43 | # RUN mkdir -p /etc/nginx/conf.d 44 | # 将工作目录设置为 Nginx 的默认配置目录 45 | WORKDIR /etc/nginx 46 | # 暴露端口 47 | EXPOSE 80 48 | # 将主机配置文件或静态资源挂载到容器(如果需要可以添加) 49 | # COPY ./container-mysql.conf /etc/nginx/nginx.conf 50 | # 设置容器启动时运行的默认命令 51 | CMD ["nginx", "-g", "daemon off;"] 52 | 53 | # =========================== 3. 构建镜像 54 | sudo docker build -t container-mysql /usr/local/nginx 55 | 56 | # =========================== 4. 运行容器 57 | sudo docker run --name container-mysql -p 80:80 -d container-mysql 58 | 59 | # =========================== 5. 进入容器并配置nginx.conf 60 | sudo docker exec -it container-mysql /bin/bash 61 | vim /etc/nginx/nginx.conf 62 | 63 | # =========================== 6. 自动化重载 64 | sudo docker exec container-mysql nginx -s reload 65 | 66 | # =========================== 7. 启用、停止、删除 67 | docker start container-mysql 68 | docker stop container-mysql 69 | docker rm -f container-mysql 70 | ``` 71 | 72 | #MySQL 73 | ```bash 74 | # =========================== 1. 创建 mysql Dockerfile 75 | sudo mkdir -p /usr/local/docker-mysql 76 | cd /usr/local/docker-mysql 77 | touch Dockerfile 78 | 79 | # =========================== 2. 编辑 Dockerfile 80 | # 使用官方 MySQL 镜像 81 | FROM mysql:latest 82 | # 设置环境变量,用于自动配置 83 | ENV MYSQL_ROOT_PASSWORD=abcd1234 \ 84 | MYSQL_DATABASE=my_db \ 85 | MYSQL_USER=lousanpang \ 86 | MYSQL_PASSWORD=abcd1234 87 | # 设置 MySQL 数据存储目录(可选) 88 | VOLUME /var/lib/mysql 89 | # 暴露 MySQL 默认端口 90 | EXPOSE 3306 91 | 92 | # =========================== 3. 构建镜像 93 | sudo docker build -t container-mysql /usr/local/docker-mysql 94 | 95 | # =========================== 4. 运行容器 96 | docker run -d \ 97 | --name container-mysql \ 98 | -p 3306:3306 \ 99 | -v /mnt/user/mysql-data:/var/lib/mysql \ 100 | container-mysql 101 | 102 | # =========================== 5. 进入容器并配置 103 | sudo docker exec -it container-mysql /bin/bash 104 | mysql -u root -p 105 | show databases; 106 | use my_db; 107 | show tables; 108 | exit 109 | 110 | # =========================== 6. 启用、停止、删除 111 | docker ps 112 | docker start container-mysql 113 | docker stop container-mysql 114 | docker rm -f container-mysql 115 | 116 | # =========================== 7. 登录 MySQL 容器 117 | docker exec -it container-mysql mysql -uroot -p 118 | # 查看初始化的数据库和用户 119 | SHOW DATABASES; 120 | SELECT User, Host FROM mysql.user; 121 | ``` 122 | :: 123 | 124 |
125 | 126 | ## Docker 与 Nginx 的项目应用 127 | 128 | ::tabs 129 | --- 130 | tabs: [ 'directory', 'docker', 'nginx' ] 131 | --- 132 | 133 | #directory 134 | ```bash 135 | - docker 136 | - nginx.conf 137 | - .dockerignore 138 | - Dockerfile 139 | ``` 140 | 141 | #docker 142 | ```bash 143 | FROM nginx:latest 144 | LABEL maintainer="LOUSANPANG<1271255653@qq.com>" 145 | 146 | COPY docker/nginx.conf /etc/nginx/nginx.conf 147 | 148 | RUN mkdir -p /root/www/web/dist 149 | COPY dist /root/www/web/dist 150 | 151 | EXPOSE 80 152 | 153 | CMD ["nginx", "-g", "daemon off;"] 154 | tail -f /var/log/nginx/access_www.log 155 | ``` 156 | 157 | #nginx 158 | ```bash 159 | user nginx; # 设置运行Nginx的用户 160 | worker_processes auto; # 自动设置工作进程数 161 | 162 | events { 163 | worker_connections 1024; # 每个进程的最大连接数 164 | } 165 | 166 | http { 167 | include /etc/nginx/mime.types; # MIME类型配置 168 | default_type application/octet-stream; # 默认MIME类型 169 | 170 | sendfile on; # 启用高效文件传输 171 | keepalive_timeout 65; # 保持连接的超时时间 172 | 173 | server { 174 | listen 80; # 监听80端口 175 | server_name localhost; # 根据需要更改为你的域名或IP 176 | 177 | location / { 178 | root /root/qiuyan/web; # 代理到此目录 179 | index index.html index.htm; # 默认文件 180 | try_files $uri $uri/ =404; # 文件查找策略 181 | } 182 | 183 | error_page 404 /404.html; # 404错误页面 184 | location = /404.html { 185 | internal; # 仅内部使用 186 | } 187 | 188 | error_page 500 502 503 504 /50x.html; # 500系列错误页面 189 | location = /50x.html { 190 | internal; # 仅内部使用 191 | } 192 | } 193 | 194 | # 可添加其他server块或配置 195 | } 196 | ``` 197 | :: 198 | 199 |
200 | 201 | ## 参考链接 202 | 203 | [NGINX 可视化选项配置](https://www.digitalocean.com/community/tools/nginx?global.app.lang=zhCN){.doclink} 204 | [Nginx安装配置详解](https://mp.weixin.qq.com/s/Cd9T_nhAtJ8hI6waEzZiEg){.doclink} 205 | -------------------------------------------------------------------------------- /content/docs/900.standard-deploy/2.applet.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: '小程序' 3 | --- 4 | -------------------------------------------------------------------------------- /content/docs/900.standard-deploy/3.app.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'App' 3 | --- 4 | 5 | ## 账号注册 6 | 7 | ### Apple 开发者账号注册 8 | - 资料准备 9 | - 注册D-U-N-S邓白氏编码 10 | - 法人名称(记住英文名称,申请开发者账户需用)、法人相关信息(身份证、邮箱、电话)、公司相关信息(营业执照、地址、公司邮箱、电话、公司网站、隐私协议网址) 11 | - 材料上传至 - 邓白氏自助服务平台 12 | - 安装Developer软件 13 | - 登录Apple ID 14 | - 注册Apple Developer Program 15 | - 注册者实名认证 -> 姓氏、名字、身份证号、手机号、人连拍照 16 | - 选择组织开发者 -> 法人相关信息(身份证、邮箱、电话)、公司相关信息(公司邮箱、电话、地址、营业执照、网址)、DUNS相关信息(法人实体英文名称[公司全称英文]、邓白氏编码)、申请人相关信息(身份证件、雇佣证明、员工工牌或名牌) 17 | - 699RMB 18 | - 登录 iOS Dev Center 19 | - 配置证书、文件 20 | - 添加开发者手机 21 | 22 | [最新苹果邓白氏编码申请流程](https://blog.csdn.net/weixin_41474319/article/details/135948716?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ECtr-3-135948716-blog-140545518.235%5Ev43%5Epc_blog_bottom_relevance_base7&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ECtr-3-135948716-blog-140545518.235%5Ev43%5Epc_blog_bottom_relevance_base7&utm_relevant_index=6){.doclink} 23 | [注册 D-U-N-S 邓白氏编码](https://support.dnb.com/?CUST=APPLEDEV){.doclink} 24 | [材料上传至 - 邓白氏自助服务平台](https://www.dnbportal.cn/){.doclink} 25 | [注册 `Apple Developer Program`](https://developer.apple.com/cn/support/app-account){.doclink} 26 | [登录 iOS Dev Center](https://developer.apple.com/account){.doclink} 27 | 28 |
29 | 30 | ### Google Play 开发者账号注册 31 | 32 | [完整的Google企业账号申请流程](https://zhuanlan.zhihu.com/p/710460516){.doclink} 33 | 34 |
35 | 36 | ## 打包 37 | 38 | ### 配置签名、证书、描述文件 39 | [iOS 证书和描述文件申请](https://ask.dcloud.net.cn/article/152){.doclink} 40 | [Android 签名证书生成指南](https://ask.dcloud.net.cn/article/35777){.doclink} 41 | 42 |
43 | 44 | ### App 打包配置 45 | [基础配置](https://uniapp.dcloud.net.cn/tutorial/app-base.html){.doclink} 46 | [图标配置](https://uniapp.dcloud.net.cn/tutorial/app-icons.html){.doclink} 47 | [启动界面](https://uniapp.dcloud.net.cn/tutorial/app-splashscreen.html){.doclink} 48 | [功能模块](https://uniapp.dcloud.net.cn/tutorial/app-modules.html){.doclink} 49 | [权限配置](https://uniapp.dcloud.net.cn/tutorial/app-permission-android.html){.doclink} 50 | [其他设置](https://uniapp.dcloud.net.cn/tutorial/app-webview-error.html){.doclink} 51 | 52 |
53 | 54 | ## iOS 上架 55 | 56 | ### TestFlight 内测 57 | - 准备工作 58 | - 苹果开发者官网新增App组 59 | - 打包IOS App 60 | - 使用 `Transporter` 上传包 61 | - 邀请、安装 62 | - 通过公开链接邀请测试员,App 的“TestFlight”页面 --> 按现有的群组 --> 启用公开链接 --> 拷贝链接分享 63 | - 通过电子邮件邀请测试员,并附上用于安装 App 和开始测试的链接 64 | - 测试信息,在 App Store Connect 中相应 App 的“测试信息”页面上设置分享 App 的内容公告 65 | - 内部测试人员也可以使用 TestFlight App 安装 App,通过链接获取兑换码进行安装,该 APP 有新版本会自动更新安装,仅支持OS系统 66 | - 内部100名、外部测试人员10000名,上传构建版本的那一天起,每个构建版本有最多 90 天的时间可供测试 67 | 68 | [TestFlight 指南](https://developer.apple.com/cn/testflight/){.doclink} 69 | [TestFlight APP使用教程](https://testflight.apple.com/){.doclink} 70 | [包上传工具](https://help.apple.com/app-store-connect/#/devb1c185036){.doclink} 71 | 72 |
73 | 74 | ### AppStore 上架 75 | - 登录 AppStore Connect 76 | - 创建 App,配置 App 的基础信息 77 | - 使用 `Transporter` 上传包 78 | 79 |
80 | 81 | ## Android 上架 82 | [国内应用市场上架](https://uniapp.dcloud.net.cn/tutorial/store.html){.doclink} 83 | [合规、隐私协议](https://uniapp.dcloud.net.cn/tutorial/android-store.html){.doclink} 84 | 85 | ### Google Play 上架 86 | - 登录 Google Play Console 87 | - 账号 88 | - 验证组织网站 Google Search Console 89 | - 创建应用,配置应用基础信息 90 | - Graphics 91 | - Logo 512*512 92 | - Feature graphic 1,024*500 93 | - Phone screenshots 16:9 or 9:16 94 | - 7-inch tablet screenshots 16:9 or 9:16 95 | - 10-inch tablet screenshots 16:9 or 9:16 96 | - 上传包 97 | - SDK >= 34 98 | 99 | [Google Play Console](https://play.google.com/console/u/0/signup){.doclink} 100 | 101 |
102 | 103 | ### 国内应用市场 104 | -------------------------------------------------------------------------------- /content/docs/900.standard-deploy/_dir.yml: -------------------------------------------------------------------------------- 1 | title: 集成部署 2 | -------------------------------------------------------------------------------- /error.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 38 | 39 | 68 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import antfu from '@antfu/eslint-config' 3 | import withNuxt from './.nuxt/eslint.config.mjs' 4 | 5 | export default withNuxt( 6 | antfu(), 7 | ) 8 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 25 | 26 | 40 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 LOUSANPANG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /middleware/analytics.global.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware((to, from) => { 2 | // https://nuxt.com/docs/getting-started/routing#route-middleware 3 | // 全局路由中间件 4 | }) 5 | -------------------------------------------------------------------------------- /middleware/auth.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware((to, from) => { 2 | // https://nuxt.com/docs/getting-started/routing#route-middleware 3 | // 页面路由中间件 4 | // return navigateTo('/') 5 | }) 6 | -------------------------------------------------------------------------------- /nuxt.config.ts: -------------------------------------------------------------------------------- 1 | export default defineNuxtConfig({ 2 | 3 | modules: [ 4 | '@nuxt/eslint', 5 | '@nuxt/content', 6 | '@unocss/nuxt', 7 | ], 8 | devtools: { enabled: true }, 9 | 10 | content: { 11 | highlight: { 12 | theme: { 13 | default: 'github-dark-dimmed', 14 | }, 15 | langs: [ 16 | 'js', 17 | 'ts', 18 | 'vue', 19 | 'css', 20 | 'scss', 21 | 'sass', 22 | 'html', 23 | 'bash', 24 | 'md', 25 | 'mdc', 26 | 'json', 27 | ], 28 | }, 29 | }, 30 | 31 | compatibilityDate: '2024-10-14', 32 | 33 | vite: { 34 | css: { 35 | preprocessorOptions: { 36 | scss: { 37 | api: 'modern-compiler', 38 | }, 39 | }, 40 | }, 41 | }, 42 | 43 | eslint: { 44 | config: { 45 | stylistic: true, 46 | standalone: false, 47 | }, 48 | }, 49 | }) 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fe-workflow", 3 | "type": "module", 4 | "license": "MIT", 5 | "engines": { 6 | "node": ">=18.0.0" 7 | }, 8 | "scripts": { 9 | "prepare": "husky", 10 | "postinstall": "nuxt prepare && npx only-allow pnpm", 11 | "clean": "nuxt cleanup", 12 | "dev": "nuxt dev", 13 | "build": "nuxt build", 14 | "generate": "nuxt generate", 15 | "preview": "nuxt preview", 16 | "typecheck": "nuxt typecheck", 17 | "upgrade": "nuxt upgrade", 18 | "lint": "eslint .", 19 | "lint:fix": "eslint . --fix" 20 | }, 21 | "dependencies": { 22 | "@nuxt/content": "^2.13.4", 23 | "@unocss/reset": "^0.63.6", 24 | "vue": "^3.5.12", 25 | "vue-router": "^4.4.5" 26 | }, 27 | "devDependencies": { 28 | "@antfu/eslint-config": "^3.8.0", 29 | "@iconify-json/carbon": "^1.2.3", 30 | "@nuxt/eslint": "^0.6.0", 31 | "@unocss/extractor-mdc": "^0.63.6", 32 | "@unocss/nuxt": "^0.63.6", 33 | "@unocss/transformer-directives": "^0.63.6", 34 | "eslint": "^9.13.0", 35 | "husky": "^9.1.6", 36 | "lint-staged": "^15.2.10", 37 | "nuxt": "^3.13.2", 38 | "sass": "^1.80.3", 39 | "unocss": "^0.63.6" 40 | }, 41 | "lint-staged": { 42 | "*": "eslint --fix" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pages/concept/[...slug].vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 71 | -------------------------------------------------------------------------------- /pages/docs/[...slug].vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 71 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 121 | 122 | 148 | -------------------------------------------------------------------------------- /public/content/concept/js_prototype_chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/public/content/concept/js_prototype_chain.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/public/favicon.ico -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LOUSANPANG/fe-workflow/c90807248b6b40ff70d35b28836b6c1d162ad41d/public/logo.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /types/navigation.ts: -------------------------------------------------------------------------------- 1 | export interface RouteType { 2 | title: string, 3 | _path: string, 4 | icon?: string, 5 | children?: RouteType[] 6 | } 7 | 8 | export interface linkType { 9 | depth: number, 10 | id: string, 11 | text: string, 12 | children?: linkType[] 13 | } 14 | export interface tocType { 15 | title: string, 16 | depth: number, 17 | searchDepth: number, 18 | links: linkType[] 19 | } 20 | -------------------------------------------------------------------------------- /uno.config.ts: -------------------------------------------------------------------------------- 1 | import extractorMdc from '@unocss/extractor-mdc' 2 | import transformerDirectives from '@unocss/transformer-directives' 3 | import { 4 | defineConfig, 5 | presetIcons, 6 | presetUno, 7 | presetWebFonts, 8 | } from 'unocss' 9 | 10 | export default defineConfig({ 11 | theme: { 12 | breakpoints: { 13 | mobile: '320px', 14 | pc: '1280px', 15 | }, 16 | colors: { 17 | primary: '#0ea5e9', 18 | success: '#10B981', 19 | warning: '#F59E0B', 20 | danger: '#EF4444', 21 | dark: '#0f172a', 22 | light: '#f8fafc', 23 | hover: '#0ea5e9', 24 | slate: { 25 | 50: '#f8fafc', 26 | 100: '#f1f5f9', 27 | 200: '#e2e8f0', 28 | 300: '#cbd5e1', 29 | 400: '#94a3b8', 30 | 500: '#64748b', 31 | 600: '#475569', 32 | 700: '#334155', 33 | 800: '#1e293b', 34 | 900: '#0f172a', 35 | }, 36 | }, 37 | }, 38 | 39 | presets: [ 40 | presetUno(), 41 | presetIcons(), 42 | presetWebFonts({ 43 | provider: 'google', 44 | fonts: { 45 | 'ubuntu-sans': 'Ubuntu Sans', 46 | }, 47 | }), 48 | ], 49 | 50 | transformers: [ 51 | transformerDirectives(), 52 | ], 53 | 54 | extractors: [ 55 | extractorMdc(), 56 | ], 57 | }) 58 | --------------------------------------------------------------------------------