├── .gitignore ├── .node-version ├── .npmrc ├── .prettierrc ├── LICENSE ├── README.md ├── docs ├── .vuepress │ ├── config.js │ ├── enhanceApp.js │ ├── public │ │ ├── _redirects │ │ ├── geneva-switzerland-narrow.jpg │ │ ├── geneva-switzerland.jpeg │ │ ├── js-logo-vue-color.png │ │ ├── js-logo.jpg │ │ ├── js-nation-square-blue.png │ │ ├── js-nation-square.png │ │ └── photo-1483653085484-eb63c9f02547.jpeg │ ├── sidebar.js │ ├── styles │ │ ├── index.styl │ │ └── palette.styl │ └── vue-redirect.js ├── README.md └── note │ ├── 00.resources │ ├── 1.awesome-tools.md │ ├── 2.where-do-i-learn-from.md │ ├── 3.my-reading-list.md │ ├── 4.crash-course-study-skills.md │ ├── 5.using-english.md │ └── the-digital-productivity-pyramid.jpeg │ ├── 02.workspace │ ├── 0.mac.md │ ├── 1.chrome.md │ └── 2.vscode.md │ ├── 08.misc │ ├── clean-a-keyboard.md │ ├── gaming-set.md │ ├── linux-basic-security.md │ ├── my-video-player-shortcuts.md │ ├── scc │ │ ├── count-lines-of-code.md │ │ └── img │ │ │ ├── time-cloc-babel-fs8.png │ │ │ ├── time-loc-babel-fs8.png │ │ │ ├── time-scc-babel-fs8.png │ │ │ └── time-tokei-babel-fs8.png │ └── study │ │ ├── dont-waste-your-time-and-money.md │ │ ├── study-fortune.md │ │ └── why-we-need-to-study.md │ ├── 10.frontend │ ├── 01.web │ │ ├── 1.html.md │ │ ├── 2.css.md │ │ ├── 3.javascript-language-basic.md │ │ ├── 4.typescript-language-basic.md │ │ └── 5.nodejs-basic.md │ ├── 02.javascript │ │ ├── 1.javascript-foundation.md │ │ ├── 2.introduction-to-javascript.md │ │ ├── 3.how-to-run-javascript-code.md │ │ ├── 4.javascript-advanced.md │ │ ├── 5.syntactic-sugar-in-javascript.md │ │ ├── 6.javascript-modules.md │ │ ├── 7.javascript-regular-expression.md │ │ └── 8.javascript-foundation-legacy-version.md │ ├── 03.npm │ │ ├── 1.introduction-to-npm.md │ │ ├── 2.speeding-up-npm-install.md │ │ └── 3.set-up-a-private-npm-registry-using-verdaccio.md │ ├── 04.react │ │ └── 1.react-hooks.md │ ├── 05.state-management │ │ ├── 3.rxjs.md │ │ └── 4.redux.md │ ├── 08.javascript-test │ │ ├── 2.jest.md │ │ ├── 3.testing-library.md │ │ └── 4.cypress.md │ └── frontend-hardcore-overview │ │ ├── frontend-hardcore-overview.md │ │ └── img │ │ ├── dk-effect.jpg │ │ ├── fe-hardcore-fs8.png │ │ ├── fe-naive-fs8.png │ │ ├── go-home.jpeg │ │ ├── stateofjs2019-dark-fs8.png │ │ └── stateofjs2019tshirt-illustration.png │ ├── 20.computer-science │ ├── 1.crash-course-computer-science.md │ ├── 2.introduction-to-functional-programming.md │ └── map-of-computer-science-fs8.png │ ├── 21.tool-skills │ ├── 01.git │ │ ├── git.md │ │ └── img │ │ │ ├── git-cheatsheet-cn.jpeg │ │ │ ├── git-flow-fs8.png │ │ │ └── git-mindmap-fs8.png │ ├── 02.markdown.md │ ├── 31.introduction-to-terminal.md │ ├── 32.terminal-settings.md │ ├── iterm2-showcase.png │ └── shell.md │ ├── 23.programming-language │ └── python-language-basic.md │ ├── 99.about │ ├── about-me.md │ ├── about-the-guild.md │ ├── about-the-site.md │ └── ref.md │ └── frontend-development-cookbook.md ├── google3ceb9a355a21cbf4.html ├── package.json ├── pnpm-lock.yaml ├── scripts ├── 301-record.ts ├── check-broken-links.ts ├── list-notes.ts └── update-config-files.ts ├── tsconfig.json └── vercel.json /.gitignore: -------------------------------------------------------------------------------- 1 | # * ---------------------------------------------------------------- 2 | 3 | # Created by https://www.gitignore.io/api/node 4 | # Edit at https://www.gitignore.io/?templates=node 5 | 6 | ### Node ### 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | 15 | # Diagnostic reports (https://nodejs.org/api/report.html) 16 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 17 | 18 | # Runtime data 19 | pids 20 | *.pid 21 | *.seed 22 | *.pid.lock 23 | 24 | # Directory for instrumented libs generated by jscoverage/JSCover 25 | lib-cov 26 | 27 | # Coverage directory used by tools like istanbul 28 | coverage 29 | *.lcov 30 | 31 | # nyc test coverage 32 | .nyc_output 33 | 34 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 35 | .grunt 36 | 37 | # Bower dependency directory (https://bower.io/) 38 | bower_components 39 | 40 | # node-waf configuration 41 | .lock-wscript 42 | 43 | # Compiled binary addons (https://nodejs.org/api/addons.html) 44 | build/Release 45 | 46 | # Dependency directories 47 | node_modules/ 48 | jspm_packages/ 49 | 50 | # TypeScript v1 declaration files 51 | typings/ 52 | 53 | # TypeScript cache 54 | *.tsbuildinfo 55 | 56 | # Optional npm cache directory 57 | .npm 58 | 59 | # Optional eslint cache 60 | .eslintcache 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # next.js build output 79 | .next 80 | 81 | # nuxt.js build output 82 | .nuxt 83 | 84 | # vuepress build output 85 | .vuepress/dist 86 | 87 | # Serverless directories 88 | .serverless/ 89 | 90 | # FuseBox cache 91 | .fusebox/ 92 | 93 | # DynamoDB Local files 94 | .dynamodb/ 95 | 96 | # End of https://www.gitignore.io/api/node 97 | n 98 | 99 | # * ---------------------------------------------------------------- 100 | 101 | /dist 102 | /public 103 | @pages/ 104 | 105 | tempCodeRunnerFile.* 106 | draft/ 107 | TODO.* -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 16 -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmmirror.com/ 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "arrowParens": "always", 4 | "trailingComma": "all", 5 | "tabWidth": 2, 6 | "singleQuote": true, 7 | "quoteProps": "consistent", 8 | "semi": true, 9 | "useTabs": false, 10 | "overrides": [ 11 | { 12 | "files": "*.md", 13 | "options": { 14 | "printWidth": 60 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 seognil 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | ![the-banner](./docs/.vuepress/public/geneva-switzerland-narrow.jpg) 4 | 5 |

6 | 7 |

一个前端指南

8 | 9 |

10 | 11 | → 在线阅读 ← 12 | 13 |

14 | 15 | ## 关于 16 | 17 | > 这个世界需要的不是英雄,而是专家。 —— 利维亚的杰洛特 18 | 19 | 我是 LC,目前是一个想要实现财务和代码双自由的前端工程师。 20 | 21 | 我没有名校光环、也没有大厂背景。2015 年刚毕业的时候,我在上海的一个小网游公司当 IT(就是修电脑的),工资不到三千块,每天的工作就是重装系统,做网线,换鼠标啥的,从早到晚忙忙碌碌。我记得公司边上有一个小饭店,一顿饭两荤一素只要 12 块钱,真好吃,不知道几年过去了有没有涨价。 22 | 23 | 算了一下收支,想要在上海买房得要几百年吧,我想我不能再这样下去了,我得支棱起来啊。后来我开始慢慢自学开发。前端的门槛还是比较低的,电脑浏览器随便打开一个页面,打开控制台,就可以入门了。 24 | 25 | 做开发头几年的时候啥也不会,也没有贵人相助,也难碰到志同道合的伙伴,我走了非常多的弯路。所谓走弯路,是指看了很多良莠不齐的资料,职业规划和心态也迷雾重重,直到 2019 年的时候,我还在用 ES5 和 jQuery 这样的上古技术。而我目前的大部分技能,无论是 React、TypeScript 等现代前端技术;还是算法、设计模式、代码设计原则等科班基础;甚至还有英语、如何与人沟通、写作、理财等等写代码以外的能力。这些实际上都是在两年内起步的。 26 | 27 | 从看菜鸟教程上的简单文档,到翻看 ECMA-262。 28 | 从跟着慕课网的视频教程,到看 Youtube 上的各种 Dev Conf。 29 | 我见到了更广阔的世界,知道从哪获取优质的信息。也对于自己的学习和技术能力越来越有自信,甚至开始有能力帮助周围的朋友和同事。 30 | 31 | 更重要的是,我现在的收入可比当初提高了不知道多少倍,增速比 APPLE 的股票都快(可惜没跑赢 NVIDIA 和 AMD),虽然离财务自由还非常遥远。但是吃饭自由已经不成问题了,去沙县大饭店的时候可以毫无顾忌随便点了~ 32 | 33 | 我想,如果我能早点意识到这些,或者有机会告诉十年前的我,努力学习赚钱真的爽。那该多好。 34 | 🎶 那么多如果,可能如果我,可惜没如果 🎶 35 | 还好,现在也不算太晚。种一棵树最好的时间是十年前,其次是现在。 36 | 37 | 本站是我自己在学习前端技能过程中的记录,包含学习路径、学习笔记和采坑经验、写的 Demo 和代码片段、收集整理的自学材料等。 38 | 39 | 写给自己,也写给其他人,希望能够有所帮助。 40 | 41 | 文笔不好,以及还在不断学新东西,旧的知识也有新的理解,慢慢修订和更新吧。 42 | 43 | > 写给我的朋友,东神、阿辉、兔子。 44 | 45 | ## 内容 46 | 47 | 线上地址: 48 | 49 | - 50 | 51 | 镜像地址: 52 | 53 | - :Powered By [Cloudflare Pages](https://dash.cloudflare.com/8144c624bc3fd1e60ba8932cdf4949e4/pages/view/rualc) 54 | - :Powered By [Vercel](https://vercel.com/seognil/rualc) 55 | 56 | 主要文章: 57 | 58 | - 导览 59 | - [前端开发入门指南](https://rualc.me/note/frontend-development-cookbook) 60 | - 系列文章 61 | - [开发环境配置系列](https://rualc.me/workspace/awesome-tools) 62 | - [JavaScript 学习系列](https://rualc.me/frontend/javascript-foundation) 63 | - [Node 基础系列](https://rualc.me/frontend/nodejs-basic) 64 | - [其他学习指南系列](https://rualc.me/study/crash-course-study-skills) 65 | 66 | 以及,授人以鱼不如授人以渔: 67 | 68 | - [我都从哪学习](https://rualc.me/study/where-do-i-learn-from) 69 | 70 | ## WIP 71 | 72 | 写作计划和开发任务现在使用 [GitHub Projects](https://github.com/seognil/fe-foundation/projects/1) 进行管理。 73 | 74 | ## Stargazers over time 75 | 76 | [![Stargazers over time](https://starchart.cc/seognil/fe-foundation.svg)](https://starchart.cc/seognil/fe-foundation) 77 | 78 | --- 79 | 80 | [捉虫请提 issue](https://github.com/seognil/fe-foundation/issues/new) 81 | 82 | [MIT](LICENSE) - 2019 83 | [知识共享协议 CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh) 84 | Made with ❤️ by Seognil LC 85 | -------------------------------------------------------------------------------- /docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | const dayjs = require('dayjs'); 2 | const localizedFormat = require('dayjs/plugin/localizedFormat'); 3 | const utc = require('dayjs/plugin/utc'); 4 | dayjs.extend(localizedFormat); 5 | dayjs.extend(utc); 6 | 7 | // const sidebar = require('./sidebar'); 8 | 9 | const markdownItAttrs = require('markdown-it-attrs'); 10 | const { slugify } = require('transliteration'); 11 | 12 | // * ---------------------------------------------------------------- 13 | 14 | const AboutMe = { 15 | author: { 16 | name: 'Seognil LC', 17 | link: 'https://github.com/seognil', 18 | }, 19 | blogger: { 20 | avatar: 'https://avatars.githubusercontent.com/u/5526096?s=400', 21 | name: 'Seognil LC', 22 | slogan: '略懂点前端', 23 | }, 24 | social: { 25 | icons: [ 26 | { 27 | iconClass: 'fab fa-github', 28 | title: 'GitHub', 29 | link: 'https://github.com/seognil', 30 | }, 31 | { 32 | iconClass: 'fab fa-steam', 33 | title: 'Steam', 34 | link: 'https://steamhunters.com/id/seognil/games?sort=completionstate', 35 | }, 36 | { 37 | iconClass: 'fab fa-playstation', 38 | title: 'PSN', 39 | link: 'https://psnprofiles.com/seognil?order=percent', 40 | }, 41 | { 42 | iconClass: 'fab fa-xbox', 43 | title: 'Xbox', 44 | link: 'https://www.trueachievements.com/gamer/seognil/games#', 45 | }, 46 | ], 47 | }, 48 | footer: { 49 | createYear: 2019, 50 | copyrightInfo: 51 | 'Seognil LC | MIT License', 52 | }, 53 | }; 54 | 55 | // * ---------------------------------------------------------------- config 56 | 57 | const config = { 58 | title: '前端指南', 59 | description: '一个前端工程师的自我修养', 60 | head: [ 61 | ['link', { rel: 'icon', type: 'image/jpg', href: '/js-nation-square-blue.png' }], 62 | [ 63 | 'meta', 64 | { 65 | name: 'keywords', 66 | content: [ 67 | 'computer-science', 68 | 'checklist', 69 | 'roadmap', 70 | 'study', 71 | 'frontend', 72 | 'notes', 73 | 'guide', 74 | 'developer', 75 | 'awesome-list', 76 | 'engineer', 77 | ].join(','), 78 | }, 79 | ], 80 | ], 81 | 82 | dest: './public', 83 | 84 | theme: 'vdoing', 85 | 86 | // * ------------------------------------------------ 87 | 88 | themeConfig: { 89 | ...AboutMe, 90 | 91 | // * ---------------- blog config 92 | 93 | repo: 'seognil/fe-foundation', 94 | 95 | lastUpdated: '上次更新', 96 | // editLinks: true, 97 | 98 | // * ---------------- theme config 99 | 100 | logo: '/js-nation-square-blue.png', 101 | 102 | bodyBgImg: [ 103 | // 'https://images.unsplash.com/photo-1542416409-400da26855b5?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2734&q=80', 104 | // 'https://images.unsplash.com/photo-1561160767-6bbd75de51b8?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2851&q=80', 105 | // 'https://images.unsplash.com/photo-1483653085484-eb63c9f02547?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=2850&q=80', 106 | '/photo-1483653085484-eb63c9f02547.jpeg', 107 | ], 108 | bodyBgImgOpacity: 0.1, 109 | 110 | contentBgStyle: 6, 111 | 112 | // * ---------------- 113 | 114 | nav: [ 115 | { text: '指南', link: '/note/frontend-development-cookbook' }, 116 | { text: '资源', link: '/study/where-do-i-learn-from/' }, 117 | { 118 | text: '代码训练', 119 | items: [ 120 | { text: '刷力扣', link: 'https://github.com/seognil-study/leetcode' }, 121 | { text: '手写题', link: 'https://github.com/seognil-study/learn-by-doing' }, 122 | ], 123 | }, 124 | { 125 | text: '归档', 126 | link: '/archives/', 127 | items: [ 128 | { text: '归档', link: '/archives/' }, 129 | { text: '分类', link: '/categories/' }, 130 | { text: '标签', link: '/tags/' }, 131 | ], 132 | }, 133 | { 134 | text: '关于', 135 | link: '/about/me', 136 | items: [ 137 | { text: '关于我', link: '/about/me/' }, 138 | { text: '关于本站', link: '/about/the-site/' }, 139 | ], 140 | }, 141 | ], 142 | 143 | // sidebarDepth: 3, 144 | sidebar: 'auto', 145 | }, 146 | 147 | // * ------------------------------------------------ 148 | 149 | plugins: [ 150 | [ 151 | '@vuepress/last-updated', 152 | { 153 | transformer: (timestamp, lang) => { 154 | return dayjs.utc(timestamp).utcOffset(8).format('lll'); 155 | }, 156 | }, 157 | ], 158 | 'vuepress-plugin-smooth-scroll', 159 | // [ 160 | // 'vuepress-plugin-medium-zoom', 161 | // { 162 | // selector: 'img', 163 | // delay: 1000, 164 | // options: { 165 | // // margin: 24, 166 | // background: 'hsla(0, 0%, 0%, 0.1)', 167 | // scrollOffset: 0, 168 | // }, 169 | // }, 170 | // ], 171 | // [ 172 | // 'vuepress-plugin-zooming', 173 | // { 174 | // selector: 'img', 175 | // delay: 1000, 176 | // options: { 177 | // bgColor: 'hsla(0, 0%, 0%, 0.1)', 178 | // // zIndex: 10000, 179 | // }, 180 | // }, 181 | // ], 182 | ], 183 | cache: false, 184 | markdown: { 185 | lineNumbers: true, 186 | 187 | // https://v1.vuepress.vuejs.org/guide/markdown.html#advanced-configuration 188 | // options for markdown-it-anchor 189 | anchor: { 190 | level: 2, 191 | slugify: (str) => slugify(str), 192 | }, 193 | extendMarkdown: (md) => { 194 | md.use(markdownItAttrs, { 195 | leftDelimiter: '{', 196 | rightDelimiter: '}', 197 | }); 198 | }, 199 | }, 200 | extendPageData($page) { 201 | const p = $page; 202 | 203 | // * ---------------- fix markdown-it-attrs for sidebar 204 | 205 | const removeAnchorAttr = (str) => str.replace(/\s{[^}]*}\s*$/, ''); 206 | 207 | if (p.title) { 208 | p.title = removeAnchorAttr(p.title); 209 | } 210 | 211 | if (p.headers) { 212 | p.headers.forEach((h) => { 213 | h.title = removeAnchorAttr(h.title); 214 | }); 215 | } 216 | 217 | // * ---------------- 218 | }, 219 | }; 220 | 221 | // * ---------------------------------------------------------------- output 222 | 223 | module.exports = config; 224 | -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | const vueRedirect = require('./vue-redirect.js'); 2 | 3 | export default ({ router }) => { 4 | router.addRoutes(vueRedirect); 5 | }; 6 | -------------------------------------------------------------------------------- /docs/.vuepress/public/_redirects: -------------------------------------------------------------------------------- 1 | /about/index.html /about/me 301 2 | /about/ /about/me 301 3 | /note/about-the-guild.html /about/the-guild 301 4 | /note/readme.html /about/the-site 301 5 | /note/cloc.html /cs/count-lines-of-code 301 6 | /note/computer-science.html /cs/crash-course-computer-science 301 7 | /note/git.html /cs/git 301 8 | /note/functional-programming.html /cs/introduction-to-functional-programming 301 9 | /note/js-basic.html /cs/javascript-language-basic 301 10 | /note/js-basic /cs/javascript-language-basic 301 11 | /note/markdown.html /cs/markdown 301 12 | /note/python-language-basic.html /cs/python-language-basic 301 13 | /note/python-language-basic /cs/python-language-basic 301 14 | /note/typescript.html /cs/typescript-language-basic 301 15 | /note/css.html /frontend/css 301 16 | /note/cypress.html /frontend/cypress 301 17 | /note/fe-hardcore-overview.html /frontend/frontend-hardcore-overview 301 18 | /note/how-to-run-js.html /frontend/how-to-run-javascript-code 301 19 | /note/html.html /frontend/html 301 20 | /note/js-intro.html /frontend/introduction-to-javascript 301 21 | /note/npm-overview.html /frontend/introduction-to-npm 301 22 | /note/js-advanced.html /frontend/javascript-advanced 301 23 | /note/js-foundation.html /frontend/javascript-foundation 301 24 | /note/js-foundation-old.html /frontend/javascript-foundation-legacy-version 301 25 | /note/js-modular.html /frontend/javascript-modules 301 26 | /note/regexp.html /frontend/javascript-regular-expression 301 27 | /note/jest.html /frontend/jest 301 28 | /note/node-basic.html /frontend/nodejs-basic 301 29 | /note/react-hooks.html /frontend/react-hooks 301 30 | /note/redux.html /frontend/redux 301 31 | /note/redux-observable.html /frontend/redux-observable 301 32 | /note/rxjs.html /frontend/rxjs 301 33 | /note/npm-verdaccio.html /frontend/set-up-a-private-npm-registry-using-verdaccio 301 34 | /note/npm-speedup.html /frontend/speeding-up-npm-install 301 35 | /note/syntactic-sugar.html /frontend/syntactic-sugar-in-javascript 301 36 | /note/testing-library.html /frontend/testing-library 301 37 | /note/clean-keyboard.html /misc/clean-a-keyboard 301 38 | /note/linux-basic-security.html /misc/linux-basic-security 301 39 | /note/fe-development-cookbook.html /note/frontend-development-cookbook 301 40 | /note/fe-development-cookbook /note/frontend-development-cookbook 301 41 | /note/fe-development-cookbook-old.html /note/frontend-development-cookbook 301 42 | /note/fe-development-cookbook-old /note/frontend-development-cookbook 301 43 | /note/frontend-development-cookbook.html /note/frontend-development-cookbook 301 44 | /note/study-methodology.html /study/crash-course-study-skills 301 45 | /note/study-the-costly-way.html /study/dont-waste-your-time-and-money 301 46 | /study/study-the-costly-way.html /study/dont-waste-your-time-and-money 301 47 | /study/study-the-costly-way /study/dont-waste-your-time-and-money 301 48 | /note/study-fortune.html /study/study-fortune 301 49 | /note/study-guild-abstraction.html /study/study-guild-abstraction 301 50 | /note/english-using.html /study/using-english 301 51 | /about/where-do-i-learn-from.html /study/where-do-i-learn-from 301 52 | /about/where-do-i-learn-from /study/where-do-i-learn-from 301 53 | /note/my-reading.html /study/where-do-i-learn-from 301 54 | /note/study-the-only-way.html /study/why-we-need-to-study 301 55 | /study/study-the-only-way.html /study/why-we-need-to-study 301 56 | /study/study-the-only-way /study/why-we-need-to-study 301 57 | /note/my-workstation.html /workspace/awesome-tools 301 58 | /note/chrome.html /workspace/chrome 301 59 | /note/terminal-intro.html /workspace/introduction-to-terminal 301 60 | /note/mac.html /workspace/mac 301 61 | /note/video-hotkey.html /workspace/my-video-player-shortcuts 301 62 | /note/terminal-config.html /workspace/terminal-settings 301 63 | /note/vscode.html /workspace/vscode 301 -------------------------------------------------------------------------------- /docs/.vuepress/public/geneva-switzerland-narrow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/.vuepress/public/geneva-switzerland-narrow.jpg -------------------------------------------------------------------------------- /docs/.vuepress/public/geneva-switzerland.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/.vuepress/public/geneva-switzerland.jpeg -------------------------------------------------------------------------------- /docs/.vuepress/public/js-logo-vue-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/.vuepress/public/js-logo-vue-color.png -------------------------------------------------------------------------------- /docs/.vuepress/public/js-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/.vuepress/public/js-logo.jpg -------------------------------------------------------------------------------- /docs/.vuepress/public/js-nation-square-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/.vuepress/public/js-nation-square-blue.png -------------------------------------------------------------------------------- /docs/.vuepress/public/js-nation-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/.vuepress/public/js-nation-square.png -------------------------------------------------------------------------------- /docs/.vuepress/public/photo-1483653085484-eb63c9f02547.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/.vuepress/public/photo-1483653085484-eb63c9f02547.jpeg -------------------------------------------------------------------------------- /docs/.vuepress/sidebar.js: -------------------------------------------------------------------------------- 1 | // const sidebar = { 2 | // '/': [ 3 | // '/note/frontend-development-cookbook', 4 | 5 | // { 6 | // title: '学习资源', 7 | // collapsable: false, 8 | // children: [ 9 | // // 10 | // '/note/00.resources/my-reading-list.md', 11 | // '/note/00.resources/where-do-i-learn-from.md', 12 | // ], 13 | // }, 14 | 15 | // { 16 | // title: '学习技巧', 17 | // collapsable: false, 18 | // children: [ 19 | // '/note/01.study/crash-course-study-skills.md', 20 | // '/note/01.study/using-english.md', 21 | // '/note/01.study/study-fortune.md', 22 | // '/note/01.study/study-guild-abstraction.md', 23 | // '/note/01.study/why-we-need-to-study.md', 24 | // '/note/01.study/dont-waste-your-time-and-money.md', 25 | // ], 26 | // }, 27 | 28 | // { 29 | // title: '开发环境', 30 | // collapsable: false, 31 | // children: [ 32 | // '/note/02.workspace/awesome-tools.md', 33 | // '/note/02.workspace/mac.md', 34 | // '/note/02.workspace/chrome.md', 35 | // '/note/02.workspace/vscode.md', 36 | 37 | // { 38 | // title: '终端', 39 | // collapsable: false, 40 | // children: [ 41 | // '/note/02.workspace/introduction-to-terminal.md', 42 | // '/note/02.workspace/terminal-settings.md', 43 | // ], 44 | // }, 45 | 46 | // { 47 | // title: '脚本', 48 | // collapsable: false, 49 | // children: [ 50 | // // 51 | // '/note/02.workspace/my-video-player-shortcuts.md', 52 | // ], 53 | // }, 54 | // ], 55 | // }, 56 | 57 | // { 58 | // title: '计算机科学', 59 | // collapsable: false, 60 | // children: [ 61 | // '/note/03.computer-science/misc/crash-course-computer-science.md', 62 | // '/note/03.computer-science/misc/introduction-to-functional-programming.md', 63 | 64 | // { 65 | // title: '工具', 66 | // collapsable: false, 67 | // children: [ 68 | // '/note/03.computer-science/tools/git/git.md', 69 | // '/note/03.computer-science/tools/markdown.md', 70 | // '/note/03.computer-science/tools/scc/count-lines-of-code.md', 71 | // ], 72 | // }, 73 | 74 | // { 75 | // title: '语言', 76 | // collapsable: false, 77 | // children: [ 78 | // '/note/03.computer-science/programming-language/javascript-language-basic.md', 79 | // '/note/03.computer-science/programming-language/typescript-language-basic.md', 80 | // '/note/03.computer-science/programming-language/python-language-basic.md', 81 | // ], 82 | // }, 83 | // ], 84 | // }, 85 | 86 | // { 87 | // title: '前端', 88 | // collapsable: false, 89 | // children: [ 90 | // '/note/04.frontend/misc/frontend-hardcore-overview/frontend-hardcore-overview.md', 91 | 92 | // { 93 | // title: 'Web', 94 | // collapsable: false, 95 | // children: [ 96 | // // 97 | // '/note/04.frontend/web/html.md', 98 | // '/note/04.frontend/web/css.md', 99 | // ], 100 | // }, 101 | 102 | // { 103 | // title: 'JavaScript', 104 | // collapsable: false, 105 | // children: [ 106 | // '/note/04.frontend/javascript/javascript-foundation.md', 107 | 108 | // '/note/04.frontend/javascript/introduction-to-javascript.md', 109 | // '/note/04.frontend/javascript/how-to-run-javascript-code.md', 110 | 111 | // '/note/04.frontend/javascript/javascript-advanced.md', 112 | // '/note/04.frontend/javascript/syntactic-sugar-in-javascript.md', 113 | // '/note/04.frontend/javascript/javascript-modules.md', 114 | // '/note/04.frontend/javascript/javascript-regular-expression.md', 115 | 116 | // '/note/04.frontend/javascript/javascript-foundation-legacy-version.md', 117 | // ], 118 | // }, 119 | 120 | // { 121 | // title: 'Node', 122 | // collapsable: false, 123 | // children: [ 124 | // '/note/04.frontend/node/nodejs-basic.md', 125 | // '/note/04.frontend/node/introduction-to-npm.md', 126 | // '/note/04.frontend/node/speeding-up-npm-install.md', 127 | // '/note/04.frontend/node/set-up-a-private-npm-registry-using-verdaccio.md', 128 | // ], 129 | // }, 130 | 131 | // { 132 | // title: '工具库', 133 | // collapsable: false, 134 | // children: [ 135 | // '/note/04.frontend/javascript-library/rxjs.md', 136 | // '/note/04.frontend/javascript-library/react-hooks.md', 137 | // '/note/04.frontend/javascript-library/redux.md', 138 | // '/note/04.frontend/javascript-library/redux-observable.md', 139 | // ], 140 | // }, 141 | 142 | // { 143 | // title: '测试库', 144 | // collapsable: false, 145 | // children: [ 146 | // '/note/04.frontend/javascript-test/jest.md', 147 | // '/note/04.frontend/javascript-test/testing-library.md', 148 | // '/note/04.frontend/javascript-test/cypress.md', 149 | // ], 150 | // }, 151 | // ], 152 | // }, 153 | 154 | // { 155 | // title: '杂项', 156 | // collapsable: false, 157 | // children: [ 158 | // // 159 | // '/note/08.misc/linux-basic-security.md', 160 | // '/note/08.misc/clean-a-keyboard.md', 161 | // '/note/08.misc/gaming-set.md', 162 | // ], 163 | // }, 164 | 165 | // { 166 | // title: 'About', 167 | // collapsable: false, 168 | // children: [ 169 | // '/note/09.about/about-me.md', 170 | // '/note/09.about/about-the-site.md', 171 | // '/note/09.about/about-the-guild.md', 172 | // // '/note/09.about/ref.md', 173 | // ], 174 | // }, 175 | // ], 176 | // }; 177 | 178 | // module.exports = sidebar; 179 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Segoe UI', 'SegoeUI', 'Microsoft YaHei', '微软雅黑', 'SF Pro SC', 'HanHei SC', 3 | 'SF Pro Text', 'Myriad Set Pro', 'SF Pro Icons', 'Apple Legacy Chevron', 'PingFang SC', 4 | 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; 5 | 6 | /** https://www.apple.com.cn/ */ 7 | /* font-family: 'SF Pro SC', 'HanHei SC', 'SF Pro Text', 'Myriad Set Pro', 'SF Pro Icons', 8 | 'Apple Legacy Chevron', 'PingFang SC', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; */ 9 | 10 | /* * https://www.microsoft.com/zh-cn/ */ 11 | /* font-family: 'Segoe UI', SegoeUI, 'Microsoft YaHei', 微软雅黑, 'Helvetica Neue', Helvetica, Arial, 12 | sans-serif; */ 13 | 14 | /** vuepress original */ 15 | /* font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, 16 | Fira Sans, Droid Sans, Helvetica Neue, sans-serif; */ 17 | } 18 | 19 | /* * ------------------------------------------------ ui */ 20 | 21 | /** hide link right-side icon */ 22 | a .icon.outbound { 23 | display: none; 24 | } 25 | 26 | /* * ---------------- sidebar */ 27 | 28 | /** sidebar nav toc */ 29 | li.sidebar-sub-header a { 30 | color: hsl(0, 0%, 50%); 31 | } 32 | 33 | /** side list item overflow */ 34 | /* .right-menu-item a, */ 35 | .sidebar-links li a { 36 | display: block; 37 | overflow: hidden; 38 | text-overflow: ellipsis; 39 | white-space: nowrap; 40 | } 41 | 42 | /* * ---------------- */ 43 | 44 | /** site inner link */ 45 | main a[href^='/'], 46 | main a[href^='#'] { 47 | text-decoration: underline dotted hsla(220, 80%, 60%, 0.5); 48 | color: $accentColor; 49 | } 50 | 51 | /** kbd */ 52 | kbd { 53 | background-color: #eee; 54 | border-radius: 3px; 55 | border: 1px solid #b4b4b4; 56 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 2px 0 0 rgba(255, 255, 255, 0.7) inset; 57 | color: #333; 58 | display: inline-block; 59 | font-size: 0.85em; 60 | font-weight: 700; 61 | line-height: 1; 62 | padding: 2px 4px; 63 | white-space: nowrap; 64 | } 65 | 66 | /** article blockquote */ 67 | blockquote { 68 | color: hsl(0, 0%, 50%); 69 | } 70 | 71 | /* * ---------------- theme override */ 72 | 73 | body .theme-vdoing-content a code { 74 | color: unset; 75 | } 76 | 77 | .theme-mode-light .theme-vdoing-content code { 78 | color: hsl(200, 100%, 20%); 79 | } 80 | 81 | /** bold link hack */ 82 | body .theme-vdoing-content a strong { 83 | color: hsl(220, 80%, 55%); 84 | font-weight: 700; 85 | } 86 | 87 | /* * ---------------- h2 spliter */ 88 | 89 | main h2:nth-of-type(4n + 1) { 90 | border-bottom: 2px solid hsl(0, 50%, 70%); 91 | } 92 | main h2:nth-of-type(4n + 2) { 93 | border-bottom: 2px solid hsl(50, 50%, 70%); 94 | } 95 | main h2:nth-of-type(4n + 3) { 96 | border-bottom: 2px solid hsl(100, 50%, 70%); 97 | } 98 | main h2:nth-of-type(4n + 4) { 99 | border-bottom: 2px solid hsl(220, 50%, 70%); 100 | } 101 | 102 | /* * ---------------- article table */ 103 | 104 | main th, 105 | main td { 106 | padding: 0.3em 0.5em; 107 | } 108 | 109 | /* * ---------------- article custom video timeline */ 110 | 111 | main .timeline-note + ul a + ul, 112 | main .timeline-note + ul a + ul ul { 113 | line-height: 1.3; 114 | font-size: 14px; 115 | color: hsl(0, 0%, 50%); 116 | } 117 | main .timeline-note + ul code { 118 | padding: 0.05rem 0.4rem; 119 | } 120 | 121 | /* * ---------------- article */ 122 | 123 | main.page { 124 | word-break: break-word; 125 | } 126 | 127 | /* * ---------------- cookbook */ 128 | 129 | main .cookbook-page ~ ul { 130 | column-count: 3; 131 | 132 | @media (max-width: 1280px) { 133 | column-count: 2; 134 | } 135 | @media (max-width: 720px) { 136 | column-count: 1; 137 | } 138 | } 139 | 140 | /* * ------------------------------------------------ util */ 141 | 142 | /* * ---------------- fontawesome import and patch */ 143 | 144 | @import url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/fontawesome.min.css); 145 | @import url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/brands.min.css); 146 | 147 | .fab.iconfont { 148 | font-family: 'Font Awesome 5 Brands' !important; 149 | line-height: unset; 150 | } 151 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/palette.styl: -------------------------------------------------------------------------------- 1 | $accentColor = hsl(220, 80%, 60%) 2 | $bannerTextColor = inherit -------------------------------------------------------------------------------- /docs/.vuepress/vue-redirect.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | "path": "/about/index.html", 4 | "redirect": "/about/me" 5 | }, 6 | { 7 | "path": "/about/", 8 | "redirect": "/about/me" 9 | }, 10 | { 11 | "path": "/note/about-the-guild.html", 12 | "redirect": "/about/the-guild" 13 | }, 14 | { 15 | "path": "/note/readme.html", 16 | "redirect": "/about/the-site" 17 | }, 18 | { 19 | "path": "/note/cloc.html", 20 | "redirect": "/cs/count-lines-of-code" 21 | }, 22 | { 23 | "path": "/note/computer-science.html", 24 | "redirect": "/cs/crash-course-computer-science" 25 | }, 26 | { 27 | "path": "/note/git.html", 28 | "redirect": "/cs/git" 29 | }, 30 | { 31 | "path": "/note/functional-programming.html", 32 | "redirect": "/cs/introduction-to-functional-programming" 33 | }, 34 | { 35 | "path": "/note/js-basic.html", 36 | "redirect": "/cs/javascript-language-basic" 37 | }, 38 | { 39 | "path": "/note/js-basic", 40 | "redirect": "/cs/javascript-language-basic" 41 | }, 42 | { 43 | "path": "/note/markdown.html", 44 | "redirect": "/cs/markdown" 45 | }, 46 | { 47 | "path": "/note/python-language-basic.html", 48 | "redirect": "/cs/python-language-basic" 49 | }, 50 | { 51 | "path": "/note/python-language-basic", 52 | "redirect": "/cs/python-language-basic" 53 | }, 54 | { 55 | "path": "/note/typescript.html", 56 | "redirect": "/cs/typescript-language-basic" 57 | }, 58 | { 59 | "path": "/note/css.html", 60 | "redirect": "/frontend/css" 61 | }, 62 | { 63 | "path": "/note/cypress.html", 64 | "redirect": "/frontend/cypress" 65 | }, 66 | { 67 | "path": "/note/fe-hardcore-overview.html", 68 | "redirect": "/frontend/frontend-hardcore-overview" 69 | }, 70 | { 71 | "path": "/note/how-to-run-js.html", 72 | "redirect": "/frontend/how-to-run-javascript-code" 73 | }, 74 | { 75 | "path": "/note/html.html", 76 | "redirect": "/frontend/html" 77 | }, 78 | { 79 | "path": "/note/js-intro.html", 80 | "redirect": "/frontend/introduction-to-javascript" 81 | }, 82 | { 83 | "path": "/note/npm-overview.html", 84 | "redirect": "/frontend/introduction-to-npm" 85 | }, 86 | { 87 | "path": "/note/js-advanced.html", 88 | "redirect": "/frontend/javascript-advanced" 89 | }, 90 | { 91 | "path": "/note/js-foundation.html", 92 | "redirect": "/frontend/javascript-foundation" 93 | }, 94 | { 95 | "path": "/note/js-foundation-old.html", 96 | "redirect": "/frontend/javascript-foundation-legacy-version" 97 | }, 98 | { 99 | "path": "/note/js-modular.html", 100 | "redirect": "/frontend/javascript-modules" 101 | }, 102 | { 103 | "path": "/note/regexp.html", 104 | "redirect": "/frontend/javascript-regular-expression" 105 | }, 106 | { 107 | "path": "/note/jest.html", 108 | "redirect": "/frontend/jest" 109 | }, 110 | { 111 | "path": "/note/node-basic.html", 112 | "redirect": "/frontend/nodejs-basic" 113 | }, 114 | { 115 | "path": "/note/react-hooks.html", 116 | "redirect": "/frontend/react-hooks" 117 | }, 118 | { 119 | "path": "/note/redux.html", 120 | "redirect": "/frontend/redux" 121 | }, 122 | { 123 | "path": "/note/redux-observable.html", 124 | "redirect": "/frontend/redux-observable" 125 | }, 126 | { 127 | "path": "/note/rxjs.html", 128 | "redirect": "/frontend/rxjs" 129 | }, 130 | { 131 | "path": "/note/npm-verdaccio.html", 132 | "redirect": "/frontend/set-up-a-private-npm-registry-using-verdaccio" 133 | }, 134 | { 135 | "path": "/note/npm-speedup.html", 136 | "redirect": "/frontend/speeding-up-npm-install" 137 | }, 138 | { 139 | "path": "/note/syntactic-sugar.html", 140 | "redirect": "/frontend/syntactic-sugar-in-javascript" 141 | }, 142 | { 143 | "path": "/note/testing-library.html", 144 | "redirect": "/frontend/testing-library" 145 | }, 146 | { 147 | "path": "/note/clean-keyboard.html", 148 | "redirect": "/misc/clean-a-keyboard" 149 | }, 150 | { 151 | "path": "/note/linux-basic-security.html", 152 | "redirect": "/misc/linux-basic-security" 153 | }, 154 | { 155 | "path": "/note/fe-development-cookbook.html", 156 | "redirect": "/note/frontend-development-cookbook" 157 | }, 158 | { 159 | "path": "/note/fe-development-cookbook", 160 | "redirect": "/note/frontend-development-cookbook" 161 | }, 162 | { 163 | "path": "/note/fe-development-cookbook-old.html", 164 | "redirect": "/note/frontend-development-cookbook" 165 | }, 166 | { 167 | "path": "/note/fe-development-cookbook-old", 168 | "redirect": "/note/frontend-development-cookbook" 169 | }, 170 | { 171 | "path": "/note/frontend-development-cookbook.html", 172 | "redirect": "/note/frontend-development-cookbook" 173 | }, 174 | { 175 | "path": "/note/study-methodology.html", 176 | "redirect": "/study/crash-course-study-skills" 177 | }, 178 | { 179 | "path": "/note/study-the-costly-way.html", 180 | "redirect": "/study/dont-waste-your-time-and-money" 181 | }, 182 | { 183 | "path": "/study/study-the-costly-way.html", 184 | "redirect": "/study/dont-waste-your-time-and-money" 185 | }, 186 | { 187 | "path": "/study/study-the-costly-way", 188 | "redirect": "/study/dont-waste-your-time-and-money" 189 | }, 190 | { 191 | "path": "/note/study-fortune.html", 192 | "redirect": "/study/study-fortune" 193 | }, 194 | { 195 | "path": "/note/study-guild-abstraction.html", 196 | "redirect": "/study/study-guild-abstraction" 197 | }, 198 | { 199 | "path": "/note/english-using.html", 200 | "redirect": "/study/using-english" 201 | }, 202 | { 203 | "path": "/about/where-do-i-learn-from.html", 204 | "redirect": "/study/where-do-i-learn-from" 205 | }, 206 | { 207 | "path": "/about/where-do-i-learn-from", 208 | "redirect": "/study/where-do-i-learn-from" 209 | }, 210 | { 211 | "path": "/note/my-reading.html", 212 | "redirect": "/study/where-do-i-learn-from" 213 | }, 214 | { 215 | "path": "/note/study-the-only-way.html", 216 | "redirect": "/study/why-we-need-to-study" 217 | }, 218 | { 219 | "path": "/study/study-the-only-way.html", 220 | "redirect": "/study/why-we-need-to-study" 221 | }, 222 | { 223 | "path": "/study/study-the-only-way", 224 | "redirect": "/study/why-we-need-to-study" 225 | }, 226 | { 227 | "path": "/note/my-workstation.html", 228 | "redirect": "/workspace/awesome-tools" 229 | }, 230 | { 231 | "path": "/note/chrome.html", 232 | "redirect": "/workspace/chrome" 233 | }, 234 | { 235 | "path": "/note/terminal-intro.html", 236 | "redirect": "/workspace/introduction-to-terminal" 237 | }, 238 | { 239 | "path": "/note/mac.html", 240 | "redirect": "/workspace/mac" 241 | }, 242 | { 243 | "path": "/note/video-hotkey.html", 244 | "redirect": "/workspace/my-video-player-shortcuts" 245 | }, 246 | { 247 | "path": "/note/terminal-config.html", 248 | "redirect": "/workspace/terminal-settings" 249 | }, 250 | { 251 | "path": "/note/vscode.html", 252 | "redirect": "/workspace/vscode" 253 | } 254 | ] -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /js-nation-square-blue.png 4 | heroText: 前端指南 5 | tagline: LC 的前端开发技能知识体系 6 | actionText: → 开始阅读 ← 7 | actionLink: /note/frontend-development-cookbook 8 | features: 9 | - title: Ecosystem 10 | details: 精通 VS Code、NodeJS、Vite、Docker 等软件的安装与卸载,配套设施也是必不可少的。 11 | - title: JavaScript 12 | details: 熟练掌握 TypeScript、QraphQL、RxJS 等单词的拼写,学习前端所需的核心语言及开发链路。 13 | - title: Value yourself 14 | details: 枯れた技術の水平思考,Coding With Good Taste,Sic Parvis Magna。 15 | footer: Powered By VuePress | 2022 Seognil LC 16 | --- 17 | -------------------------------------------------------------------------------- /docs/note/00.resources/1.awesome-tools.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 装了啥(2021) 3 | date: 2021-10-08 10:39:13 4 | permalink: /workspace/awesome-tools 5 | categories: 6 | - 开发环境 7 | tags: 8 | - 工具 9 | - awesome 10 | --- 11 | 12 | # 装了啥(2021) 13 | 14 | --- 15 | 16 | > 参考自:[装了啥 - 云谦](https://github.com/sorrycc/awesome-tools) 17 | 18 | --- 19 | 20 | ![the-digital-productivity-pyramid](./the-digital-productivity-pyramid.jpeg) 21 | 22 | [Tiago Forte 生产力金字塔](https://fortelabs.co/blog/the-digital-productivity-pyramid/) 23 | 24 | ## 上网 25 | 26 | (paradiseduo) 27 | 28 | ## 软件和工具 29 | 30 | 这些拆到单独的文章了 31 | 32 | - [Mac](/workspace/mac) 33 | - [Chrome](/workspace/chrome) 34 | - [VS Code](/workspace/vscode) 35 | 36 | ## 网站及服务 37 | 38 | - 技术学习和生产 39 | - [Google](https://www.google.com/) 40 | - [YouTube](https://www.youtube.com/) 41 | - [GitHub](https://github.com/) 42 | - [Stack Overflow](https://stackoverflow.com/) 43 | - 网站部署 44 | - [Vercel](https://vercel.com/):静态托管服务 45 | - [阿里云域名](https://wanwang.aliyun.com/):网站域名 46 | - 小工具 47 | - [A SOFT MURMUR](https://asoftmurmur.com/):白噪声 48 | - [astralapp](https://app.astralapp.com/dashboard):GitHub Star 管理器(你是不是也把 star 当收藏夹用?) 49 | - [bundlephobia](https://bundlephobia.com/package/rxjs):npm 包分析 50 | 51 | ## 关爱你的数据 52 | 53 | - [数据备份 之 3-2-1 原则](https://sspai.com/post/39591) 54 | - 云存储(热文件、碎片化信息) 55 | - OneNote:快取笔记 56 | - OneDrive:主要的云盘 57 | - [MEGA sync](https://mega.nz/):可以筛掉 node_modules,放了两个玩具项目和 rualc (因为本地有很多草稿文章) 58 | - Google Photos:手机拍的照片自动备份 59 | - 物理存储(大文件、磁盘、冷存储) 60 | - [选固态](https://zhuanlan.zhihu.com/p/166162142) 61 | - [选机械](https://zhuanlan.zhihu.com/p/147065869) 62 | - 选 U 盘用 SSD:[低功耗 NVME 电流在 2.0A 以下的就不会特别烫](https://www.chiphell.com/forum.php?mod=viewthread&tid=2163456) 63 | 64 | ## 通勤装备 65 | 66 | - 背包:谷歌开发者大会纪念背包 67 | - MacBook Air (M1, 2020) 16G-256G 68 | - 收纳板:cocoon grid it 69 | - 512G U 盘(用来做 Time Machine、iPhone 备份,sata m.2 固态 + 壳) 70 | - 几个小 U 盘(用来做系统安装盘) 71 | - N 合 1 Hub,应急用 72 | - 一堆线材,一堆 Type-C 转接头 73 | - 充电头:倍思 GaN 2C1A 65W 74 | - 紫米无线充电宝 75 | - 其他 76 | - 小米手环 5 NFC 版 77 | - AirPods Pro(噪用和全家桶设备间切换真好用) 78 | - KeySmart 钥匙扣 79 | - 双面公交卡套 80 | - 手机 81 | - 手机 82 | - iPhone 12 83 | - 红米 K40 84 | - 流量 85 | - 移动:8 元低保套餐 86 | - 联通:O 粉卡 87 | - 电信:家里宽带送的 88 | 89 | ## 固定位硬件 90 | 91 | 保证每个工作区都有一组合适的外设,以便接上主力 MBP 提供最大生产力。 92 | 93 | - 每个地方都 +1 的外设 94 | - 34 寸 3440x1440 直屏(大屏即正义!),AOC、ViewSonic 之类的正经牌子哪个有折扣买哪个,平均两千元左右一块,固定位共三块 95 | - GaN 的 2C1A 65W 充电头可以说是很香了,倍思和征拓各两个,一共四个(固定位三个 + 通勤一个)(倍思的指示灯就是太亮了…) 96 | - 小米手写板(有时写写草稿可以说是多快好省了) 97 | - 苹果的触控板(接 Mac) 98 | - 公司 99 | - DockCase P1 QC,作为 MBP 的供电和 USB Hub(考虑到稳定性,视讯线单独接一根在 Type-C 口上) 100 | - 键盘:NIZ Plum 84 101 | - 苹果的鼠标(不常用) 102 | - 出租屋 103 | - Mac Mini M1 8G+256G(可以说是最低配了,冲浪/写玩具用) 104 | - 一台游戏 PC(配置略,最近吃灰了) 105 | - 键盘:Keychron K3(可以不同设备间蓝牙切换) 106 | - 鼠标:罗技 M590(接 PC) 107 | - 铁威马 D4-300 108 | - 希捷酷鹰 4T \* 2 (Raid 1) 109 | - 某便宜的 23 寸显示器(接不同设备应急用) 110 | - 选配结构件 111 | - 爱格升显示器支架(之前用过乐歌的关节处不太行) 112 | - Jugar 极架(金属木板架子,纵向堆设备用) 113 | 114 | ## 游戏机 115 | 116 | - PS4 Pro 港版(借同学了) 117 | - Xbox Series S 德亚(XGPU 真香,手机串流真香) 118 | - Switch 初版 日版(吃灰很久了) 119 | -------------------------------------------------------------------------------- /docs/note/00.resources/3.my-reading-list.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 看了啥(2021) 3 | date: 2021-10-07 15:32:01 4 | permalink: /study/my-reading-list/ 5 | categories: 6 | - 学习渠道 7 | tags: 8 | - awesome 9 | --- 10 | 11 | # 看了啥(2021) 12 | 13 | 来源:实体书、微信读书、听书、速读 14 | 15 | 注:带链接的是我读过的版本,大部分是豆瓣和 B 站 16 | 17 | ## 书 18 | 19 | - 技术 20 | - [游戏设计艺术(第 2 版)](https://book.douban.com/subject/26791007/):CMU 教材,已经出新版了,买新版吧 21 | - 心理 22 | - [《非暴力沟通》 - 马歇尔·卢森堡](https://book.douban.com/subject/3533221/) 23 | - [《被讨厌的勇气》 - 岸见一郎/古贺史健](https://book.douban.com/subject/26369699/):“自我启发之父”阿德勒的哲学课 24 | - [《亲密关系》 - 克里斯多福·孟](https://book.douban.com/subject/26363229/) 25 | - [《正面管教》- 简·尼尔森](https://book.douban.com/subject/3420606/):如何不惩罚、不娇纵地有效管教孩子 26 | - 文学 27 | - 《老人与海》 - 海明威 28 | - 《竹林中》 - 芥川龍之介 29 | - [《小王子》 2015 动画电影](https://movie.douban.com/subject/20645098/) 30 | - 《动物农庄》 - 乔治·奥威尔 31 | - 《献给阿尔吉侬的花束》 - 丹尼尔·凯斯 32 | - B 站 - 李好帅的黄金屋 - 沉浸式读书 33 | - ▶️ [第一集](https://www.bilibili.com/video/BV1mL411b7ek)、[第二集](https://www.bilibili.com/video/BV1Yy4y1G7Ea)、[第三集](https://www.bilibili.com/video/BV1Mg411V7Xg)、[第四集](https://www.bilibili.com/video/BV1bQ4y1a7Es) 34 | - [《献给阿尔吉侬的花束》创作故事](https://www.bilibili.com/read/cv13023094) 35 | - 经济 36 | - [《小狗钱钱》 - 博多·舍费尔](https://book.douban.com/subject/35295592/) 37 | - [《穷爸爸富爸爸》 - 罗伯特·清崎](https://book.douban.com/subject/27153484/) 38 | - 健康 39 | - 《给男孩的身体书》 - 凯莉·邓纳姆 40 | - 《给女孩的身体书》 - 凯莉·邓纳姆 41 | - [《公共营养师 [基础知识]》 - 中国就业培训技术指导中心](https://book.douban.com/subject/20493950/) 42 | - [《全科医学(家庭版)》 - 约翰·莫塔](https://book.douban.com/subject/34986173/) 43 | - 生活 44 | - [《從生命的車窗眺望》 - 星野源](https://book.douban.com/subject/27045708/) 45 | - [《平衡的智慧》 - 帕特·基辛格](https://book.douban.com/subject/1283295/) 46 | - [▶️ B 站 - 幻海航行 - 科幻小说速读](https://space.bilibili.com/193147738) 47 | - 《宇宙过河卒》 - 波尔·安德森 48 | - 《基地》三部曲 - 艾萨克·阿西莫夫 49 | - 《神们自己》 - 艾萨克·阿西莫夫 50 | - 《猎户座防线》 - 史蒂芬·巴克斯特 51 | - 《最后的问题》 - 艾萨克·阿西莫夫 52 | 53 | ## 视频 54 | 55 | - 真人剧 56 | - [▶️ 逃避虽可耻但有用](https://www.bilibili.com/bangumi/play/ss25365/) 57 | - [▶️ 半泽直树 第二季](https://www.bilibili.com/bangumi/play/ss35110/) 58 | - [致命女人 第一季](https://movie.douban.com/subject/30401122/) 59 | - [亿万 第一季](https://movie.douban.com/subject/26200198/) 60 | - [金装律师 第一季](https://movie.douban.com/subject/4842285/) 61 | - 动画 62 | - [▶️ 辉夜大小姐想让我告白? 第二季](https://www.bilibili.com/bangumi/play/ss32982/) 63 | - 攻壳机动队 64 | - [▶️ 第一季](https://www.bilibili.com/bangumi/play/ss1564/) 65 | - [▶️ 第二季](https://www.bilibili.com/bangumi/play/ss1565/) 66 | - [EVA 新剧场版:终](https://movie.douban.com/subject/10428501/) 67 | - [星球大战:幻境](https://movie.douban.com/subject/35284557/) 68 | -------------------------------------------------------------------------------- /docs/note/00.resources/4.crash-course-study-skills.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 学习方法论 3 | date: 2019-11-23 23:38:58 4 | permalink: /study/crash-course-study-skills 5 | categories: 6 | - 学习技巧 7 | tags: 8 | - crash course 9 | --- 10 | 11 | # 学习方法论 12 | 13 | ## 简介 14 | 15 | ### 什么是 学习方法论 16 | 17 | 我的学习计划系列文章标题一般是「XXX 学习指南」 18 | 19 | 所以这篇文章也可以叫「学习“如何学习”的学习指南」 20 | 21 | ### 为什么要学习 关于学习的方法论 22 | 23 | 像所有其他方法论的目标一样: 24 | 提高 XXX 的执行效率和效果。 25 | 26 | `where (XXX = "学习") => 提高学习的效率和效果` 27 | 28 | ## 学习方法论 29 | 30 | ### 概览 31 | 32 | - 耗时: 33 | - 视频本身大约 100 分钟,但我花了 8 个小时才看完(包括理解和笔记) 34 | - 其他资料断断续续看的,累计可能有 20 个小时 35 | - 难点: 36 | - 养成总结**知识体系**的习惯 37 | - 更好的**时间管理**计划 38 | - 工具: 39 | - 文本编辑器(我用 [VS Code](/workspace/vscode)) 40 | - 云存储(我用过的,~~目前主力 Dropbox~~) 41 | - [Dropbox](https://www.dropbox.com/) 42 | - [OneDrive](https://onedrive.live.com/) 43 | - [Google Drive](https://www.google.com/drive/download/backup-and-sync/) 44 | - [MEGA](https://mega.nz/) 45 | - [坚果云](https://www.jianguoyun.com/) 46 | 47 | ### 学习路线 48 | 49 | - 学习 Crash Course Study Skills(按视视频顺序) 50 | - 大脑工作原理 51 | - 笔记和知识管理 52 | - 学习策略 53 | - 心理学技巧 54 | - 考试、工作的准备事项 55 | - 实战 56 | - 立即建立自己的知识体系管理系统 57 | - 在日常工作中进行时间管理 58 | - 健康的作息 59 | 60 | ## 资料 61 | 62 | ### 自学教程 63 | 64 | - CCSS 65 | - [Crash Course Study Skills - YouTube](https://www.youtube.com/watch?v=IhuwS5ZLwKY&list=PL8dPuuaLjXtNcAJRf3bE1IJU6nMfHj86W) 66 | - [学习技能 - bilibili](https://www.bilibili.com/video/av16785517) 67 | 68 | ### 扩展阅读 方法论 69 | 70 | - [费曼学习法](https://wiki.mbalib.com/wiki/%E8%B4%B9%E6%9B%BC%E5%AD%A6%E4%B9%A0%E6%B3%95) 71 | - [艾宾浩斯记忆法](https://wiki.mbalib.com/wiki/%E8%89%BE%E5%AE%BE%E6%B5%A9%E6%96%AF%E8%AE%B0%E5%BF%86%E9%81%97%E5%BF%98%E6%9B%B2%E7%BA%BF) 72 | - [刻意训练](https://www.zhihu.com/question/65785362) 73 | - [小黄鸭调试法](https://zh.wikipedia.org/zh-hans/%E5%B0%8F%E9%BB%84%E9%B8%AD%E8%B0%83%E8%AF%95%E6%B3%95) 74 | - [每月高效工作 200 小时 / Environment Body Mind](https://wanqu.co/a/5765/%E6%AF%8F%E6%9C%88%E9%AB%98%E6%95%88%E5%B7%A5%E4%BD%9C-200-%E5%B0%8F%E6%97%B6/) 75 | - [任务换人有害无益 - Joel 说软件](https://www.kancloud.cn/wizardforcel/joel-on-software/99190) 76 | - [X-Y PROBLEM](https://coolshell.cn/articles/10804.html) 77 | - [提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md) 78 | 79 | ### 扩展阅读 心理学 80 | 81 | - 正面 82 | - [路径依赖](https://wiki.mbalib.com/wiki/%E8%B7%AF%E5%BE%84%E4%BE%9D%E8%B5%96) 83 | - [多看效应](https://wiki.mbalib.com/wiki/%E5%A4%9A%E7%9C%8B%E6%95%88%E5%BA%94) 84 | - [游戏化](https://zhuanlan.zhihu.com/p/45980716) 85 | - [心流]() 86 | - [斯金纳箱](https://www.gcores.com/radios/97874) 87 | - 负面 88 | - [达克效应](https://zh.wikipedia.org/wiki/%E8%BE%BE%E5%85%8B%E6%95%88%E5%BA%94) 89 | - [冒名顶替症候群](https://zh.wikipedia.org/wiki/%E5%86%92%E5%90%8D%E9%A0%82%E6%9B%BF%E7%97%87%E5%80%99%E7%BE%A4) 90 | - [习得性无助](https://www.zhihu.com/question/26518056) 91 | - [分析瘫痪](https://zh.wikipedia.org/wiki/%E5%88%86%E6%9E%90%E7%99%B1%E7%98%93) 92 | - [死锁](https://zh.wikipedia.org/wiki/%E6%AD%BB%E9%94%81) 93 | 94 | ## Crash Course Study Skills 总结 95 | 96 | - 学习系统 97 | - 信息采集 98 | - 采集 99 | - 自然语言也是语法和**含义** 100 | - 语言就是信息,而信息就是一切(出自 [杀死伊芙](https://movie.douban.com/subject/26915602/)) 101 | - **记下来**(笔记、书签等) 102 | - 主要信息来源 103 | - 来源(大) 104 | - 权威材料(如官方文档、经典书籍等) 105 | - 学习指南(如个人总结的一篇文章) 106 | - 扩展阅读(以上一般都会有的) 107 | - 来源(小) 108 | - big ideas(要点) 109 | - bullet lists(列表) 110 | - definations(定义) 111 | - **examples**(示例) 112 | - 重要性和优先级 113 | - **argument**(核心概念) 114 | - description(描述) 115 | - context(上下文) 116 | - 三个阅读等级(精读、泛读、跳过) 117 | - SQ3R 阅读法 118 | - 做笔记 119 | - 方式 120 | - 子弹笔记(列表系统) 121 | - 康奈尔笔记(关键目标、笔记、总结) 122 | - 思维导图(脑图、Mind Mapping) 123 | - 提高信噪比(只记关键部分) 124 | - CheatSheet 模式 125 | - 缓冲区(临时信息存储) 126 | - 数据持久化(比如笔记、代码、图片、材料等) 127 | - 设计分层存储系统 128 | - 建立周期性计划 129 | 130 | * 脑科学 131 | - 记忆工作类型 132 | - 记忆(三层模型) 133 | - 传感记忆(视觉听觉信号等) 134 | - 工作记忆(当前工作的信息) 135 | - 长期记忆(记忆) 136 | - **回忆**("学会"的本质) 137 | - 间隔效应 138 | - 艾宾浩斯记忆曲线 139 | - 莱特纳系统 140 | - 知识加工 141 | - 真实性、可视化、独特化、符号化 142 | - 神经突触链接的建立 143 | - 大脑工作的生物资源消耗 144 | 145 | - 心理学 146 | - 专注 147 | - 时间动机理论 148 | - 负面效果 149 | - 定向注意力疲劳 150 | - 刺激反馈成瘾(斯金纳箱、巴普洛夫) 151 | - 抑制机制(嘈杂环境、太难或简单、身体状态、连续工作等) 152 | - 正面措施 153 | - 放慢速度(减少工作记忆负荷) 154 | - 减少被动信息摄入(少刷抖音微博朋友圈,屏蔽环境噪音) 155 | - **停止多任务**(短时休息时也不要切换工作) 156 | - 认知切换惩罚 157 | - 注意力残留 158 | - Environment/Body/Mind 159 | - 番茄工作法 160 | - 压力 161 | - 失败是成功之母 162 | - 压力的生理现象 163 | - 皮质醇激素会阻碍大脑工作 164 | - 来源 165 | - 害怕重复过去的失败(负面认知偏差) 166 | - 害怕未知 167 | - 害怕损失 168 | - 正面措施 169 | - 把烦恼写下来(释放工作记忆) 170 | - 分析过去的错误 171 | - 提高经验水平 172 | - 训练 173 | - 预演 174 | - Memory is context based(记忆是基于场景(上下文)的) 175 | - 寻求专业帮助(心理医生) 176 | 177 | * 健身 178 | - TODO 179 | 180 | - 考试和论文相关 181 | - 略(TODO) 182 | -------------------------------------------------------------------------------- /docs/note/00.resources/5.using-english.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 英语 训练指南 编程篇 3 | date: 2019-12-14 22:03:19 4 | permalink: /study/using-english 5 | categories: 6 | - 学习技巧 7 | tags: 8 | - 英语 9 | --- 10 | 11 | # 英语 训练指南 编程篇 12 | 13 | ## 英语 简介 14 | 15 | ### 什么是 英语 16 | 17 | > 英语(English),中文也称英文,是一种西日耳曼语言,诞生于日德兰半岛和莱茵河流域,如今具有全球通用语的地位。 18 | > 由于使用英语的两个主要国家——英国与美国,先后成为世界超级大国之故,并在商业、学术领域具较大影响力,在科技方面的突出贡献和领先地位,而且英文相对易学,因此许多人都将英语做为一种外语或第二语言,把英语作为外国语使用的人约 3-5 亿。英语在香港作为第二官方语言,在欧洲大陆及日本则是最普遍作为外语来学习的语言(32.6%),接着是法语、德语和西班牙语,在中国大陆、澳门特区、台湾、韩国、日本等地,英语是学校的必修外语课程。 19 | 20 | ### 为什么需要使用 英语 21 | 22 | > Language is information and information is everything. —— Killing Eve 23 | 24 | 根据统计,英语是全世界使用人数最多的语言: 25 | 26 | - [List of languages by total number of speakers](https://en.wikipedia.org/wiki/List_of_languages_by_total_number_of_speakers) 27 | - [INTERNET WORLD USERS BY LANGUAGE](https://www.internetworldstats.com/stats7.htm) 28 | 29 | 编程领域最早发展自英语系国家: 30 | 31 | - [计算机早期历史 - Early Computing](https://www.bilibili.com/video/av21376839/) 32 | 33 | 程序的编码是最早来自英语: 34 | 35 | - [Characters, Symbols and the Unicode Miracle - Computerphile](https://www.youtube.com/watch?v=MijmeoH9LT4) 36 | 37 | 编程语言中的很多关键字也来源于英语: 38 | 39 | - [保留字 - MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Lexical_grammar#%E5%85%B3%E9%94%AE%E5%AD%97) 40 | 41 | 代码的编写、命名、注释、文档等,也广泛使用英语: 42 | 43 | - [Learn X in Y minutes](https://learnxinyminutes.com/docs/javascript/) 44 | 45 | 无数编程资料的第一语言都是英语: 46 | 47 | - [GitHub](https://github.com/) 48 | - [Stack Overflow](https://stackoverflow.com/) 49 | - [Web Development - YouTube](https://www.youtube.com/results?search_query=Web+Development) 50 | - [FrontendMasters](https://frontendmasters.com/) 51 | - [Standard ECMA-262](https://www.ecma-international.org/publications/standards/Ecma-262.htm) 52 | - [Daily JS - Medium](https://medium.com/dailyjs) 53 | - [npm](https://www.npmjs.com/) 54 | - [Redux - Doc](https://redux.js.org/) 55 | 56 | 无数非英语母语的大佬,除了母语以外都会英语: 57 | 58 | - Redux 作者、React 团队核心成员:Dan Abramov - **俄国** 59 | - Cycle.js 作者、响应式编程专家:André Staltz - **巴西** 60 | - Linux 之父、Git 之父:Linus Torvalds - **芬兰** 61 | 62 | #### 一定要使用英语? 63 | 64 | 平时更多地使用英语,本质上是提高自己的英语水平, 65 | 使自己能够在第一时间了解最新的资讯。 66 | 67 | 如果不熟悉英语,_只能_ 看汉化版的资料, 68 | 如果还没有汉化版,_只能_ 苦苦等别人汉化,或者看别人二次演绎的文章。 69 | 而汉化、心得这些二手资料的问题在于,可能和原文传达的信息有出入。 70 | 71 | > 对于读者:不要妄图通过二手资料来学习,对于某个有争议的观点,我们应该去寻找最初的参考来源 72 | > —— [怎样理解 Eric Elliott 的文章《为什么说 TypeScript 不适合大型项目》?- justjavac](https://www.zhihu.com/question/338522586/answer/781367678) 73 | 74 | 得不到第一手资料,永远落后于时代, 75 | 永远需要依靠别人,永远没有自己的**核心竞争力**。 76 | 77 | 从更高的视角来看, 78 | 提高自己的英语水平,本质上其实是扩大自己的资讯来源。 79 | 简单的道理:兼听则明,偏信则暗。 80 | 了解学习某个事物,势必需要从大量不同的站点、书籍、文章中获取信息。 81 | 根据英语在技术领域的使用程度之广泛,训练(更多使用)英语**是必须的**。 82 | 83 | #### 一定要只用英语? 84 | 85 | 但作为中文母语者,显然阅读中文还是更有效率的。 86 | 在有**高质量汉化**的情况下(如官方中文文档、视频字幕等), 87 | 也不必特地选择英文版。 88 | 因为对于开发工作来说,学习技术的最终目的是掌握技术,而不是掌握英语。 89 | 如果通过汉化版能够更**高效**地了解学习某个事物,那就是有意义的。 90 | (毕竟汉化本身也算广义的造轮子) 91 | 92 | #### 别的自然语言 93 | 94 | 当然,我还见过使用日语、俄语、德语、法语等编写的资料, 95 | 这些作为第三、第四语言也是可以选择性学习的。 96 | 但以编程领域来说,优先训练自己的英语水平是更合适的。 97 | 98 | ## 学习英语 99 | 100 | ### 概览 101 | 102 | - 耗时:长期(永久) 103 | - 难点:初期陡峭的学习曲线,坚持 104 | - 工具: 105 | - [沙拉查词-聚合词典划词翻译](https://chrome.google.com/webstore/detail/%E6%B2%99%E6%8B%89%E6%9F%A5%E8%AF%8D-%E8%81%9A%E5%90%88%E8%AF%8D%E5%85%B8%E5%88%92%E8%AF%8D%E7%BF%BB%E8%AF%91/cdonnmffkdaoajfknoeeecmchibpmkmg) 106 | - [Grammarly for Chrome](https://chrome.google.com/webstore/detail/grammarly-for-chrome/kbfnbcaeplbcioakkpcpgfkobkghlhen) 107 | 108 | ### 学习路线 109 | 110 | 两个简单的道理: 111 | 112 | - 工欲善其事,必先利其器 113 | - 用进废退、熟能生巧 114 | 115 | 我的做法**不是**先**背**一本《计算机英语》, 116 | 而**是立即开始持续使用**英语, 117 | 直到能够全面覆盖每天工作流程。 118 | (艾宾浩斯遗忘曲线?不存在的,天天用,哪来的遗忘) 119 | 120 | - 打造使用环境 121 | - 把系统调成英文 122 | - 准备好翻译器和插件 123 | - 学习技术时 124 | - 优先选择英文的教程 125 | - 尽量看文档的英文版本 126 | - 多看英文技术文章 127 | - 写代码时 128 | - 更有意义的英语变量命名 129 | - 尝试写英语注释 130 | - 用 Google 进行搜索(或 Bing、DuckDuckGo 等,反正不是百度) 131 | - 用英语关键字搜索资料 132 | - 创造更多使用场景 133 | - 参与 GitHub 的开源项目 134 | - 和老外沟通 135 | - 给没有中文的技术文档提供翻译 136 | - 做自己的开源项目,尝试用英语写文档 137 | 138 | 以上列表覆盖“听说读写”中的绝大部分部分(除“说”外), 139 | 创造了良好的使用环境,熟练使用英语的也就是自然而然的事情了。 140 | 141 | ## 资料 142 | 143 | - 工具 144 | - [沙拉查词-聚合词典划词翻译](https://chrome.google.com/webstore/detail/%E6%B2%99%E6%8B%89%E6%9F%A5%E8%AF%8D-%E8%81%9A%E5%90%88%E8%AF%8D%E5%85%B8%E5%88%92%E8%AF%8D%E7%BF%BB%E8%AF%91/cdonnmffkdaoajfknoeeecmchibpmkmg) 145 | - [Grammarly for Chrome](https://chrome.google.com/webstore/detail/grammarly-for-chrome/kbfnbcaeplbcioakkpcpgfkobkghlhen) 146 | - 扩展阅读 147 | - [English-level-up-tips-for-Chinese](https://github.com/byoungd/english-level-up-tips-for-Chinese) 148 | - [人人都能用英语](https://github.com/xiaolai/everyone-can-use-english) 149 | - [词汇量 2 万? 纯正英式? 中国人的英语误区 (亚洲适用)](https://www.youtube.com/watch?v=xmIB-kyFeg8) 150 | -------------------------------------------------------------------------------- /docs/note/00.resources/the-digital-productivity-pyramid.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/00.resources/the-digital-productivity-pyramid.jpeg -------------------------------------------------------------------------------- /docs/note/02.workspace/0.mac.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mac 环境(M1 + Monterey) 3 | date: 2021-11-15 15:43:26 4 | permalink: /workspace/mac 5 | categories: 6 | - 开发环境 7 | tags: 8 | - mac 9 | - 工具 10 | --- 11 | 12 | # Mac 环境(M1 + Monterey) 13 | 14 | ## Mac 简介 15 | 16 | - 视频 17 | - [学生党 M1 Mac 入门指北](https://www.bilibili.com/video/BV1sD4y1X7MQ) 18 | - [Mac Tutorial for Beginners - Switching from Windows to macOS](https://www.youtube.com/watch?v=67keaaWOKzE) 19 | - [How to Set Up Your Mac for Maximum Productivity](https://www.youtube.com/watch?v=XBi3OB23Utk) 20 | - 官方文档 21 | - [macOS 使用手册](https://support.apple.com/zh-cn/guide/mac-help/welcome/mac) 22 | - [Mac 键盘快捷键](https://support.apple.com/zh-cn/HT201236) 23 | - M1 兼容性相关 24 | - [Is Apple Silicon ready?](https://isapplesiliconready.com/) 25 | - [Does It ARM?](https://doesitarm.com/) 26 | 27 | ## 配置 28 | 29 | (如果有其他 Mac 的话用 Time Machine 直接迁移就好) 30 | 31 | ### Time Machine 恢复后的问题 32 | 33 | #### 如果网络不正常 34 | 35 | - 刚配好丝丝要重启 36 | - 到这里看看删掉与 network 相关的文件,重启: 37 | 38 | ```sh 39 | open /Library/Preferences/SystemConfiguration 40 | ``` 41 | 42 | ```sh 43 | # 找到这些文件 44 | com.apple.airport.preferences.plist 45 | com.apple.network.eapolclient.configuration.plist 46 | com.apple.wifi.message-tracer.plist 47 | NetworkInterfaces.plist 48 | preferences.plist 49 | ``` 50 | 51 | #### 如果是恢复到另一台设备 52 | 53 | - 到 Sharing 改电脑名字,重启 54 | - Chrome 用一个新账户重新同步(不然似乎历史记录会识别为同一台设备) 55 | 56 | ### System Preferences 57 | 58 | - Language & Region:英语、简体中文 59 | - Sharing:改电脑名字,重启 60 | - Software Update 61 | - Keyboard:先把 Key Repeat 和 Delay 调到最快 62 | 63 | 安装 [Additional Tools for Xcode](https://developer.apple.com/download/more/?=additional%20tools) 里的 [Network Link Conditioner](https://nshipster.com/network-link-conditioner/)(给电脑限速用的) 64 | 65 | (如果装 NTFS 工具等需要 [Reduced Security](https://support.apple.com/en-gb/guide/mac-help/mchl768f7291/mac)) 66 | 67 | ### dotfiles 68 | 69 | ```sh 70 | .zprofile 71 | .zshrc 72 | .zsh_history 73 | .nrmrc 74 | ``` 75 | 76 | ### 终端配置 77 | 78 | sudo 无需密码: 79 | 80 | ```sh 81 | echo -e "\n$USER ALL=(ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers 82 | ``` 83 | 84 | 允许安装运行任意软件: 85 | 86 | ```sh 87 | sudo spctl --global-disable 88 | sudo spctl --status 89 | ``` 90 | 91 | bin 目录权限(解决 npm global install 问题): 92 | 93 | ```sh 94 | sudo chown -R $USER /usr/local/bin 95 | ``` 96 | 97 | 复制来的 ssh 私钥要调成只读: 98 | 99 | ```sh 100 | sudo chmod 600 101 | ``` 102 | 103 | 禁止 PressAndHold(需重启)(解决 [这个 VS Code 问题](https://github.com/microsoft/vscode/issues/31919)): 104 | 105 | ```sh 106 | defaults write -g ApplePressAndHoldEnabled -bool false 107 | ``` 108 | 109 | 更快的按键重复(控制面板的 KeyRepeat 最快才到 2)(需重启): 110 | 111 | ```sh 112 | defaults write -g InitialKeyRepeat -int 15 113 | defaults write -g KeyRepeat -int 1 114 | ``` 115 | 116 | 提高 Time Machine 的速度(重启后失效,可以做一个 function): 117 | 118 | ```sh 119 | sudo sysctl debug.lowpri_throttle_enabled=0 120 | ``` 121 | 122 | 启用 `locate` 命令并建立索引: 123 | 124 | ```sh 125 | sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist 126 | ``` 127 | 128 | ### 安装基本工具 129 | 130 | 魔法丝袜之影(略) 131 | 132 | ```sh 133 | export ALL_PROXY='http://127.0.0.1:1080' 134 | ``` 135 | 136 | 安装 Xcode Command Line Tools: 137 | 138 | ```sh 139 | xcode-select --install 140 | ``` 141 | 142 | 安装 [Brew](https://brew.sh/): 143 | 144 | ```sh 145 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 146 | ``` 147 | 148 | (按照提示)激活 `brew` 命令: 149 | 150 | ```sh 151 | echo 'eval $(/opt/homebrew/bin/brew shellenv)' >> $HOME/.zprofile 152 | eval "$(/opt/homebrew/bin/brew shellenv)" 153 | ``` 154 | 155 | 安装一些基本工具(虽然系统自带一些,但是用 brew 来做后续更新): 156 | 157 | ```sh 158 | brew install --formula bat git n scc tig trash tree zsh 159 | brew install --cask google-chrome visual-studio-code iterm2 160 | ``` 161 | 162 | 安装 [Oh My Zsh](https://github.com/ohmyzsh/ohmyzsh): 163 | 164 | ```sh 165 | sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" 166 | ``` 167 | 168 | 安装 [更纱黑体](https://github.com/be5invis/Sarasa-Gothic)(`"Sarasa Mono SC"`, "Sarasa Term SC"): 169 | 170 | ```sh 171 | brew tap homebrew/cask-fonts 172 | brew install font-sarasa-gothic 173 | ``` 174 | 175 | 安装 Node.js(我用 n 来管理): 176 | 177 | ```sh 178 | sudo n 16 179 | ``` 180 | 181 | ### Finder 182 | 183 | - 显示扩展名:`cmd + ,` > Advanced 184 | - (剪切功能的快捷键:`cmd + option + v`) 185 | 186 | 总是显示隐藏文件: 187 | 188 | ```sh 189 | defaults write com.apple.finder AppleShowAllFiles -boolean true; killall Finder 190 | ``` 191 | 192 | 标题显示完整路径: 193 | 194 | ```sh 195 | defaults write com.apple.finder \_FXShowPosixPathInTitle -bool true; killall Finder 196 | ``` 197 | 198 | Open In Terminal,(装好到 System Preferences > Extensions 开启): 199 | 200 | ```sh 201 | brew install openinterminal 202 | ``` 203 | 204 | (其他配置略,`cmd + ,`、`cmd + j`) 205 | 206 | ## 其他安装的工具 207 | 208 | ### npm global 209 | 210 | `npm -g i` 211 | 212 | - [pnpm](https://github.com/pnpm/pnpm):代替 npm 用 213 | - [@antfu/ni](https://github.com/antfu/ni):自动判断当前的包管理器(npm、yarn、pnpm) 214 | - [@types/node](https://www.npmjs.com/package/@types/node):node 的类型定义,写 ts 脚本的时候辅助用 215 | - [serve](https://github.com/vercel/serve):读本地文件夹起一个 server(类似 http-server) 216 | - [tldr](https://github.com/tldr-pages/tldr):简化的 help 工具(类似 man 或 --help) 217 | - [tsno](https://github.com/egoist/tsno):更方便的 ts-node 的代替品,底层是 esbuild 218 | - [vercel](https://github.com/vercel/vercel):部署本地 app dist 到 vercel 219 | 220 | 把全局安装的 `@types` 软链接到根目录,[以便 ts 全局搜索](https://www.typescriptlang.org/tsconfig#typeRoots) 221 | 222 | ```sh 223 | mkdir -p ~/node_modules/ 224 | ln -s ~/pnpm-global/5/node_modules/@types ~/node_modules/@types 225 | ``` 226 | 227 | ### brew 228 | 229 | `brew install` 230 | 231 | - [bat](https://github.com/sharkdp/bat):显示文件内容(类似 cat) 232 | - [n](https://github.com/tj/n):Node 版本管理器 233 | - [neofetch](https://github.com/dylanaraps/neofetch):显示当前环境信息(类似 screenfetch) 234 | - [pngquant](https://pngquant.org/):png 图片压缩 235 | - [scc](https://github.com/boyter/scc):统计代码行数(类似 cloc) 236 | - [smartmontools](https://apple.stackexchange.com/questions/135565/how-do-i-get-detailed-smart-disk-information-on-os-x-mavericks-or-later):磁盘健康度 237 | - [tig](https://jonas.github.io/tig/doc/manual.html):更方便的 git history 238 | - [trash](https://hasseg.org/trash/):扔到垃圾桶(用来代替 `rm -rf`) 239 | - [tree](https://sourabhbajaj.com/mac-setup/iTerm/tree.html):显示文件夹树状结构 240 | - [you-get](https://github.com/soimort/you-get):视频下载器 241 | 242 | ### brew cask 243 | 244 | `brew install --cask` 245 | 246 | - 开发相关 247 | - [docker](https://www.docker.com/):轻量级虚拟化技术 248 | - [switchhosts](https://github.com/oldj/SwitchHosts):Host 编辑器 249 | - [postman](https://www.getpostman.com/):网络请求监听 250 | - 系统增强 251 | - [alfred](https://www.alfredapp.com/):增强版 spotlight 252 | - [bettertouchtool](https://folivora.ai/):快捷键绑定 253 | - [hiddenbar](https://github.com/dwarvesf/hidden):菜单栏图标折叠 254 | - [karabiner-elements](https://karabiner-elements.pqrs.org/):键位映射 255 | - [monitorcontrol](https://github.com/MonitorControl/MonitorControl):通过软件直接控制外接显示器硬件亮度 256 | - [openinterminal](https://github.com/Ji4n1ng/OpenInTerminal):Finder 打开到终端 257 | - [unshaky](https://github.com/aahung/Unshaky):防止按键误触发的工具(解决蝴蝶键盘问题) 258 | - 性能和监控 259 | - [cinebench](https://www.maxon.net/en/products/cinebench-r20-overview/):CPU/GPU 性能测试 260 | - [coconutbattery](https://coconut-flavour.com/coconutbattery/):电池健康度检查 261 | - [daisydisk](https://daisydiskapp.com/):磁盘空间分析 262 | - [istat-menus](https://bjango.com/mac/istatmenus/):任务栏硬件监控 263 | - 其他日用 264 | - [fliqlo](https://fliqlo.com/):一个翻页时钟屏保 265 | - [keka](https://www.keka.io/):压缩软件 266 | - [keycastr](https://github.com/keycastr/keycastr):显示按键(录屏时用) 267 | - [iina](https://iina.io/):视频播放器 268 | - [itsycal](https://www.mowglii.com/itsycal/):菜单栏日历 269 | - [imazing](https://imazing.com/):备份 iPhone 的软件 270 | - [telegram-desktop](https://desktop.telegram.org/):Telegram 桌面客户端 271 | - 网盘/下载 272 | - [onedrive](https://onedrive.live.com/):One Drive 273 | - [megasync](https://mega.nz/sync):Mega Sync,可以排除 node_modules,放一些临时项目用 274 | - [thunder](https://mac.xunlei.com/):迅雷 275 | 276 | ### App store 277 | 278 | - [Blackmagic Disk Speed Test](https://apps.apple.com/us/app/blackmagic-disk-speed-test/id425264550):磁盘速度测试 279 | - [Desktop Clock](https://apps.apple.com/us/app/desktop-clock-live/id894760156?mt=12):桌面时钟 280 | - [GIPHY CAPTURE](https://giphy.com/apps/giphycapture):截动图/视频工具 281 | - [OneNote](https://www.onenote.com/):微软的跨平台笔记 282 | - [QQ](https://im.qq.com/):QQ 283 | - [Unsplash Wallpapers](https://apps.apple.com/us/app/unsplash-wallpapers/id1284863847?mt=12):Unsplash 随机壁纸 284 | - [WeChat](https://mac.weixin.qq.com/):微信 285 | - [Xcode](https://developer.apple.com/xcode/):苹果自家的 IDE 286 | - [Xnip](https://xnipapp.com/):截图工具 287 | -------------------------------------------------------------------------------- /docs/note/02.workspace/1.chrome.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 关于 Chrome 3 | date: 2019-12-14 22:03:19 4 | permalink: /workspace/chrome 5 | categories: 6 | - 开发环境 7 | tags: 8 | - 浏览器 9 | - chrome 10 | --- 11 | 12 | # 关于 Chrome 13 | 14 | ## Chrome 简介 15 | 16 | [Chrome](https://www.google.com/chrome/) 是一个免费的跨平台浏览器,由 Google 开发, 17 | Chrome 对于前端开发来说(尤其是调试代码)非常方便, 18 | 并且有丰富的插件市场,包括很多前端框架的调试插件。 19 | 20 | 用 Brew 安装 Chrome:`brew cask install google-chrome` 21 | 22 | ### Chrome 界面设计 23 | 24 | - [Redesigning Chrome Desktop: The value of a pixel](https://medium.com/google-design/redesigning-chrome-desktop-769aeb5ab987) 25 | - [Unboxing Chrome: Redesigning the omnibox](https://medium.com/@san_toki/unboxing-chrome-f6af7b8161a2) 26 | 27 | ## 浏览器的知识 28 | 29 | ### 浏览器基本调试技巧 30 | 31 | - [在 Chrome DevTools 中调试 JavaScript 入门](https://developers.google.com/web/tools/chrome-devtools/javascript/?hl=zh-cn) 32 | - [Performance Analysis Reference](https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference?hl=zh-cn) 33 | 34 | ### 浏览器原理 35 | 36 | - [当···时发生了什么?](https://github.com/skyline75489/what-happens-when-zh_CN) 37 | - [浏览器输入 URL 后发生了什么?](https://zhuanlan.zhihu.com/p/43369093) 38 | - [Navigation Timing Level 2](https://w3c.github.io/navigation-timing/) 39 | 40 | * [浏览器的工作原理:新式网络浏览器幕后揭秘](https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/) 41 | 42 | - [[译] 现代浏览器内部揭秘(第一部分)](https://juejin.im/post/5b9b0932e51d450e9059c16a) 43 | - [[译] 现代浏览器内部揭秘(第二部分)](https://juejin.im/post/5bc293cf6fb9a05ce95c8468) 44 | - [[译] 现代浏览器内部揭秘(第三部分)](https://juejin.im/post/5bc29d56e51d450e9e4466cc) 45 | - [[译] 现代浏览器内部揭秘(第四部分)](https://juejin.im/post/5bc95247e51d450e40072e49) 46 | 47 | ## 设置 Chrome 48 | 49 | ### 浏览器设置 50 | 51 | - 确认搜索引擎设置为 Google (或 bing、DuckDuckGo,反正不要用百度) 52 | - 开启账号同步 53 | 54 | ### 插件 55 | 56 | 我用的一些重要插件: 57 | 58 | #### 私人 59 | 60 | - [Google Keep](https://keep.google.com/):笔记速写工具 61 | - [LastPass](https://chrome.google.com/webstore/detail/lastpass-free-password-ma/hdokiejnpimakedhajhdlcegeplioahd):密码管理工具 62 | - [Adblock Plus](https://chrome.google.com/webstore/detail/adblock-plus-free-ad-bloc/cfhdojbkjhnklbpkdaibdccddilifddb):广告屏蔽 63 | - [Momentum](https://chrome.google.com/webstore/detail/momentum/laookkfknpbbblfpciffpaejjkokdgca):个性化新标签页 64 | - [PocketTube: Youtube Subscription Manager](https://chrome.google.com/webstore/detail/pockettube-youtube-subscr/kdmnjgijlmjgmimahnillepgcgeemffb):YouTube 订阅管理器 65 | 66 | #### 干活 67 | 68 | - 杂项 69 | - [Proxy SwitchyOmega](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif):Proxy 管理工具 70 | - [Workona](https://chrome.google.com/webstore/detail/workona/ailcmbgekjpnablpdkmaaccecekgdhlh?hl=en):工作区管理器(增强的标签管理器) 71 | - ~~[Tab Manager Plus for Chrome](https://chrome.google.com/webstore/detail/tab-manager-plus-for-chro/cnkdjjdmfiffagllbiiilooaoofcoeff):标签管理器~~ 72 | - [Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo):脚本扩展平台 73 | - [Stylus](https://chrome.google.com/webstore/detail/stylus/clngdbkpkpeebahjckkjfobafhncgmne):网站样式扩展平台 74 | - 英语 75 | - [沙拉查词-聚合词典划词翻译](https://chrome.google.com/webstore/detail/%E6%B2%99%E6%8B%89%E6%9F%A5%E8%AF%8D-%E8%81%9A%E5%90%88%E8%AF%8D%E5%85%B8%E5%88%92%E8%AF%8D%E7%BF%BB%E8%AF%91/cdonnmffkdaoajfknoeeecmchibpmkmg):划词翻译(参考 [英语 训练指南](/study/using-english)) 76 | - [Grammarly for Chrome](https://chrome.google.com/webstore/detail/grammarly-for-chrome/kbfnbcaeplbcioakkpcpgfkobkghlhen):英语语法检查助手 77 | - 增强 78 | - [Video Speed Controller](https://chrome.google.com/webstore/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk):视频快捷键(参考 [用快捷键控制视频播放](/workspace/my-video-player-shortcuts)) 79 | - [User JavaScript and CSS](https://chrome.google.com/webstore/detail/user-javascript-and-css/nbhcbdghjpllgmfilhnhkllmkecfmpld):自定义脚本和样式注入 80 | - [JSON Viewer](https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh):JSON 格式化查看器 81 | - Github 82 | - [Enhanced Github](https://chrome.google.com/webstore/detail/enhanced-github/anlikcnbgdeidpacdbdljnabclhahhmd?hl=en):GitHub 功能增强 83 | - [Isometric Contributions](https://chrome.google.com/webstore/detail/isometric-contributions/mjoedlfflcchnleknnceiplgaeoegien):GitHub 提交活动 3D 化 84 | - [Octotree](https://chrome.google.com/webstore/detail/octotree/bkhaagjahfmjljalopjnoealnfndnagc):Repo 侧边栏文件树 85 | - 开发 86 | - [Console Importer](https://chrome.google.com/webstore/detail/console-importer/hgajpakhafplebkdljleajgbpdmplhie):在控制台安装 npm 包 87 | - [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi):React DevTools 88 | - [Redux DevTools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd):Redux DevTools 89 | - [Vue.js devtools](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd):Vue DevTools 90 | - [MobX Developer Tools](https://chrome.google.com/webstore/detail/mobx-developer-tools/pfgnfdagidkfgccljigdamigbcnndkod):MobX DevTools 91 | -------------------------------------------------------------------------------- /docs/note/02.workspace/2.vscode.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 关于 VS Code 3 | date: 2019-12-14 22:03:19 4 | permalink: /workspace/vscode 5 | categories: 6 | - 开发环境 7 | tags: 8 | - vscode 9 | - 工具 10 | --- 11 | 12 | # 关于 VS Code 13 | 14 | ## VS Code 简介 15 | 16 | [VS Code](https://code.visualstudio.com/) 是一个跨平台代码编辑器,由微软开发并开源, 17 | VS Code 兼顾了轻便性和扩展性,是前端开发(甚至其他语言)的主流编辑器。 18 | (另一些编辑器/IDE,例如:WebStorm、Sublime Text 等) 19 | 20 | 用 Brew 安装 VS Code:`brew cask install visual-studio-code` 21 | 22 | 安装完成后,可以 [注册 `code` 命令](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line), 23 | 使得在命令行中执行 `code ./project1` 即可用 VS Code 打开项目或文件。 24 | 25 | ### VS Code 基本功能 26 | 27 | - 命令行 28 | - [注册 `code` 命令](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line) 29 | - 功能系统 30 | - [命令面板](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) 31 | - [插件系统](https://code.visualstudio.com/docs/editor/extension-gallery) 32 | - [内建终端](https://code.visualstudio.com/docs/editor/integrated-terminal) 33 | - [内建 Git](https://code.visualstudio.com/Docs/editor/versioncontrol#_git-support) 34 | - [snippets](https://code.visualstudio.com/docs/editor/userdefinedsnippets) 35 | - [settings](https://code.visualstudio.com/docs/getstarted/settings) 36 | - 增强功能 37 | - [intellisense](https://code.visualstudio.com/docs/editor/intellisense) 38 | - [定义跳转](https://code.visualstudio.com/Docs/editor/editingevolved#_peek) 39 | - [全局重命名](https://code.visualstudio.com/Docs/editor/editingevolved#_rename-symbol) 40 | - [代码格式化](https://code.visualstudio.com/docs/editor/codebasics#_formatting) 41 | - 开发 42 | - [Debugger](https://code.visualstudio.com/Docs/editor/debugging) 43 | - [快捷键](https://code.visualstudio.com/docs/getstarted/keybindings#_keyboard-shortcuts-reference)(Mac) 44 | - cmd + pcmd + shift + p 45 | - cmd + fcmd + shift + f 46 | - cmd + dcmd + shift + L 47 | - opt + shift + o:organize imports 48 | 49 | ### VS Code 源码 50 | 51 | - [从 VSCode 看大型 IDE 技术架构](https://zhuanlan.zhihu.com/p/96041706) 52 | 53 | ## 使用 VS Code 54 | 55 | ### 入门 56 | 57 | - [VS Code Top-Ten Pro Tips](https://www.youtube.com/watch?v=u21W_tfPVrY) 58 | 10 分钟:10 个 VS Code 常用功能一览 59 | - [Visual Studio Code Intro & Setup](https://www.youtube.com/watch?v=fnPhJHN0jTE) 60 | 40 分钟:(2017 年的视频,有些功能现在可能改变,但总体是相似的) 61 | VS Code 界面功能和配置,基本使用,一些插件介绍,Git 简介 62 | - [Visual Studio Code Can Do That: Tips & Tricks : Build 2018](https://www.youtube.com/watch?v=OOG3xcUQY5k) 63 | 80 分钟: 64 | 65 | - [25 VS Code Productivity Tips and Speed Hacks](https://www.youtube.com/watch?v=ifTF3ags0XI) 66 | 67 | ### 插件 68 | 69 | 我用的一些重要插件: 70 | 71 | - 功能增强 72 | - [Settings Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync):同步所有配置到 Git Gist 73 | - [GitLens — Git supercharged](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens):Git 增强 74 | - [Code Runner](https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner):快捷键直接运行代码文件 75 | - [Diff Tool](https://marketplace.visualstudio.com/items?itemName=jinsihou.diff-tool):Diff 两个文件 76 | - [Code Outline](https://marketplace.visualstudio.com/items?itemName=patrys.vscode-code-outline):显示代码大致结构 77 | - [Quokka.js](https://marketplace.visualstudio.com/items?itemName=WallabyJs.quokka-vscode):直接显示代码运行结果 78 | - [LeetCode](https://marketplace.visualstudio.com/items?itemName=shengchen.vscode-leetcode):在本地刷 LeetCode 79 | - [open in browser](https://marketplace.visualstudio.com/items?itemName=techer.open-in-browser):用浏览器打开文件 80 | - 界面增强 81 | - [Dracula](https://draculatheme.com/):高亮主题 82 | - [Material Icon Theme](https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme):图标主题 83 | - [Better Comments](https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments):不同颜色标记不同类型的注释 84 | - [Todo Tree](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree):高亮显示 TODO 85 | - [Bracket Pair Colorizer](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer):用不同颜色配对不同层级的括号 86 | - [indent-rainbow](https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow):彩虹色缩进 87 | - [Import Cost](https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost):显示包的 import 大小 88 | - [filesize](https://marketplace.visualstudio.com/items?itemName=mkxml.vscode-filesize):显示文件大小 89 | - 自动化 90 | 91 | - [Path Intellisense](https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense):路径自动补全 92 | - [npm Intellisense](https://marketplace.visualstudio.com/items?itemName=christian-kohler.npm-intellisense):包名自动补全 93 | - [Visual Studio IntelliCode](https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.vscodeintellicode):代码自动补全(AI-based) 94 | - [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode):格式化 95 | - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint):静态检查 96 | - [Sort lines](https://marketplace.visualstudio.com/items?itemName=Tyriar.sort-lines):多行字典排序 97 | - [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one):Markdown 增强(参考 [Markdown 学习指南](/cs/markdown)) 98 | - HTML/JSX 99 | - [Auto Close Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag):自动闭合标签 100 | - [Auto Rename Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag):自动重命名标签(同步开头结尾) 101 | - CSS 102 | - 无 103 | - JS 104 | - 无 105 | - React 106 | - [ES7 React/Redux/GraphQL/React-Native snippets](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets):React 开发插件集 107 | - Vue 108 | - [Vue.js Extension Pack](https://marketplace.visualstudio.com/items?itemName=mubaidr.vuejs-extension-pack):Vue 开发插件集 109 | - [Vue 2 Snippets](https://marketplace.visualstudio.com/items?itemName=hollowtree.vue-snippets):Vue 代码片段 110 | -------------------------------------------------------------------------------- /docs/note/08.misc/clean-a-keyboard.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 如何清洁机械键盘 3 | date: 2019-11-08 16:07:45 4 | permalink: /misc/clean-a-keyboard 5 | categories: 6 | - 杂项 7 | tags: 8 | - 杂谈 9 | --- 10 | 11 | # 如何清洁机械键盘 12 | 13 | ## 这都要写? 14 | 15 | 嗯…当我拆干净之后发现缺少趁手的工具,留着那么多垃圾再装回去有点难以接受…… 16 | 但是因为缺少合适的工具,导致整个过程很没有效率,最后也没达到最好的清洁效果。 17 | 18 | ## 总览 19 | 20 | - 耗时:根据工具和方法,大约需要 1~2 小时 21 | - 难度:中(迫真) 22 | - 准备: 23 | - 三角拆机片 24 | - 拔键器 25 | - 酒精棉片 26 | - 十字螺丝刀 27 | - 一字螺丝刀 (或任意够硬的细金属棒) 28 | - 毛刷(旧牙刷) 29 | - 脸盆(可选) 30 | - 内衣网兜+洗衣机(可选) 31 | - 润滑油(可选 缝纫机的那种?) 32 | 33 | ## 过程 34 | 35 | (图忘拍了,以后有机会再补充) 36 | 37 | (酒精是脂溶性的,酒精棉片的作用在于可以有效清除油性物质,确保你的设备本身不会和它发生反应) 38 | 39 | - 在拆之前最好拍一下按键布局(确信) 40 | 41 | * 清洁外壳(如果你想的话) 42 | - 用**拆机片**拆出键盘外壳 43 | - (有的键盘是卡扣式设计的) 44 | - 或用**螺丝刀**拧下外壳(螺丝可能藏在脚垫里) 45 | - 手动水洗或干洗 46 | 47 | - 清洁键帽 48 | - 用**拔键器**拔除所有键帽 49 | - 清洁键帽(方法 N 选 1) 50 | - 把所有键帽装到**内衣网兜**里,扔到**洗衣机**里(洗得巨干净,记得别加烘干步骤防止变形) 51 | - 放**脸盆**里用刷子手动水洗 52 | - 用**酒精棉片**手动干洗 53 | 54 | * 清洁面板 55 | - 手持面板(轴体朝下,防止垃圾屑掉落到轴里) 56 | - 用**毛刷**清洁轴体周围的 PCB(或有钢板)部分 57 | - (因为这样比较经济实惠) 58 | - 用**酒精棉片**进一步清洁 59 | - (有可能会有油脂毛发等顽固污渍) 60 | 61 | - 金属连杆(说明) 62 | - 有的键盘可能会有连杆设计(比如空格那种长键下面会有) 63 | - 拆之前记录部件的安装方式(方向) 64 | - 金属连杆 65 | - 拆除所有相关部件 66 | - 连杆一般都是卡扣式固定在板上,用**一字螺丝刀**从关键部位顶出来 67 | - 都是小部件,可以选择用**酒精棉片**清洁 68 | - 把连杆按照正确的安装方式和键帽组合 69 | - 完毕后可以选择性给关节部位涂上**润滑油** 70 | - 把键帽直接装回面板上 71 | - 用**一字螺丝刀**将连杆的固定位置顶回卡扣中 72 | 73 | * 收尾 74 | - 将所有部分按照正确的方式组装回去 75 | - (清理工作台) 76 | - (测试一下按键可靠性(随便找个在线的 比如 )) 77 | - (拍照发朋友圈假装是个新键盘) 78 | -------------------------------------------------------------------------------- /docs/note/08.misc/linux-basic-security.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Ubuntu 服务器基本防护 3 | date: 2019-11-10 21:57:03 4 | permalink: /misc/linux-basic-security 5 | categories: 6 | - 杂项 7 | tags: 8 | - 杂谈 9 | --- 10 | 11 | # Ubuntu 服务器基本防护 12 | 13 | 记录一下步骤 14 | 15 | - 加一个新用户 16 | - 禁用 root 登录 17 | - 禁用密码登录(只允许 rsa) 18 | - 修改 ssh 端口 19 | - 防火墙 20 | 21 | ## 用户 22 | 23 | ```bash 24 | # * 加用户 25 | sudo adduser USERNAME 26 | # * 加到 root 组 27 | sudo usermod -aG sudo USERNAME 28 | 29 | # * 删除用户(可能要先 kill 该用户进程) 30 | # ps -aux | grep USERNAME 31 | # sudo pkill -u USERNAME 32 | sudo deluser USERNAME 33 | sudo groupdel GROUPNAME 34 | 35 | # * 查看用户和组 36 | cat /etc/passwd 37 | cat /etc/group 38 | 39 | # * 修改密码,ubuntu 初始 root 无密码 40 | sudo su root 41 | sudo passwd root 42 | 43 | # * sudo 免密 44 | echo -e "\n USERNAME ALL=(ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers 45 | 46 | # * 加 shh key (在 host 操作 需要在关闭密码登录前操作) 47 | ssh-copy-id -i ~/LOCALKEY.public USER@HOST 48 | 49 | # * ssh 认证文件位置 每条 append 50 | # /root/.ssh/authorized_keys 51 | # /home/USERNAME/.ssh/authorized_keys 52 | 53 | # * change user 54 | su 55 | ``` 56 | 57 | ## ssh 配置 58 | 59 | ```bash 60 | # * check 61 | # sudo vi /etc/ssh/sshd_config 62 | 63 | # * tweak config 64 | sudo sed -i 's/^.*\bPort\b.*$/Port 0000/' /etc/ssh/sshd_config 65 | sudo sed -i 's/^.*PasswordAuthentication.*$/PasswordAuthentication no/' /etc/ssh/sshd_config 66 | # sudo sed -i 's/^.*PasswordAuthentication.*$/PasswordAuthentication yes/' /etc/ssh/sshd_config 67 | 68 | # * default is 'prohibit-password', so its not necessery 69 | sudo sed -i 's/^.*PermitRootLogin.*$/PermitRootLogin no/' /etc/ssh/sshd_config 70 | # sudo sed -i 's/^.*PermitRootLogin.*$/PermitRootLogin yes/' /etc/ssh/sshd_config 71 | # sudo sed -i 's/^.*PermitRootLogin.*$/#PermitRootLogin prohibit-password/' /etc/ssh/sshd_config 72 | 73 | # * 重启服务 74 | sudo service sshd restart 75 | # sudo systemctl restart sshd 76 | ``` 77 | 78 | ## ufw 防火墙 79 | 80 | ```bash 81 | # * 拒绝所有,打开指定 82 | 83 | sudo ufw default deny incoming 84 | 85 | # sudo ufw allow ssh 86 | sudo ufw allow 0000 87 | sudo ufw allow from 0.0.0.0 to any port 0000 proto tcp 88 | 89 | # * 禁止 ping 90 | sudo copy /etc/ufw/before.rules /etc/ufw/before.rules.bak 91 | sudo sed -ir 's/\(ufw-before-input -p icmp --icmp-type.*\) .*/\1 DROP/' /etc/ufw/before.rules 92 | # sudo sed -ir 's/\(ufw-before-input -p icmp --icmp-type.*\) .*/\1 ACCEPT/' /etc/ufw/before.rules 93 | 94 | # * 直接改了配置文件需要重启 ufw 95 | sudo ufw reload 96 | ``` 97 | 98 | ## 系统 99 | 100 | ```bash 101 | # * 设置主机名 102 | hostnamectl set-hostname example.com 103 | 104 | # * 查看 shell 105 | echo $SHELL 106 | cat /etc/shells 107 | 108 | # * 查看系统信息 109 | cat /etc/*-release 110 | ``` 111 | 112 | ## 其他命令 113 | 114 | ```bash 115 | 116 | # * 生成秘钥 117 | ssh-keygen -t rsa -b 4096 -f ~/folder/id_rsa 118 | 119 | # * 端口转发 120 | ssh -LN localhost:2000:theirlocalhost:80 root@0.0.0.0 -p 0000 121 | 122 | # * 清除某个 known_hosts 123 | ssh-keygen -R HOSTNAME 124 | 125 | # * proxy 126 | export http_proxy=http:// 127 | export https_proxy=http:// 128 | ``` 129 | -------------------------------------------------------------------------------- /docs/note/08.misc/my-video-player-shortcuts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 用快捷键控制视频播放 3 | date: 2019-12-14 22:03:19 4 | permalink: /workspace/my-video-player-shortcuts 5 | categories: 6 | - 开发环境 7 | tags: 8 | - 脚本 9 | --- 10 | 11 | # 用快捷键控制视频播放 12 | 13 | 如果你有通过视频学习的经历, 14 | 你应该知道快进快退暂停调速等视频控制功能有多重要。 15 | 16 | ## 我的快捷键 17 | 18 | 我在用的一组桌面快捷键, 19 | 通过覆盖键盘左侧,实现方便的(左手)单手控制。 20 | 21 | (注意到 [FrontendMasters](https://frontendmasters.com/) 的 Q 键是切换视频质量,有冲突) 22 | 23 | - 通用 24 | - Q:快退 3 秒 25 | - E:快进 3 秒 26 | - Z:播放速度 -0.25 27 | - X:播放速度 +0.25 28 | - V:在(当前播放速度,1)之间切换 29 | - 网页 Only(YouTube 自带) 30 | - T:切换网页全屏 31 | - C:切换字幕/弹幕 32 | - 本地 Only 33 | - PageUp:上一文件 34 | - PageDown:下一文件 35 | - Shift+:快进 30 秒 36 | - Shift+:快退 30 秒 37 | 38 | ## 工具 39 | 40 | ### Video Speed Controller 41 | 42 | Chrome 插件:[Video Speed Controller](https://chrome.google.com/webstore/detail/video-speed-controller/nffaoalbilbmmfgbnbgppjihopabppdk) 43 | 44 | ### User JavaScript and CSS 45 | 46 | Chrome 插件:[User JavaScript and CSS](https://chrome.google.com/webstore/detail/user-javascript-and-css/nbhcbdghjpllgmfilhnhkllmkecfmpld) 47 | 48 | 自定义脚本注入插件 49 | 50 | 我在 BiliBili 的配置,实现类似 YouTube 的观看体验。 51 | 52 | ```javascript 53 | { 54 | let maskShown = true; 55 | document.addEventListener('keypress', (e) => { 56 | if (e.key === 't') { 57 | $('.bilibili-player-video-web-fullscreen').click(); 58 | } 59 | if (e.key === 'c') { 60 | // * use opacity but not disable the feature 61 | maskShown = !maskShown; 62 | $('.bilibili-player-video-danmaku').css( 63 | 'opacity', 64 | maskShown ? 1 : 0, 65 | ); 66 | $('.bilibili-player-video-danmaku-switch').css( 67 | 'opacity', 68 | maskShown ? 1 : 0.1, 69 | ); 70 | } 71 | }); 72 | } 73 | ``` 74 | 75 | ### IINA/PotPlayer 76 | 77 | 都支持快捷键改键 78 | 79 | - [IINA](https://iina.io/):macOS 上的播放器 80 | - [PotPlayer](https://potplayer.daum.net/):Windows 上的播放器 81 | -------------------------------------------------------------------------------- /docs/note/08.misc/scc/count-lines-of-code.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 代码行数统计工具小测 3 | date: 2020-02-08 20:15:50 4 | permalink: /cs/count-lines-of-code 5 | categories: 6 | - 计算机科学 7 | tags: 8 | - 工具 9 | --- 10 | 11 | # 代码行数统计工具小测 12 | 13 | ## 背景 14 | 15 | 代码量统计可以量化地分析项目中的代码的情况。 16 | 17 | 我最早知道和使用的是 cloc,但是我一直不满意它的运行速度, 18 | 可能小型项目没什么感觉, 19 | 而我处理的项目源码有几十万行的代码量(排除 `node_modules`), 20 | 统计一次需要稳定花费 20s…… 21 | 22 | 虽然它的筛选功能很强大,但是实在是太慢了… 23 | 后来我偶然间发现了其他同类工具,直接从 20s 来到 1s, 24 | 太香了! 25 | 26 | 那这些工具有(按字典排序): 27 | 28 | - cloc: 29 | - loc: 30 | - scc: 31 | - tokei: 32 | 33 | 它们有各有差异,诸如: 34 | 35 | - 对文件的默认排除(隐藏文件、`gitignore` 等)策略不同 36 | - 对注释和空行的识别有差异 37 | - 默认的排序项等等 38 | 39 | 但它们都支持一些基本的统计需求: 40 | 41 | - 显示每个文件的独立分析 42 | - 是否包含隐藏文件 43 | - 包含/排除指定文件 44 | - 结果按某列排序 45 | - 总和 46 | 47 | 都是实用的工具。 48 | 49 | ## 简单测试对比 50 | 51 | 先来一些我发现的基本的纸面数据: 52 | 53 | | Repo | Star | 更新 | 语言 | 功能\* | 默认排序 | 速度 | 54 | | :--------------: | :----------: | :----------: | :--: | :----: | :------: | :--: | 55 | | [cloc][cloc-u] | ![][cloc-s] | ![][cloc-l] | Perl | 84 | 代码行数 | 慢 | 56 | | [loc][loc-u] | ![][loc-s] | ![][loc-l] | Rust | 6 | 代码行数 | 快 | 57 | | [scc][scc-u] | ![][scc-s] | ![][scc-l] | Go | 29 | 文件数量 | 快 | 58 | | [tokei][tokei-u] | ![][tokei-s] | ![][tokei-l] | Rust | 14 | 语言类型 | 快 | 59 | 60 | [cloc-u]: https://github.com/AlDanial/cloc 61 | [loc-u]: https://github.com/cgag/loc 62 | [scc-u]: https://github.com/boyter/scc 63 | [tokei-u]: https://github.com/XAMPPRocky/tokei 64 | 65 | 66 | 67 | [cloc-l]: https://img.shields.io/github/last-commit/AlDanial/cloc 68 | [loc-l]: https://img.shields.io/github/last-commit/cgag/loc 69 | [scc-l]: https://img.shields.io/github/last-commit/boyter/scc 70 | [tokei-l]: https://img.shields.io/github/last-commit/XAMPPRocky/tokei 71 | 72 | 73 | 74 | [cloc-s]: https://img.shields.io/github/stars/AlDanial/cloc 75 | [loc-s]: https://img.shields.io/github/stars/cgag/loc 76 | [scc-s]: https://img.shields.io/github/stars/boyter/scc 77 | [tokei-s]: https://img.shields.io/github/stars/XAMPPRocky/tokei 78 | 79 | 还有 tokei 自己做的性能对比: 80 | 81 | 82 | > 注:功能的值来自除了 `help` 以外的参数个数,诸如: 83 | > 84 | > ```bash 85 | > cloc --help | grep -v '\-\-help' | grep -E '^.{0,20}\-\-' | wc -l 86 | > ``` 87 | 88 | 可以看到 cloc 是 star 最多的, 89 | 功能也是最丰富的, 90 | 包括它的文档说明也是巨细无遗, 91 | (可惜它是真的慢……) 92 | 93 | 行叭,看看实际干活都怎么样。 94 | 95 | 先找一个巨型仓库:Babel、 96 | 然后是规模小一点的:RxJS、 97 | 最后自己新建了一些文件试试。 98 | 99 | ```bash 100 | git clone --depth=1 https://github.com/babel/babel 101 | git clone --depth=1 https://github.com/ReactiveX/rxjs 102 | git clone --depth=1 https://github.com/seognil-study/cloc-playground 103 | ``` 104 | 105 | ## 测试结果 106 | 107 | 直接用最大的 babel 来试试各个工具和结果如何: 108 | 109 | > 注:`time` 是 mac 上统计运行时间用的, 110 | > 打印出来 `total` 左边的数字是实际运行秒数,比如: 111 | > 112 | > ```bash 113 | > time sleep 1 114 | > sleep 1 0.00s user 0.00s system 0% cpu 1.007 total 115 | > ``` 116 | 117 | `time cloc --skip-uniqueness babel` ↓ 118 | 119 | ![time-cloc-babel](./img/time-cloc-babel-fs8.png) 120 | 121 | `time loc --sort=lines babel` ↓ 122 | 123 | ![time-loc-babel](./img/time-loc-babel-fs8.png) 124 | 125 | `time scc -s=lines babel` ↓ 126 | 127 | ![time-scc-babel](./img/time-scc-babel-fs8.png) 128 | 129 | `time tokei -s=lines babel` ↓ 130 | 131 | ![time-tokei-babel](./img/time-tokei-babel-fs8.png) 132 | 133 | ## 小结 134 | 135 | cloc 确实是最慢的,要花 10s 以上, 136 | (cloc 是否关闭去重功能,其实对速度的影响有限…) 137 | 138 | 而其他工具基本都在 1s 左右, 139 | 这是对于 Babel 仓库 88MB、一万多个文件的情况, 140 | 更小的项目只会更快。 141 | 142 | 另外可以注意到对文件识别上的差别: 143 | 144 | - cloc 没有统计 Plain Text 145 | - loc 将 `ts`/`tsx` 区分成了 `TypeScript`/`Typescript JSX` 146 | - 各个工具找到的文件和统计也有差别 147 | 148 | 我手动 find 的文件数量: 149 | 150 | `find babel -name "*.json" | wc -l` 151 | 结果是 6428,和 `cloc`、`scc` 一致 152 | 153 | `find babel -name "*.js" | wc -l` 154 | 结果是 9436,和 `loc -uu` 一致 155 | 156 | 而诸如代码和注释,每个工具也有所差别, 157 | 比如我发现 JSON 中的注释它们都是不支持的, 158 | 159 | ```json 160 | { 161 | // 注释 162 | /** 163 | * 注释 164 | */ 165 | } 166 | ``` 167 | 168 | 你说 JSON 不支持注释,为什么 JSON 里有注释? 169 | 实际上在 VS Code 里支持一种语言类型叫 `JSON with Comments`, 170 | 以下文件都支持 JSON + 注释而不会造成失效: 171 | 172 | - VS Code 的 `settings.json` 173 | - Prettier 的 `.prettierrc` 174 | - TypeScript 的 `tsconfig.json` 175 | 176 | 所以统计差异可以理解, 177 | 毕竟这些工具的代码也是人来维护的, 178 | 不可能穷尽和覆盖世界上的所有语言。 179 | 180 | `.jsx` 来自于 React,万一哪天出了 `.jsy`、`.jsz` 新 DSL 呢? 181 | 还有 `.prettierrc` 是什么?(它们都识别不了) 182 | 183 | 实际上 `.prettierrc` 支持 JSON 或 YAML 的不同格式, 184 | 然而如果还要解析语法,这就超出了简单的统计工具的能力范围了。 185 | 186 | 后续我可能会使用 scc,毕竟看上去统计的是最全的,数字是最多的(误 187 | 而且开发复杂度和开发成本估计的功能挺有意思… 188 | -------------------------------------------------------------------------------- /docs/note/08.misc/scc/img/time-cloc-babel-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/08.misc/scc/img/time-cloc-babel-fs8.png -------------------------------------------------------------------------------- /docs/note/08.misc/scc/img/time-loc-babel-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/08.misc/scc/img/time-loc-babel-fs8.png -------------------------------------------------------------------------------- /docs/note/08.misc/scc/img/time-scc-babel-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/08.misc/scc/img/time-scc-babel-fs8.png -------------------------------------------------------------------------------- /docs/note/08.misc/scc/img/time-tokei-babel-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/08.misc/scc/img/time-tokei-babel-fs8.png -------------------------------------------------------------------------------- /docs/note/08.misc/study/dont-waste-your-time-and-money.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 杂谈:你可学点好吧 3 | date: 2021-10-03 16:47:25 4 | permalink: /study/dont-waste-your-time-and-money 5 | categories: 6 | - 学习技巧 7 | tags: 8 | - 杂谈 9 | --- 10 | 11 | # 杂谈:你可学点好吧 12 | 13 | 我叫 LC,现在在做前端开发。 14 | 15 | 我刚入行的时候,当时缺少大佬的指点,自己的认知水平也不太行。走了很多弯路,看过很多粗制滥造或的教程。 16 | 17 | 所谓走弯路。用最近新学到的一个词 **ROI**(Return On Investment),即**投入产出比**来解释。对于学习而言,投入具有多种形态:时间、精力、金钱、情绪等,而最直观的产出则是是否学会了某项技能。所谓走弯路即是 ROI 低,效率低。 18 | 19 | 现在随着我的技能水平和视野不断提升,我已经接触到了很多优秀的资料,也认识了一些能给我指引方向的人,甚至我自己也逐渐成为别人眼中专业的人。今天的我如果穿越回去重新教自己,肯定少走一些弯路。 20 | 21 | 比方说时间角度,知道了从哪获取优质的、专业的、由浅入深的、合适的资料,避免大海捞针式地看低质的、业余的资料。有效信息密度提高了,学习效率自然也就高了。 22 | 23 | 经济角度,问题转而变成:我如何便宜地筛选和获取这些优秀资料? 24 | 25 | 其中有一个我觉得最亏的一笔支出,那是我花了一万多块买了一套为期几个月的“高级前端进阶课程”(具体名字忘了,反正都这个味儿)。 26 | 27 | ## 故事 28 | 29 | 当时比较 naive。试听了几个小时,看了下他们的课程大纲,对标大厂 P 几 T 几,挑战年薪几十万。我以为贵自然有贵的道理,一套十全大补汤下来我的水平肯定能再提高一个段位。 30 | 31 | 也确实不错,想必对于很多初级前端来说或许真的能让他们快速入行,或者跳槽的时候工资翻倍。 32 | 33 | 我自己也是有所收获。JS 的语言标准 ECMA-262、JS runtime 的 Execution Context Stack、Node.js 垃圾回收原理等概念我最早就是从这儿知道的。 34 | 35 | **但也仅限于此了**。 36 | 37 | 当时我已经看过一些文章和书,有一些工程经验和理论储备了。所以课程中讲的很多理论性内容我早就知道了,高程和小黄书上都有嘛,无非就是用刁钻题再多训练几遍。但这没什么意义,实际工程中最佳实践是提倡少写骚代码的。 38 | 39 | 举个例子。我现在写项目,`function`、`class`、`this`、`var`、`==` 这些基本不用。现在 React 推行函数式编程,我直接箭头函数、`const`、外加 ESLint 和 TypeScript 拉满就好了。精通 this 的四种写法干嘛呢?手写 ES5 继承和 new?这些知道下概念以后能看懂不就好了?精通八股文是哪门子的高级? 40 | 41 | 框架类库的实战训练课程也就是教下概念,调调 API 糊个玩具项目,还有面试装逼用的源码解析环节。但是没接触过的工具我不能自己学啊?官方文档、Demo、视频教程、源码解析这些网上遍地都是啊?碰到瓶颈了多用用 Stack Overflow、看看不同的解释不就完事了? 42 | 43 | 啊,还有什么前端图形学。听上去高大上,搞半天用下 three.js 而已,还以为会科普下 pbr 之类的呢… 44 | 45 | 就这? 46 | 47 | 所以总体来说并没有达到我对一个五位数级别知识付费的期望。除了最开始可能十个小时的内容我全部听完了,也刷了一些题目,之后基本就没再怎么打开过。 48 | 49 | ## 技术培训产业 50 | 51 | 有的小可爱比较机灵:那我去咸鱼买盗版,去网盘直接下各种全集,我也不是大佬,好歹能查漏补缺,学到点东西,白嫖总不会亏吧? 52 | 53 | 真不亏吗?之前提到,投入是具有多种形态的。培训机构只不过是没赚到一些钱而已,可你却失去了宝贵的时间啊! 54 | 55 | 我前几年零散看(嫖)过一些国内的视频教程(包括刚才提到的,以及像网易云课堂、慕课网、黑马之类的)。无论收费免费,大部分质量都很一般,甚至还有: 56 | 57 | 个别讲师对技术的理解僵化,教条主义,照本宣科。 58 | 个别讲师搞起直播文化,求弹幕刷礼物,不知道的还以为娱乐主播呢。 59 | 60 | 稍有经验的前端工程师应该都清楚前端**技术更新**的速度。如果不是长期参与实际项目、拥有扎实的基础训练、并不断思考,光靠别人把知识灌到自己的脑子里是很难理解到**技术的本质**、形成对技术的判断力和直觉的。 61 | 62 | 以状态管理为例,培训班顶多教教 Redux、Vuex 啥的速成一下,撑死了讲源码甚至手写一个。但我在工作中实际接触过的状管工具不下十个,做针对性项目选型、需求分析、看论文、自研。哪个培训班能提供这些冰山以下的东西?时间有限,大部分声称高大上的课程,都只是入个门而已。 63 | 64 | 此外我有时会直接关注业界的最新动向,看看大佬们在干什么: 65 | 66 | - **Dan Abramov**:Redux 的作者,React 核心开发者 67 | - **Dmitry Soshnikov**:JavaScript: The Core 的作者 68 | - **Douglas Crockford**:JavaScript: The Good Parts 的作者 69 | - **Evan You**:Vue.js 的作者 70 | - **Robert C. Martin**:Clean Code 的作者 71 | 72 | 又有哪个培训班有这种教学资源? 73 | 74 | ## 如何学习 75 | 76 | 说到底是市场人才需求的膨胀以及人们的职业焦虑,影响培训产业也快速发展。 77 | 78 | 培训班的商业模式就是靠卖课恰饭嘛,恰饭多香啊。但很多有能力的人直接在开发者大会上做分享,搞开源项目拿赞助,给大厂做付费咨询。他们走另外的赛道了,会稀得开这种恰饭的培训班吗? 79 | 80 | 哦也是有的,我也确实认识一些创业做培训或是副业技术自媒体的大佬。恰饭嘛,不寒碜。广义上来讲,大学不也是付费培训班呗……我看过 CMU、Stanford 的公开课和教材,也听过尤雨溪讲 Vue、Dan 讲 Redux 的完整课程。 81 | 82 | 所以倒不是培训班本身不好,而是产业规模化之后整体质量的下滑或内卷跑偏,导致获取优质信息的成本变大了。 83 | 84 | 暂停一下,所以…不是培训班本身不好…吗?我认为本质问题也不在这,获取资源的成本先不谈,我认为培训班或者说系统性课程在形式上也有局限性。 85 | 86 | 学前端的时候来一套课程,那之后学后端和其他技术栈呢?想做投资,了解下商业、经济、法律呢?教育、心理学、沟通能力这些呢?生活技能像吉他、摄影、写作、烹饪、健身这些呢?全靠所谓的培训吗?就算钱包受得住(家里有矿是吧),时间也顶不住啊。 87 | 88 | 通常我们的需求只是够用就好,不可能对每个领域都进行无限的投入并以成为该领域专家为目标。 89 | 90 | 所以,我现在看待培训班,并不把它当做标准答案甚至救命稻草,反而是一个参考、一种学习工具。它就像电脑、技术框架、书一样都是工具。好的工具拿来用,不趁手的工具就不用。我们需要的不是“鱼”的结果而是“渔”的技巧。做工具的主人,不断形成自己的思考,训练和掌握主动检索信息的能力,才能多快好省地学到东西,更高效地实现自我提升。 91 | 92 | 现在那种成套的培训班视频我基本不看了(新领域也如此)。把钱用来买订阅服务和书(书可太便宜了),把时间用来看 Youtube 上的各种 Crash Course、开发者大会、官方文档、经典书籍、论文、技术专栏、博客…… 93 | 94 | > You don’t need college to learn stuff 95 | > Everything is available basically for free 96 | > You can learn anything you want for free 97 | > 98 | > -- [Elon Musk knocks the college experience](https://www.youtube.com/watch?v=Io3sdAAcZLw) 99 | 100 | ## 参考资料 101 | 102 | - [前端职业规划 - 2021 年](https://github.com/ascoders/weekly/blob/master/%E5%89%8D%E6%B2%BF%E6%8A%80%E6%9C%AF/196.%E7%B2%BE%E8%AF%BB%E3%80%8A%E5%89%8D%E7%AB%AF%E8%81%8C%E4%B8%9A%E8%A7%84%E5%88%92%20-%202021%20%E5%B9%B4%E3%80%8B.md) 103 | - [中国的程序员数量是否已经饱和或者过剩?](https://www.zhihu.com/question/356982241/answer/1010277323) 104 | - [【李自然说】在线教育,又一个伪风口?](https://www.bilibili.com/video/BV114411r74i/) 105 | - [你能做我的 mentor 吗 - 湾区日报](https://wanqu.co/a/7452/%E4%BD%A0%E8%83%BD%E5%81%9A%E6%88%91%E7%9A%84-mentor-%E5%90%97/) 106 | -------------------------------------------------------------------------------- /docs/note/08.misc/study/study-fortune.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 关于学习的鸡汤 3 | date: 2019-12-29 16:08:12 4 | permalink: /study/study-fortune 5 | categories: 6 | - 学习技巧 7 | tags: 8 | - 杂谈 9 | --- 10 | 11 | # 关于学习的鸡汤 12 | 13 | ## TLDR 14 | 15 | 我觉得最重要的三点([学习方法论](/study/crash-course-study-skills)): 16 | 17 | - 学得会并记得住 18 | - 大量搜集资源 19 | - 掌握解决问题的思维(DEBUG) 20 | 21 | ## 持续前进 22 | 23 | - [【C 菌】全是干货!GPA4.0 研究生 UP 主教你学习诀窍!](https://www.bilibili.com/video/av63716273/) 24 | - [永远投资你的教育](https://wanqu.co/a/4092/%E6%B0%B8%E8%BF%9C%E6%8A%95%E8%B5%84%E4%BD%A0%E7%9A%84%E6%95%99%E8%82%B2/) 25 | - [A Valuable Lesson For A Happier Life](https://www.youtube.com/watch?v=SqGRnlXplx0) 26 | 27 | > 学而时习之 温故而知新 —— 孔子 28 | 29 | 保持兴趣,循序渐进 30 | 广泛涉猎,融汇贯通 31 | 32 | 编程是理科,同时也是工科。 33 | 行业中有一些部分,可能并不是极难的研发性质的工作, 34 | 仅仅只是学习前人的经验,并仿照着实现而已。 35 | 36 | 根据自己当前的水平适当调整节奏。 37 | 不要经历“习得性无助” —— “我总是不行,太难了,做不了。” 38 | 反之,不断给自己创造微小的成就感,持之以恒就能点亮整片技能树。 39 | 40 | ~~(曾经我周末花了一整天,仅仅在反复琢磨 node 和 npm 的版本和安装卸载,并在之后快乐了一个星期)~~ 41 | 42 | ## 练习英语 43 | 44 | [英语 训练指南(编程篇)](/study/using-english) 45 | 46 | ## 工程师思维 47 | 48 | 养成解决问题的习惯,而不仅仅是能够解决问题。 49 | 学会发现问题,而不是人云亦云。 50 | (这也是工作和上学最大的区别之一) 51 | 52 | 随着工作经历的增加,一定会碰到无数之前没有见过的问题、知识、技能需要学习。 53 | 这其中有的新技能是通用的,掌握之后是可以长期受用的, 54 | 也有一些问题,仅仅是暂时的,以后永远不会再碰到的。 55 | (当然,能够提前区分这两种类型也需要靠不断的经验积累) 56 | 57 | 那么通过预先学习来覆盖所有情况是不现实的。 58 | 所以要学会即时发现新的问题,并运用一定的技巧去尝试解决, 59 | 比如基于本站的文章,就能产生很多问题: 60 | 61 | - “很多资料链接都是英文的,以我目前的英语水平会很吃力,有没有可能已经有翻译版了呢” 62 | - “这个概念我不懂,文中的解释也不够充分,我从哪里可以查阅呢” 63 | - “我从不同的地方看到了相反的答案,如何判断哪个是正确的呢” 64 | - “这是别人的心得,我如何定制适合自己的计划呢” 65 | - “这个工具我用着很别扭,有什么方式可以改进呢” 66 | 67 | 互联网上有无数免费和付费的资料。 68 | 69 | ## 理解编程 70 | 71 | [计算机科学 入门指南](/cs/crash-course-computer-science) 72 | 73 | 了解框架原理,而不是背诵框架 API。 74 | 学习编程思想,而不是深究实现细节。 75 | (比如不要在初学阶段沉迷研究 JS 里的隐式类型转换具体规则) 76 | 77 | 你是工具的主人,不是工具的奴隶, 78 | 语言、框架、软件、电脑是你的工具。 79 | 了解工具的性质,更好地使用它们。 80 | 81 | ### 调整心态 82 | 83 | 前期避免过度追求变现, 84 | 优先追求掌握技能和创造价值, 85 | 有技术水平才能有议价能力。 86 | 87 | (说人话:不要太关心能拿多高的工资) 88 | (但是也要考虑工作和学习、生活的平衡) 89 | 90 | 面向解决技术问题开发,而不是面向解决具体业务开发。 91 | (如果有机会的话…) 92 | 93 | ~~尤其是在互联网资本寒冬的现在(真的吗?)~~ 94 | 夯实基础,稳步前进。 95 | 96 | ### 费曼学习法 97 | 98 | [【思维论 03】费曼学习法的误区:为什么学渣给学霸讲题,学习收益才更高?](https://www.bilibili.com/video/av88910392) 99 | 100 | 我理解的一句话版本: 101 | 102 | > 如果你能将一个概念完整地教会别人,那么说明你掌握了它。 103 | 104 | 对于任何一个知识/技术体系来说, 105 | 你第一次发现它的时候,它还不属于你, 106 | 你只能通过查阅来弄懂。 107 | 108 | 而当你不断地在脑海中构建和修正出自己的结构化体系, 109 | 你能够基于自己的体系,在脑海中直接快速地检索到它的每一个细节, 110 | 那么你就掌握了它。 111 | 112 | ### 小黄鸭调试法 113 | 114 | > 小黄鸭调试法,又称橡皮鸭调试法、黄鸭除虫法(Rubber Duck Debugging)是可在软件工程中使用的一种调试代码的方法。方法就是在程序的调试、调试或测试过程中,操作人耐心地向小黄鸭解释每一行程序的作用,以此来激发灵感与发现矛盾。 115 | 116 | 看似很胡扯,但是其实是非常严肃的道理。 117 | 118 | > 就在解释的过程中,程序员可能就发觉了问题的解决方案。 119 | 120 | 程序的运作,代码的运行都是有据可循的: 121 | 运行结果不符合预期,肯定是某一步或者某几步出了问题。 122 | 通过不断拆分步骤并逐步分析,就能定位到问题所在,才能试图解决它。 123 | 124 | ### 编程训练 125 | 126 | > 限制方法的灵活性几乎总能使你把事情做得更好。 —— DOOM 之父 约翰卡马克 127 | > 学而不思则罔,思而不学则殆 —— 孔子 128 | > 最高级的想象力是不自由的 —— 同人于野 129 | 130 | 一定要向古老的智慧学习,理解久经考验的技术思路的精髓。 131 | 132 | 算法、设计模式、范式、特性、规范、协议等等,各式各样的名词… 133 | 不严谨地来讲,我认为指的都是同一件事 —— 别人总结的成熟可靠的经验。 134 | 135 | > 纸上得来终觉浅,绝知此事要躬行 —— 陆游 136 | 137 | 同时,写代码这件事,只能通过反复的实际编写运行和推敲才能掌握, 138 | 才更有机会形成(潜意识的)技术直觉。 139 | (就像学会开车) 140 | ~~(就像上文中我反复安装 node 的故事那样)~~ 141 | 142 | > Learn fast, Learn Cheap 143 | > 工欲善其事,必先利其器 —— 孔子 144 | 145 | 软件工程中有敏捷开发的概念,学习本身也可以敏捷化。 146 | 想办法优先提高效率。(即使这个过程很耗时) 147 | 148 | 举个例子:在仿写 JS 代码的时候如何快速运行? 149 | 打开浏览器的 devtools 手动敲吗? 150 | 更好的方式是:利用 [VS Code](/workspace/vscode) + [Code Runner](https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner) + [Quokka.js](https://marketplace.visualstudio.com/items?itemName=WallabyJs.quokka-vscode) 151 | 152 | ### Environment/Body/Mind 153 | 154 | [每月高效工作 200 小时](https://wanqu.co/a/5765/%E6%AF%8F%E6%9C%88%E9%AB%98%E6%95%88%E5%B7%A5%E4%BD%9C-200-%E5%B0%8F%E6%97%B6/) 155 | 156 | 利用环境和工具 157 | 保持健康的身体和清醒的头脑 158 | 自我激励和自我意志 159 | 160 | 适当休息暂停学习,长期来看反而能产生更大的效益(边际效益最大化) 161 | -------------------------------------------------------------------------------- /docs/note/08.misc/study/why-we-need-to-study.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 杂谈:我们为什么需要读书和学习 3 | date: 2021-10-02 13:13:35 4 | permalink: /study/why-we-need-to-study 5 | categories: 6 | - 学习技巧 7 | tags: 8 | - 杂谈 9 | --- 10 | 11 | # 杂谈:我们为什么需要读书学习 12 | 13 | > 要说这世界有多少本书 14 | > 仿佛这世间来过多少个人就有多少本书 15 | > 有的书只写到了目录 16 | > 有的书全是过往的痕迹 17 | > 虽然时光会让新书变旧 18 | > 但文字却不会因岁月沧桑 19 | > 空出两格另起一段 20 | > 辗转反侧再写一行 21 | > 要到何处埋下伏笔 22 | > 又在何处会惊艳全场 23 | > 24 | > -- [《图 书 馆 子》- 巫托邦](https://www.bilibili.com/video/BV1J64y187C3) 25 | 26 | ## 浅谈 27 | 28 | 人类还不具备(像黑客帝国一样)直接下载知识技能到大脑的能力。 29 | 30 | 从最初的牙牙学语和直立行走,到基础义务教育,再到通过专业技能进行劳动创造社会价值。 31 | 一切知识技能都需要通过缓慢而长期地学习和训练获得。 32 | 33 | 抽象地来说:学习的过程,其实是人体这个碳基系统**训练新的输入输出响应**的过程, 34 | 这个过程将会更新肌肉以及人体各部分的生物设施,以及不断塑造新的大脑**神经通路**。 35 | 36 | 正如古人所云: 37 | 38 | > 纸上得来终觉浅,绝知此事要躬行。 39 | 40 | 我们不断地向他人学习、通过历史资料学习,学习那些前人已经帮我们总结出的经验,从而与当今的世界共存,同时不断创造出新的知识。 41 | 42 | ## 扩展阅读 43 | 44 | - [B 站 UP 主:智能路障](https://space.bilibili.com/79577853) 45 | - [2020 世界读书日 节目](https://www.bilibili.com/video/BV1T5411w7yh) 46 | - [读书又不能赚钱,那么读书到底有什么用呢?](https://www.bilibili.com/video/BV1ug4y187W7) 47 | - [2021 世界读书日 节目](https://www.bilibili.com/video/BV1T5411w7yh) 48 | - [读书和成功有必然联系吗?我们为什么要读书?](https://www.bilibili.com/video/BV1RQ4y1177C) 49 | - 湾区日报 50 | - [最好的投资](https://wanqu.co/a/4701/) 51 | - [巴菲特公式](https://wanqu.co/a/4065/2016-10-12-the-buffett-formula/) 52 | - [五个比 Bitcoin 更好的投资](https://wanqu.co/a/6067/%E4%BA%94%E4%B8%AA%E6%AF%94-bitcoin-%E6%9B%B4%E5%A5%BD%E7%9A%84%E6%8A%95%E8%B5%84/) 53 | - 短片小说 54 | - [他们是肉造的 - 泰利·比森](https://www.zhihu.com/question/321878154) 55 | - [乡村教师 - 刘慈欣](http://www.00txt.com/xiangcunjiaoshi/2033.html) 56 | -------------------------------------------------------------------------------- /docs/note/10.frontend/02.javascript/1.javascript-foundation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 学习指南 * 3 | date: 2019-08-08 18:36:05 4 | permalink: /frontend/javascript-foundation 5 | categories: 6 | - 前端开发 7 | - JavaScript 8 | tags: 9 | - JavaScript 10 | --- 11 | 12 | # JavaScript 学习指南 \* 13 | 14 | \* 撰写中 15 | 16 | --- 17 | 18 | > 查看旧版 [JS Foundation(旧)](/frontend/javascript-foundation-legacy-version) 19 | 20 | --- 21 | 22 | 我自己目前在 JavaScript 本身上的学习可能已经累计超过 200~500 小时。 23 | (甚至还没进入核心层面,只能算略懂,甚至有一些理解偏差) 24 | 25 | ## 大致路线图 26 | 27 | 对于**学习 JavaScript 语言**来说,我认为合适的方式大致是: 28 | 29 | - 准备:预先理解最基本的编程思想 30 | - 入门:熟悉 JavaScript 基本语法,了解 JavaScript 的大致样貌 31 | - 熟悉:练习 JavaScript 常用内置对象的常用 API 用法 32 | - 实战:熟悉 JavaScript 能够进行的进行实际开发 33 | - 深入:了解 JavaScript 深层次的语言特性和原理 34 | 35 | ## JavaScript 知识体系结构图 36 | 37 | - **前置学习** 38 | - [前端开发入门指南](/note/frontend-development-cookbook) 39 | - **JavaScript** 40 | - [JavaScript 简介](/frontend/introduction-to-javascript) 41 | - [运行 JavaScript 代码的十几种方式](/frontend/how-to-run-javascript-code) 42 | - **JavaScript 语言核心** 43 | - [JavaScript 语言基础(2021)](/cs/javascript-language-basic) 44 | - [JavaScript 进阶指南](/frontend/javascript-advanced) 45 | - JavaScript 硬核指南(TODO) 46 | - [前端模块化](/frontend/javascript-modules) 47 | - _JavaScript 内置对象_ 48 | - [正则表达式](/frontend/javascript-regular-expression) 49 | - Promise(TODO) 50 | - [语法糖、操作符、关键字、特性](/frontend/syntactic-sugar-in-javascript) 51 | - **JavaScript 编程** 52 | - JavaScript DOM 编程指南(TODO) 53 | - 事件、代理事件 54 | - 本地存储 55 | - JavaScript 异步编程(TODO) 56 | - JavaScript 网络开发指南(TODO) 57 | - ajax、fetch、跨域、cookie 58 | - JavaScript 移动端开发指南(TODO) 59 | - TouchEvent 60 | - 传感器(陀螺仪等) 61 | - **Node.js 和 NPM** 62 | - [Node.js 入门指南](/frontend/nodejs-basic) 63 | - [npm 基本概念和使用](/frontend/introduction-to-npm) 64 | - [用 Proxy 进一步提高 npm 安装速度](/frontend/speeding-up-npm-install) 65 | - [使用 verdaccio 搭建私有 npm 仓库](/frontend/set-up-a-private-npm-registry-using-verdaccio) 66 | - Node.js 踩坑记录 67 | - 开发和发布一个 npm 包(TODO) 68 | -------------------------------------------------------------------------------- /docs/note/10.frontend/02.javascript/2.introduction-to-javascript.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 简介 3 | date: 2019-12-30 11:39:54 4 | permalink: /frontend/introduction-to-javascript 5 | categories: 6 | - 前端开发 7 | - JavaScript 8 | tags: 9 | - JavaScript 10 | --- 11 | 12 | # JavaScript 简介 13 | 14 | ## 什么是 JavaScript 15 | 16 | JavaScript(通常缩写为 JS)是一种解释型高级语言。 17 | 通常作为开发 Web 页面的脚本语言, 18 | 但是它也可以在非浏览器环境中使用,例如 Node.js。 19 | 20 | 广义的 JavaScript 包含三个部分: 21 | 22 | - `ES`:ECMAScript,核心标准 23 | - `DOM`:Document Object Model,文档对象模型 24 | - `BOM`: Browser Object Model,浏览器对象模型 25 | 26 | 狭义的 JavaScript 可以只指 `ECMAScript`, 27 | 可以简单理解为浏览器、Node 嵌入式等所有环境都必须支持的 JS 功能子集。 28 | (去掉了 `document`、`window` 等概念) 29 | 30 | [JavaScript 是图灵完备的](https://www.freecodecamp.org/news/javascript-is-turing-complete-explained-41a34287d263/) 31 | 32 | ## 什么是 ES6 33 | 34 | ES 就是 ECMAScript, 35 | ES2015/ES6 是 ES 的一个里程碑(大更新)版本, 36 | 其中 2015 表示年份,6 表示版本号, 37 | (目前最新的是 ES2019/ES10) 38 | ES6+ 是前端开发的基本语言。 39 | 40 | - ES6 相比 ES5: 41 | - 多了一些语法 42 | - 或需要被预编译成 ES5 以增加旧环境兼容性 43 | - 多了一些 API 44 | - 或需要 Polyfill 45 | - 多了一些数据结构和类型 46 | - 或可以被预转译 47 | - 部分特性无法被完美模拟(如 Proxy) 48 | 49 | * 兼容性 50 | - [ECMAScript 6 compatibility table - kangax](https://kangax.github.io/compat-table/) 51 | - [Can I use Arrow functions ?](https://caniuse.com/#search=Arrow%20functions) 52 | 53 | ## 为什么要学习 JavaScript 54 | 55 | - 如果你想编程入门 56 | - 如果你想魔改某些页面 57 | - 如果你想从事前端开发工作 58 | 59 | ## JS 概况/漫谈 60 | 61 | - [硬核前端(劝退篇)](/frontend/frontend-hardcore-overview) 62 | 63 | - [王垠对 JS 的评价](https://zhuanlan.zhihu.com/p/54821270) 64 | 65 | * [2019 年 JavaScript 明星项目](https://risingstars.js.org/2019/zh) 66 | * [2018 年 JavaScript 明星项目](https://risingstars.js.org/2018/zh) 67 | * [The State of JavaScript 2019](https://2019.stateofjs.com/zh/) 68 | 69 | - [为什么认为 Backbone 是现代前端框架的基石](https://zhuanlan.zhihu.com/p/30982369) 70 | - [[译文] 现代 js 框架存在的根本原因](https://juejin.im/post/5b111436e51d4506d06205fd) 71 | 72 | ## JavaScript 版本/方言/历史 73 | 74 | - [JavaScript: The First 20 Years](https://zenodo.org/record/3710954) 75 | - [The Weird History of JavaScript](https://www.youtube.com/watch?v=Sh6lK57Cuk4) 76 | - [JavaScript: How It's Made](https://www.youtube.com/watch?v=FSs_JYwnAdI) 77 | - [漫谈 JavaScript 方言与派系](https://www.blackglory.me/javascript-dialects-and-factions/) 78 | 79 | 在现代前端开发中, 80 | 开发时需要使用配套的解析工具, 81 | 发布前基本上都会预编译到 ES5。 82 | 83 | - **ECMAScript** 官方规范(from _Ecma TC39_) 84 | - **ES1~3**:1995 起,上古版本 85 | - **ES5**:(aka `ES3.1`)2009 起的版本 86 | - **ES6**:(aka `ES2015`)2015 年大更新的版本,带动了 JS 预编译生态,后续逐年小幅度更新 87 | - **Vanilla JavaScript**:民间称呼,指的就是标准/原生/不使用库的 JS,Vanilla 表示 Plain 或者 Pure 88 | - **JSON**: JavaScript Object Notation,JS 对象表示法,基于 JS 语法子集的数据格式 89 | - 类型系统 90 | - **TypeScript**:带类型检查的扩展集(from _Microsoft_) 91 | - **Flow**:比 TS 功能少一点的类型检查扩展集,现已式微(from _Facebook_) 92 | - 框架语言(基于 ES、TS 并含有扩展语法的 DSL/语法糖) 93 | - **JSX**:React 的 JS + HTML 混合语法 94 | - **Vue**:Vue 自己的(文件和 template)格式 95 | - **ClojureScript**:Clojure+JS 的函数式方言 96 | - 其他方言(现已式微的) 97 | - **ActionScript**:以 ES4 衍生发展成的旁支(用于 _Adobe_ Flash,但是 Flash 已死) 98 | - **CoffeeScript**:方言之一,简化了 JS 语法 99 | - **LiveScript**:CoffeeScript 的兄弟版本(JS 早期曾用名也是这个,但是不同的东西) 100 | -------------------------------------------------------------------------------- /docs/note/10.frontend/02.javascript/4.javascript-advanced.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JavaScript 进阶指南 * 3 | date: 2019-12-30 11:39:54 4 | permalink: /frontend/javascript-advanced 5 | categories: 6 | - 前端开发 7 | - JavaScript 8 | tags: 9 | - JavaScript 10 | --- 11 | 12 | # JavaScript 进阶指南 \* 13 | 14 | \* 撰写中 15 | 16 | ## 学习 JavaScript 进阶知识 17 | 18 | ### 概览 19 | 20 | - 耗时: 21 | - 深入 JS 语言特性和编程技巧,耗时大约 60~120 小时 22 | - 难点:略 23 | - 工具:略 24 | 25 | ### 学习路线 26 | 27 | - 前置学习 28 | - [JavaScript 语言基础(2021)](/cs/javascript-language-basic) 29 | - 学习 JavaScript 高级特性 30 | - 看书、看视频 ↓,掌握下文中的提到的 JS 进阶知识体系 31 | - 实战 32 | - 刷题 ↓ 33 | - 迷思 34 | - 什么是元编程 35 | - 什么是反射 36 | - 什么是运算符重载,JS 里能不能实现 37 | 38 | ## 资料 39 | 40 | ### 自学教材 41 | 42 | - 书籍 43 | - [你不知道的 JavaScript](https://book.douban.com/series/40642):小黄书,中卷 全部 44 | - [JavaScript 忍者秘籍](https://book.douban.com/subject/26638316/):忍者书,全部 45 | - [JavaScript 语言精粹](https://book.douban.com/subject/3590768/):蝴蝶书,全部 46 | - 视频 47 | - [The JavaScript Survival Guide](https://www.youtube.com/watch?v=9emXNzqCKyg) 48 | 14 分钟:JS 基本技巧和特性细节 49 | - [JavaScript Pro Tips - Code This, NOT That](https://www.youtube.com/watch?v=Mus_vwhTCq0) 50 | 12 分钟:JS 编码修养 51 | - [The Future of JavaScript - New Features and Disruptive Trends in 2020](https://www.youtube.com/watch?v=f0DrPLKf6Ro) 52 | 10 分钟:ES2020 新特性介绍 53 | - [JavaScript: Understanding the Weird Parts - The First 3.5 Hours](https://www.youtube.com/watch?v=Bv_5Zv5c-Ts) 54 | - 扩展阅读 55 | - [i=1 为什么(++i)+(++i)=6?](https://www.zhihu.com/question/347864795) 56 | 57 | ### 刷题教材 58 | 59 | 同样的道理,可能会有很多重复的题,选择性跳过,建立自己的知识体系 60 | 注意到纯 JS 和 DOM 编程的题可能会混在一起,可以考虑分开刷 61 | 62 | - 代码片段 63 | - [JavaScript - 30 seconds of code](https://www.30secondsofcode.org/js/p/1) 64 | - 在线刷题 65 | - [codewars](https://www.codewars.com/?language=javascript) 66 | - 别人整理的题目(按字典排序) 67 | - [JavaScript - FE-Interview-Questions](https://github.com/poetries/FE-Interview-Questions/blob/master/JavaScript.md) 68 | - [JavaScript - 前端硬核面试专题](https://github.com/biaochenxuying/blog/blob/master/interview/fe-interview.md#4-javascript):第四章(JS)、第五章(ES6+) 69 | - [JavaScript 开发者应懂的 33 个概念](https://github.com/stephentian/33-js-concepts):(可以先排除设计模式、算法的部分) 70 | - [JavaScript 进阶问题列表](https://github.com/lydiahallie/javascript-questions/blob/master/zh-CN/README-zh_CN.md) 71 | - [javaScript 问题 - FEGuide 前端指南](https://github.com/FEGuideTeam/FEGuide/tree/master/javascript%E9%97%AE%E9%A2%98) 72 | - [JS - 前端进阶之道](https://github.com/InterviewMap/CS-Interview-Knowledge-Map/blob/master/JS/JS-ch.md) 73 | - [JS 相关问题 - 前端工作面试问题](https://github.com/h5bp/Front-end-Developer-Interview-Questions/blob/master/src/translations/chinese/README.md#js-%E7%9B%B8%E5%85%B3%E9%97%AE%E9%A2%98) 74 | - [JS 进阶 - 前端每日一问](https://github.com/sanyuan0704/frontend_daily_question#js-%E8%BF%9B%E9%98%B6):JS 的部分 75 | - [搞搞 js - PersonalBlog Nealyang 全栈前端](https://github.com/Nealyang/PersonalBlog#%E6%90%9E%E6%90%9Ejs):JS 部分(语言本身相关的那些) 76 | - [深入系列目录 - 冴羽的博客](https://github.com/mqyqingfeng/Blog#%E6%B7%B1%E5%85%A5%E7%B3%BB%E5%88%97%E7%9B%AE%E5%BD%95) 77 | 78 | ## JavaScript 进阶知识体系 79 | 80 | ### JavaScript 进阶概念 81 | 82 | - 语言特性 83 | - 变量 84 | - 基本类型 vs 引用类型、按值传递 85 | - 类型转换、隐式类型转换(`toString`/`valueOf`) 86 | - 变量提升 87 | - 函数 88 | - `length`、`name`、`prototype` 89 | - `this`、`arguments` 90 | - 立即执行函数表达式(IIFE)、高阶函数 91 | - 闭包、作用域、`eval`、内存泄露 92 | - ES6:箭头函数、剩余参数、默认参数 93 | - 数组 94 | - Array-Like(如 `arguments` 等) 95 | - 对象 96 | - `prototype`、`constructor` 97 | - 原型链 98 | - ES6 对象 99 | - `Promise`、`Generator`、`async` 100 | - `Map`、`Set` 101 | - `Proxy` 102 | - Array-Like(如 `BigUint64Array` 等) 103 | - 正则表达式 104 | - 前端模块化 105 | - 执行原理 106 | - 短路计算 107 | - IEEE754 问题 108 | - EventLoop 109 | - 垃圾回收 110 | - 前瞻(2020) 111 | - ES 新特性(含草案) 112 | - 动态引入:`await import('lib')` 113 | - 可选链:`user?.shooping?.list` 114 | - Nullish Coalescing:`const animeTime = duration ?? 400` 115 | - BigInt 116 | - Node 117 | - Worker Threads 118 | - ES module support 119 | 120 | ### JavaScript 编码素养 121 | 122 | - 语言精粹/毒瘤 123 | - 多用 124 | - 分号、花括号 125 | - ES6 新特性(解构、模板字符串) 126 | - 静态检查器([ESLint](https://eslint.org/))、自动格式化([Prettier](https://prettier.io/)) 127 | - 少用 128 | - 显式全局变量、未定义变量、隐式 Falsy、`==` 129 | - `with`、`eval`、`label`、`switch`、`void` 130 | - `++`、`--` 131 | - 提高编码技巧 132 | - `console` API 133 | - 对象处理、数组处理 134 | - `async` 135 | - 手写系列 136 | - 对象:组合寄生继承 137 | - 数组:`map`/`filter`/`reducer` 的 Polyfill 138 | - 模拟实现 `new`/`bind`/`call`/`apply`/`instanceof` 139 | - `Promise` 140 | - `deepClone`、`deepFlatten` 141 | - 函数:`debounce`/`throttle` 142 | - 集合:`unique`/`union` 143 | - 事件:EventEmitter/EventBus 144 | -------------------------------------------------------------------------------- /docs/note/10.frontend/02.javascript/7.javascript-regular-expression.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 正则表达式 学习指南 3 | date: 2019-12-26 18:39:31 4 | permalink: /frontend/javascript-regular-expression 5 | categories: 6 | - 前端开发 7 | - JavaScript 8 | tags: 9 | - JavaScript 10 | - 正则表达式 11 | --- 12 | 13 | # 正则表达式 学习指南 14 | 15 | ## 正则表达式 简介 16 | 17 | ### 什么是 正则表达式 18 | 19 | > 正则表达式(英语:Regular Expression,常简写为 regex、regexp 或 RE),又称正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。 20 | 21 | 正则不仅在 JavaScript 中存在, 22 | 很多其他主流语言以及工具都支持正则, 23 | 例如: 24 | 25 | - [JS 中的 RegExp 对象](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp)、[python 中的 `re` 模块](https://docs.python.org/zh-cn/3/library/re.html) 26 | - Unix 中的 `sed` 命令、`grep` 命令的 `-E` 参数 27 | - 几乎所有代码编辑器的搜索功能:VS Code、Sublime Text、vim、IntelliJ IDEA 系列 28 | - [Chrome 正则搜索插件](https://chrome.google.com/webstore/detail/chrome-regex-search/bpelaihoicobbkgmhcbikncnpacdbknn) 29 | 30 | #### 正则表达式 概念分类 31 | 32 | - 转义字符 33 | - 位置匹配(边界,如单词边界、行开头) 34 | - 组合和量词 35 | - 正则中具有多种功能的字符们 36 | - `()`, `?`, `^`, `\`, `$` 37 | - 断言(边界,预测前后字符串) 38 | - flags(不同的检索策略,如是否忽略大小写) 39 | 40 | ### 为什么要用 正则表达式 41 | 42 | 展开说可以有更多具体的使用场景, 43 | (比如完成业务需求或在编辑器里模糊查询) 44 | 45 | 但总的来说只有一个原因: 46 | 47 | - 实现基于模式查询的自动处理 48 | 49 | 一个经典的正则例子,以千分位切割数字: 50 | 把 ((不是边界、且右边有(3\*n 个数字))的位置),变成逗号。 51 | 52 | ```javascript 53 | const toThousand = (str) => 54 | String(str).replace(/\B(?=(\d{3})+\b)/g, ','); 55 | 56 | toThousand(123456789); // => "123,456,789" 57 | ``` 58 | 59 | ## 学习 正则表达式 60 | 61 | ### 概览 62 | 63 | - 耗时:从入门到掌握需要大约一天 64 | - 难点:记住所有基本规则、断言、合理使用 65 | - 工具:JS 自带的 RegExp,所以任意浏览器 devtool 或 Node 即可 66 | 67 | ### 学习路线 68 | 69 | - 前置学习 70 | - [JavaScript 语言基础(2021)](/cs/javascript-language-basic) 71 | - 学习正则表达式 72 | - 使用 JS 练习所有正则规则 73 | - 了解:不同工具中的正则可能会有一些扩展规则 74 | - 实战 75 | - 在工作业务中使用正则完成代码需求 76 | - 在批量编辑代码时使用正则完成查找(比如 VS Code 中) 77 | - 在其他场景使用正则(如 `sed`、`grep`) 78 | - 进阶(正则迷你书) 79 | - 正则运行原理:非贪婪(惰性)、回溯和性能优化 80 | - NFA DFA 匹配器(回溯陷阱) 81 | - 正则运算符的优先级 82 | 83 | ## 资料 84 | 85 | ### 自学教材 86 | 87 | - 电子教程 88 | - [《JS 正则迷你书》](https://github.com/qdlaoyao/js-regex-mini-book) 89 | - [Learn Regex The Easy Way](https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md):中文版 90 | - 书籍 91 | - [JavaScript 高级程序设计](https://book.douban.com/subject/10546125/):(第三版)5.4 RegExp 类型 92 | - [JavaScript 忍者秘籍](https://book.douban.com/subject/26638316/):(第二版)第 10 章(正则) 93 | - 正则的细节 94 | - [正则表达式零宽断言详解](https://www.cnblogs.com/onepixel/articles/7717789.html) 95 | - [Unicode: flag "u" and class \p{...}](https://javascript.info/regexp-unicode) 96 | 97 | ### 在线正则解析(帮助理解) 98 | 99 | - [RegExr](https://regexr.com/):规则解析 100 | - [Regulex](https://jex.im/regulex/):可视化解析 101 | 102 | ### 文档 103 | 104 | - [正则表达式 - MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions) 105 | - [正则表达式 - javascript.info](https://zh.javascript.info/regular-expressions) 106 | 107 | ## 正则表达式 知识体系 108 | 109 | ### 正则基本概念 110 | 111 | (个人整理和分类,用语可能不太规范,但容易理解) 112 | 113 | - **正则基础规则** 114 | - 正则支持任意朴素字符 115 | - `hello world` 116 | - 正则支持子正则的平行拼接 117 | - `^h(a|e)?llo\sworld\b.*$` 118 | - **字符模式(匹配单个字符)** 119 | - **字符组** 120 | - `[abc]` a 或 b 或 c (匹配这些字符) 121 | - `[^abc]` 不是 a 或 b 或 c 的其他字符(排除这些字符) 122 | - `[a-z]` 匹配 a 到 z 123 | - `[g-zA-F1-5]` 匹配小写 g 到 z、大写 A 到 F、数字 1 到 5 124 | - **转义字符** 125 | - `.` 任意字符 126 | - `\s` 空格 127 | - `\S` 非空格 128 | - `\d` 数字 129 | - `\D` 非数字 130 | - `\w` 字符(字母+数字+下划线) 131 | - `\W` 非字符 132 | - `\t` tab 133 | - `\n` 换行 134 | - `\r` 回车 135 | - `\/` `/`(因为 JS 正则字面量写法以斜杠包裹,所以需要转义。其他具有功能的字符也同理,例如:`/c:\/\[path\]/` => `c:/[path]`) 136 | - **捕获和引用**(括号,可用于后续处理,如 replace) 137 | - **捕获组** `()` 138 | - `(hallo)` 匹配 hallo,且捕获括号内内容 139 | - (捕获组的捕获顺序,按左括号从左到右为 1234…) 140 | - **正则内引用** `\1` 141 | - `(ab),\1` 匹配 'ab,ab' 142 | - **结果引用**(replace 第二参数的特殊字符) 143 | - `$1` 按捕获顺序,例如:`'abcd'.replace(/(ab)/, '$1,') => 'ab,c'` 144 | - `$&` 匹配的整个子串 145 | - `` $` `` 匹配子串的左边文本(键盘左侧的反引号) 146 | - `$'` 匹配子串的右边文本(键盘右侧的引号) 147 | - `$$` 转义 `$` 148 | - **组合模式(正则串的单次组合)** 149 | - **或** `|` 150 | - `h(a|e)llo` 匹配 hallo 或 hello(切换匹配(并捕获)) 151 | - **量词**(左边的 a 可以是任意正则模式) 152 | - `a+` 匹配 'a、'aa'(至少一个) 153 | - `a*` 匹配 ''、'aaa'(零或多个) 154 | - `a?` 匹配 ''、'a'(零或一个) 155 | - `a{3}` 匹配 'aaa'(精确的 N 个) 156 | - `a{3,}` 匹配 'aaa' 到 'aaaaaaa...'(至少 N 个) 157 | - `a{3,6}` 匹配 'aaa' 到 'aaaaaa'(N 到 M 个) 158 | - **非贪婪(惰性)** 159 | - `a{3,6}?` 匹配 'aaa'(非贪婪:匹配到越少越好) 160 | - **位置模式(位置不是字符,不具有宽度)** 161 | - **转义字符** 162 | - `^` 行开头 163 | - `$` 行结尾 164 | - `\b` 单词边界 165 | - `\B` 非单词边界 166 | - **断言**(其中的 a 可以是任意子正则) 167 | - `(?=a)` Positive lookahead,右边匹配 168 | - `(?!a)` Negative lookahead,右边不匹配 169 | - `(?<=a)` Positive lookbehind,左边匹配 170 | - `(? ArrayLike | null` 181 | - `reg.test(str) => boolean` 182 | - String 183 | - `str.match(reg) => ArrayLike | null` 184 | - `str.matchAll(reg) => Iterator` 185 | - `str.replace(reg|str, str|fn) => string` 186 | - `str.search(reg) => index | -1` 187 | - `str.split(reg|str, limit?) => array` 188 | 189 | ```javascript 190 | // * -------------------------------- 构造正则 191 | 192 | // * 字面量 193 | var re1 = /foo*/g; 194 | 195 | // * 构造函数(以便支持动态生成) 196 | var re2 = RegExp('foo*', 'g'); 197 | 198 | re1 instanceof RegExp; // => true 199 | re2 instanceof RegExp; // => true 200 | 201 | typeof re1; // => "object" 202 | typeof re2; // => "object" 203 | 204 | // * ---------------- flag example: g and u 205 | 206 | '😄🤔'.match(/./gu); // =>  ["😄", "🤔"] 207 | 208 | // * -------------------------------- RegExp 209 | 210 | /(ba)r*/g.exec('barrrbar'); 211 | // => ["barrr", "ba", index: 0, input: "barrrbar", groups: undefined] 212 | 213 | /(ba)r*/g.test('barrrbar'); 214 | // => true 215 | 216 | // * -------------------------------- String 217 | 218 | // * ---------------- basic 219 | 220 | 'barrrbar'.match(/(ba)r*/g); 221 | // => ["barrr", "bar"] 222 | 223 | 'barrrbar'.match(/(ba)r*/); 224 | // => ["barrr", "ba", index: 0, input: "barrrbar", groups: undefined] 225 | 226 | 'barrrbar'.search(/(ba)r*/g); 227 | // => 0 (相当于支持正则的 indexOf) 228 | 229 | '2019/12-26'.split(/-|\//); 230 | // => ["2019", "12", "26"] 231 | 232 | // * ---------------- matchAll 233 | 234 | // * matchAll 返回结果是一个 Iterator 235 | 236 | [...'barrrbar'.matchAll(/(ba)r*/g)]; 237 | 238 | // => [ 239 | // ["barrr", "ba", index: 0, input: "barrrbar", groups: undefined], 240 | // ["bar", "ba", index: 5, input: "barrrbar", groups: undefined] 241 | // ] 242 | 243 | // * ---------------- replace 244 | 245 | 'barrrbar'.replace(/(ba)r*/g, '$1,'); 246 | // => "ba,ba," 247 | 248 | 'reg is not hard'.replace( 249 | /(is|are)\s?(not)?/, 250 | '$1 $2', 251 | ); 252 | // => "reg is not hard" 253 | 254 | 'reg is not hard'.replace(/(is|are)(\snot)?/, '$&'); 255 | // => "reg is not hard" 256 | 257 | 'reg_is_cool'.replace(/(is|are)/, '$`'); 258 | // => "reg_reg__cool" 259 | 260 | 'reg_is_cool'.replace(/(is|are)/, "$'"); 261 | // => "reg__cool_cool" 262 | 263 | // * ---------------- replace function 264 | 265 | function replacer(match, p1, p2, p3, offset, string) { 266 | // p1 is nondigits, p2 digits, and p3 non-alphanumerics 267 | return [p1, p2, p3].join(' - '); 268 | } 269 | var newString = 'abc12345#$*%'.replace( 270 | /([^\d]*)(\d*)([^\w]*)/, 271 | replacer, 272 | ); 273 | // => "abc - 12345 - #$*%" 274 | ``` 275 | 276 | ## 正则表达式 相关 277 | 278 | ### 关于断言的翻译 {#about-regex-assertion-translation} 279 | 280 | 关于断言的主流翻译,我个人认为非常垃圾, 281 | 我之前非常难理解断言的概念, 282 | 现在看来,应该是垃圾翻译造成的: 283 | 284 | - `Positive lookahead` => `零宽正向先行断言` 285 | - `Negative lookahead` => `零宽负向先行断言` 286 | - `Positive lookbehind` => `零宽负向先行断言` 287 | - `Negative lookbehind` => `零宽正向后行断言` 288 | 289 | 嗨,我的老伙计!您瞧瞧,这说的是人话吗? 290 | 291 | `Positive`/`Negative` 翻译成 正向/负向?上下文呢? 292 | 正向的意思是指字符串方向么? 293 | 294 | 实际上,这两个英文单词还有很多意思: 295 | 296 | - Positive:肯定的、确定的、阳性的 297 | - Negative:否定的、拒绝的、阴性的 298 | 299 | 根据正则的用途和实际的规则, 300 | 也就是 **找到**/**找不到**, 301 | 或者说 **应该匹配**/**不应该匹配**。 302 | 303 | 可以发现和 正向/负向 没有半毛钱关系, 304 | 实属垃圾翻译。 305 | 306 | `lookahead`/`lookbehind` => `先行`/`后行`,也可以改进。 307 | 308 | 什么叫先行后行?中文中的“先行”还可以这样用: 309 | 310 | > 茶会尚未结束,它就先行离开了。 311 | 312 | 所以断言里的 `lookhead` 是已经出现的、之前的字符串的意思吗? 313 | 恰恰相反,是指后面的字符串。 314 | 不良的翻译造成了理解的困惑。 315 | 316 | 实际上,英文中有这么一对词组: 317 | 318 | - look ahead:预测、向前看、计划未来 319 | - look behind:回顾、回头看 320 | 321 | 字符串的书写是从左到右的, 322 | 未来,也就是还未出现的,当前位置右边的字符串, 323 | 回顾,也就是已出现的,当前位置左边的字符串。 324 | 325 | 我见过的另一个翻译版本略微高明一点: 326 | 327 | - `零宽度正预测先行断言` 328 | - `零宽度负预测先行断言` 329 | - `零宽度正回顾后发断言` 330 | - `零宽度负回顾后发断言` 331 | 332 | 但是我觉得它也有一些问题: 333 | `正`/`负` 的传达的意思依然不够精确, 334 | `预测先行`/`回顾后发` 相当于翻译了两遍。 335 | (记不记得编码中的 DRY 原则?) 336 | 337 | 所以综上,我个人把它翻译为: 338 | 339 | - **`Positive lookahead` => `预测匹配断言`** 340 | - **`Negative lookahead` => `预测不匹配断言`** 341 | - **`Positive lookbehind` => `回顾匹配断言`** 342 | - **`Negative lookbehind` => `回顾不匹配断言`** 343 | 344 | `预测匹配断言`: 345 | 我来预测现在这个位置之后出现的字符串应该符合某模式, 346 | 预测成功了!那么当前位置是符合正则的。 347 | 348 | 或者在理解上更直白: 349 | 350 | - 右边匹配 351 | - 右边不匹配 352 | - 左边匹配 353 | - 左边不匹配 354 | 355 | `=` 就是匹配,`!` 就是不匹配, 356 | 默认编码顺序是右边,用 `<` 左尖括号来表示左边。 357 | 358 | 这样简单的规则总结不仅更符合编码直觉, 359 | 和断言语法中的助记符也非常对应。 360 | 361 | 我的翻译在“信达雅”上,“雅”先不谈, 362 | 但是“信达”程度应该比什么“零宽正向先行断言”高多了, 363 | 364 | 但是垃圾翻译已经先入为主并普及了,我也没办法, 365 | 那么以后沟通的时候索性直接用英文原文得了。 366 | 367 | (再次说明了看懂一手英文的重要性,以及垃圾二手资料的危害性) 368 | -------------------------------------------------------------------------------- /docs/note/10.frontend/03.npm/1.introduction-to-npm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: npm 基本概念和使用 3 | date: 2019-11-10 22:20:59 4 | permalink: /frontend/introduction-to-npm 5 | categories: 6 | - 前端开发 7 | - Node.js 8 | tags: 9 | - Node.js 10 | - npm 11 | --- 12 | 13 | # npm 基本概念和使用 14 | 15 | ## 概览 16 | 17 | - [npm-package.json | npm Documentation](https://docs.npmjs.com/files/package.json) 18 | 19 | 简单开发只需安装一个版本的 `node` 即可, 20 | 多项目开发环境可以利用 `nvm` 进行版本切换。 21 | 22 | 提高 npm 装包的速度,在国内可以使用淘宝源, 23 | 安装 `nrm` 接着 `nrm use taobao` 自动修改配置文件, 24 | 即可达到提速效果,之后像往常一样直接使用 npm。 25 | 26 | ### 常用工具 27 | 28 | - node 29 | - 现代化前端开发基本环境,可在命令行中运行 JS 代码 30 | - Node 偶数版是长期支持版,进度参考官网 31 | - `brew install node`,不过推荐使用 `n` 来安装 node 和做版本控制 32 | - npm 33 | - Node Package Manager,包管理器,node 装好后附带的工具 34 | - `npm i -g npm` 是升级 npm 自己 35 | - n 36 | - Node Version Manager,Node 版本(环境)切换工具 37 | - `brew install n` 38 | - nrm 39 | - Npm Registry Manager,npm 仓库切换器 40 | - `npm i -g nrm --registry=https://registry.npmmirror.com` 41 | - pnpm 42 | - 可代替 npm 的管理器,更快、省空间、monorepo 支持方便 43 | - `npm i -g pnpm` 44 | 45 | ### 基本命令 46 | 47 | ```bash 48 | # 查看版本 49 | node -v 50 | npm -v 51 | pnpm -v 52 | 53 | # nvm 54 | n ls 55 | sudo n lts 56 | 57 | # nrm 58 | nrm ls 59 | nrm use taobao 60 | 61 | # npm 62 | npm i -g typescript # 全局安装 63 | npm init # 新建一个项目 64 | npm i @types/node # 在项目中安装一个包 65 | npm un @types/node # 在项目中卸载一个包 66 | ``` 67 | 68 | ## npm 相关概念 69 | 70 | - 同义词 71 | - registry、仓库、源 72 | - package、包 73 | 74 | * [cnpm](https://github.com/cnpm) 是由淘宝开发的一套 npm 生态,包含服务端、客户端、npm 镜像(可视为已配置好的服务端),等等一系列工具和服务。 75 | * [package.json](https://github.com/stereobooster/package.json) 是一个包含 npm package 相应信息的配置文件。 76 | 77 | ### 服务端 78 | 79 | `verdaccio`、`sinopia` 等私有库工具都是属于服务端。 80 | 也有其他 SaaS 形式的服务(比如 [Nexus Repository Manager](https://www.sonatype.com/nexus-repository-sonatype)、[GitHub Package Registry](https://help.github.com/en/articles/configuring-npm-for-use-with-github-package-registry))。 81 | 82 | - [搭建私有 npm 仓库](/frontend/set-up-a-private-npm-registry-using-verdaccio) 83 | 84 | ### 客户端 85 | 86 | - [npm](https://docs.npmjs.com/about-npm/):Node.js 默认的包管理器。 87 | - [pnpm](https://pnpm.io/):可代替 npm,更快、省空间、monorepo 支持方便 88 | 89 | 客户端基本使用方式: 90 | 91 | - `npm i the-answer` / `npm un the-answer` 92 | - `pnpm i the-answer` / `pnpm un the-answer` (保持一致) 93 | 94 | ### registry 95 | 96 | 源、仓库,存放众多开发者所开发的 package 的地方。 97 | 98 | 很多公开源都只是官方 npm 的镜像, 99 | 定期自动同步(只读),并且拒绝接收 package 发布。 100 | 101 | - 官方仓库:https://registry.npmjs.org/ 102 | - 淘宝源:https://registry.npm.taobao.org/ 103 | 104 | 当我们搭建了私有仓库之后,也就成为了一个可供我们访问的源, 105 | 只需要在客户端配置好地址即可。 106 | 107 | ### registry 的切换方式 108 | 109 | 上文提到的三个客户端都兼容 npm 的配置方式。 110 | 那么下面的例子只列举 npm 的方式, 111 | 也可以将命令中的 npm 替换成 pnpm 查看效果。 112 | 113 | 仓库的切换有以下几种方式。 114 | 115 | #### 通过参数 116 | 117 | 只需要在命令最后加 `--registry=${url}` 参数即可,例如: 118 | `npm i the-answer --registry=https://registry.npm.taobao.org/` 119 | 120 | #### 通过 config 121 | 122 | npm 自带的命令 `config set registry ${url}`,例如: 123 | `npm config set registry https://registry.npm.taobao.org/` 124 | 这个方式避免了每次输相关命令都需要敲入参数。 125 | 输入 `config --help` 看到 config 的命令有 `set, get, delete, list` 等。 126 | 127 | #### 通过 nrm 128 | 129 | config 能够保存配置到全局,但是在切换不同仓库的时候依然过于繁琐。 130 | 有一个工具简化这个过程,就是 [nrm](https://github.com/Pana/nrm)。 131 | 132 | nrm 是 npm registry manager 的缩写,顾名思义,也就是仓库源的管理工具。 133 | 有 `add、del、ls、use、current` 等命令。 134 | 并且自带了一些常用的 npm 源清单。 135 | 136 | 比如可以执行 `nrm use taobao`、`nrm use npm` 在淘宝源和官方仓库之间快速切换。 137 | 138 | 例如使用自己搭建的本地私有仓库: 139 | 140 | ``` 141 | nrm add localnpm http://localhost:4873/ 142 | nrm use localnpm 143 | ``` 144 | -------------------------------------------------------------------------------- /docs/note/10.frontend/03.npm/2.speeding-up-npm-install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 用 Proxy 进一步提高 npm 安装速度 3 | date: 2019-11-10 22:20:59 4 | permalink: /frontend/speeding-up-npm-install 5 | categories: 6 | - 前端开发 7 | - Node.js 8 | tags: 9 | - npm 10 | - 命令行 11 | --- 12 | 13 | # 用 Proxy 进一步提高 npm 安装速度 14 | 15 | ## 碰到的问题 16 | 17 | 在前一篇 [Node 概览](/frontend/introduction-to-npm) 中我们提到: 18 | 可以使用换源的方式提高 npm 的安装速度, 19 | `nrm use taobao` 已经足够快。 20 | 21 | 但在安装一些包的时候,还是会表现出假死状态或失败报错。 22 | 例如安装 `node-sass`、`cypress`、`puppeteer` 等。 23 | (用 npm 或 pnpm 或其他工具都有这个问题) 24 | 25 | ## 原因 26 | 27 | 这是网络原因,因为这些包需要从 npm 以外的地址下载数据。 28 | 所以只有 npm 换源起不到作用。 29 | 30 | **node-sass** 31 | 32 | ```bash 33 | $ npm i --save-dev node-sass 34 | ... 35 | > node-sass@4.13.1 install /Users/lc/0Work/temp/test/node_modules/node-sass 36 | > node scripts/install.js 37 | 38 | Downloading binary from https://github.com/sass/node-sass/releases/download/v4.13.1/darwin-x64-79_binding.node 39 | ``` 40 | 41 | **cypress** 42 | 43 | ```bash 44 | $ npm i --save-dev cypress 45 | ... 46 | > cypress@4.3.0 postinstall /Users/lc/0Work/temp/test/node_modules/cypress 47 | > node index.js --exec install 48 | 49 | Installing Cypress (version: 4.3.0) 50 | 51 | ⠧ Downloading Cypress 52 | Unzipping Cypress 53 | Finishing Installation 54 | ``` 55 | 56 | **puppeteer** 57 | 58 | ```bash 59 | $ npm i --save-dev puppeteer 60 | ... 61 | > puppeteer@2.1.1 install /Users/lc/0Work/temp/test/node_modules/puppeteer 62 | > node install.js 63 | 64 | Downloading Chromium r722234 - 116.4 Mb [ ] 1% 536.9s 65 | ``` 66 | 67 | 在这些包的实际文件中, 68 | 也果然能够找到关于下载链接或代理的代码。 69 | 70 | **node-sass**: `node_modules/node-sass/lib/extensions.js` 71 | 72 | ```js 73 | function getBinaryUrl() { 74 | var site = 75 | getArgument('--sass-binary-site') || 76 | process.env.SASS_BINARY_SITE || 77 | process.env.npm_config_sass_binary_site || 78 | (pkg.nodeSassConfig && pkg.nodeSassConfig.binarySite) || 79 | 'https://github.com/sass/node-sass/releases/download'; 80 | 81 | return [site, 'v' + pkg.version, getBinaryName()].join( 82 | '/', 83 | ); 84 | } 85 | ``` 86 | 87 | **cypress**: `node_modules/cypress/lib/tasks/download.js` 88 | 89 | ```js 90 | var defaultBaseUrl = 'https://download.cypress.io/'; 91 | 92 | var getProxyUrl = function getProxyUrl() { 93 | return ( 94 | process.env.HTTPS_PROXY || 95 | process.env.https_proxy || 96 | process.env.npm_config_https_proxy || 97 | process.env.HTTP_PROXY || 98 | process.env.http_proxy || 99 | process.env.npm_config_proxy || 100 | null 101 | ); 102 | }; 103 | ``` 104 | 105 | **puppeteer**: `node_modules/puppeteer/lib/BrowserFetcher.js` 106 | 107 | ```js 108 | const DEFAULT_DOWNLOAD_HOST = 109 | 'https://storage.googleapis.com'; 110 | 111 | const supportedPlatforms = [ 112 | 'mac', 113 | 'linux', 114 | 'win32', 115 | 'win64', 116 | ]; 117 | const downloadURLs = { 118 | linux: 119 | '%s/chromium-browser-snapshots/Linux_x64/%d/%s.zip', 120 | mac: '%s/chromium-browser-snapshots/Mac/%d/%s.zip', 121 | win32: '%s/chromium-browser-snapshots/Win/%d/%s.zip', 122 | win64: '%s/chromium-browser-snapshots/Win_x64/%d/%s.zip', 123 | }; 124 | ``` 125 | 126 | 那么如果环境访问外网太慢或无法访问外网, 127 | 显然就会导致安装太慢或失败。 128 | 129 | ## 解决方法 130 | 131 | 有几个解决方法: 132 | 133 | 一是添加 `--ignore-scripts` 直接无视额外安装脚本, 134 | 例如:`npm i --save-dev node-sass --ignore-scripts` 135 | 136 | 二是使用**对应的镜像源**参数, 137 | 例如:`npm i --save-dev node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/` 138 | 139 | 这也适用于离线安装的情况,比如指向企业的内网镜像库。 140 | 141 | ## 代理的方法 142 | 143 | 而个人开发的万金油方法,是使用代理连接到高速服务器, 144 | (也可以指向企业的内网镜像库,实现离线安装) 145 | 146 | (以下内容基于 mac,windows 的命令可能不同但原理类似) 147 | 在终端中执行: 148 | 149 | ```bash 150 | export http_proxy="http://127.0.0.1:1080" 151 | ``` 152 | 153 | 其中的 `http://127.0.0.1:1080` 是我们配置的一个内网 proxy, 154 | 直接将所有请求转发到(公司的)高速服务器。 155 | (关于 proxy 的配置方式这里不详细说明。) 156 | 157 | 可以在 `~/.zshrc` 里做更详细的处理, 158 | 并把代理封装成两个函数作为快捷开关。 159 | (`bash` 或 `fish` 等其他 `shell` 类似) 160 | 161 | ```bash 162 | export no_proxy=localhost,127.0.0.1,mysite.com # 白名单 163 | 164 | function proxy() { 165 | export http_proxy="http://127.0.0.1:1080" # 改成你自己的地址 166 | export https_proxy="http://127.0.0.1:1080" # 改成你自己的地址 167 | echo "HTTP Proxy on" 168 | } 169 | 170 | function unproxy() { 171 | unset http_proxy https_proxy # 取消 proxy 172 | echo "HTTP Proxy off" 173 | } 174 | 175 | proxy # 可以加入这一行实现打开终端直接开启 proxy 176 | ``` 177 | 178 | 这样就生成了 `proxy`、`unproxy` 两个开关代理的方法。 179 | 然后打开新的终端,再尝试安装: 180 | 181 | ```bash 182 | # cd temp/test/ 183 | # proxy 184 | npm i --save-dev puppeteer 185 | ``` 186 | 187 | 此时外部文件的下载已经通过高速代理,所以不会再卡住安装。 188 | 189 | ```bash 190 | Downloading Chromium r722234 - 116.4 Mb [====== ] 28% 19.7s 191 | ``` 192 | -------------------------------------------------------------------------------- /docs/note/10.frontend/03.npm/3.set-up-a-private-npm-registry-using-verdaccio.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 使用 verdaccio 搭建私有 npm 仓库 3 | date: 2019-11-10 22:20:59 4 | permalink: /frontend/set-up-a-private-npm-registry-using-verdaccio 5 | categories: 6 | - 前端开发 7 | - Node.js 8 | - 前端工具 9 | tags: 10 | - Node.js 11 | - npm 12 | - verdaccio 13 | --- 14 | 15 | # 使用 verdaccio 搭建私有 npm 仓库 16 | 17 | 私有仓库可用于包的开发和发布测试。 18 | 或作为镜像仓库缓存离线使用。 19 | 20 | ## 背景 21 | 22 | ### 基本需求分析 23 | 24 | 私有的 npm 仓库是实现不同项目的代码库共享的方式之一, 25 | 基本需求依次为: 26 | 27 | - 私有仓库 28 | - 可正常使用 npm 的功能 29 | - 小团队使用,避免太过复杂的配置过程 30 | - 私有权限管理 31 | 32 | ### 可选方案 33 | 34 | 经初步调研,有几款工具可以覆盖上述需求。 35 | 36 | - [verdaccio](https://github.com/verdaccio/verdaccio) 37 | - [sinopia](https://github.com/rlidwka/sinopia) 38 | - [cnpm(server)](https://github.com/cnpm/cnpmjs.org) 39 | 40 | cnpm 的实现 [略显复杂](https://cnpmjs.org/),可能不适用于轻度使用; 41 | sinopia 基本已经不再维护(3 years ago); 42 | verdaccio fork 于 sinopia,并且在持续更新。 43 | 44 | 于是对于私有仓库,我们可以尝试 verdaccio。 45 | 46 | 有一些好的特性,不过由于其轻量级的特性,也会有一些不足之处。 47 | 48 | - **Pro** 49 | - 配置简单可控,文档和示例丰富 50 | - 使用本地文件缓存代替 sql,无需配置存储 51 | - 私有的发布访问 52 | - 简单的权限系统 53 | - 图形化管理界面 54 | - 可以同时使用多个源地址 55 | - **Con** 56 | - 一些附加功能不太成熟(比如权限管理之于大型团队) 57 | - 文档中文化程度一般。 58 | 59 | 综合来说,verdaccio 比较适合小团队或个人。 60 | 61 | ### 相关文档 62 | 63 | - [Installation · Verdaccio](https://verdaccio.org/docs/zh-CN/installation) 64 | - [npm-publish | npm Documentation](https://docs.npmjs.com/cli/publish) 65 | 66 | ## 配置 verdaccio 67 | 68 | ### 搭建和配置 69 | 70 | `verdaccio` 虽然是一个私有仓库搭建工具,但本身也是一个基于 `npm` 的包。 71 | 所以需要预先安装 `node` 和 `npm`,接着执行: 72 | 73 | ```shell 74 | # 终端 75 | npm i -g verdaccio # 安装 76 | verdaccio # 启动 verdaccio 77 | ``` 78 | 79 | 可以看到 log 信息: 80 | 81 | ```shell 82 | warn --- config file - /Users/lc/.config/verdaccio/config.yaml 83 | warn --- Plugin successfully loaded: htpasswd 84 | warn --- Plugin successfully loaded: audit 85 | warn --- http address - http://localhost:4873/ - verdaccio/3.11.5 86 | ``` 87 | 88 | 说明已经启动成功,可以看到仓库的默认地址是 `http://localhost:4873/` 89 | 配置文件在 `~/.config/verdaccio/config.yaml` 90 | 并且在浏览器中访问 ,可以看到一个图形化管理界面。 91 | verdaccio 可以设置多个源,我们加入淘宝源。 92 | (也可以直接删掉 npmjs 相应的行,只使用淘宝源,以提高响应速度。) 93 | 94 | ```yaml 95 | # config.yaml 96 | uplinks: 97 | npmjs: 98 | url: https://registry.npmjs.org/ 99 | # 其他设置 ... 100 | taobao: 101 | url: https://registry.npm.taobao.org/ 102 | # 其他设置 ... 103 | # 其他设置 ... 104 | packages: 105 | '@*/*': 106 | proxy: 107 | - npmjs 108 | - taobao 109 | # 其他设置 ... 110 | '**': 111 | proxy: 112 | - npmjs 113 | - taobao 114 | # 其他设置 ... 115 | ``` 116 | 117 | 设置完成后,保存并重启命令行中的 verdaccio。 118 | 保持 verdaccio 的运行状态,打开新的终端窗口备用。 119 | 120 | ### set registry 121 | 122 | 我们先将 npm registry 改为这个地址: 123 | 124 | ```shell 125 | # npm config 126 | npm config set registry http://localhost:4873/ 127 | npm config get registry # -> http://localhost:4873/ 128 | 129 | # 或 nrm 130 | nrm add localnpm http://localhost:4873/ 131 | nrm use localnpm 132 | ``` 133 | 134 | ### npm install 135 | 136 | 测试对于现有包的安装是否正常,建立一个空项目,安装 `the-answer` 这个包。 137 | 138 | ```shell 139 | mkdir test-localnpm 140 | cd test-localnpm 141 | npm init -y 142 | npm i the-answer # 安装 the-answer 143 | ``` 144 | 145 | 回到运行 verdaccio 的终端窗口可以看到一下内容, 146 | 说明 verdaccio 从多个源获取包信息,并传回 npm 客户端。 147 | 148 | ```shell 149 | http --> 200, req: 'GET https://registry.npm.taobao.org/the-answer' (streaming) 150 | http --> 200, req: 'GET https://registry.npm.taobao.org/the-answer', bytes: 0/2632 151 | http --> 200, req: 'GET https://registry.npmjs.org/the-answer' (streaming) 152 | http --> 200, req: 'GET https://registry.npmjs.org/the-answer', bytes: 0/2661 153 | http <-- 200, user: null(127.0.0.1), req: 'GET /the-answer', bytes: 0/1122 154 | http <-- 200, user: null(127.0.0.1), req: 'GET /the-answer', bytes: 0/1122 155 | ``` 156 | 157 | 而重新安装或全新安装的 log 则会变成: 158 | 159 | ```shell 160 | http <-- 304, user: null(127.0.0.1), req: 'GET /the-answer', bytes: 0/0 161 | http <-- 304, user: null(127.0.0.1), req: 'GET /the-answer', bytes: 0/0 162 | ``` 163 | 164 | ```shell 165 | http --> 304, req: 'GET https://registry.npm.taobao.org/the-answer' (streaming) 166 | http --> 304, req: 'GET https://registry.npm.taobao.org/the-answer', bytes: 0/0 167 | http --> 304, req: 'GET https://registry.npmjs.org/the-answer' (streaming) 168 | http --> 304, req: 'GET https://registry.npmjs.org/the-answer', bytes: 0/0 169 | http <-- 200, user: null(127.0.0.1), req: 'GET /the-answer', bytes: 0/1122 170 | http <-- 200, user: null(127.0.0.1), req: 'GET /the-answer', bytes: 0/1122 171 | ``` 172 | 173 | 一些地方的 http status 从 200 变成了 304, 174 | 表示有缓存功能的存在,不会每次都重新从远端仓库下载包代码。 175 | 尝试在代码中调用,可以发现 `the-answer` 这个包能够正常工作。 176 | 177 | ```javascript 178 | // .js 179 | const theAnswer = require('the-answer'); 180 | console.log(theAnswer); // -> 42 181 | ``` 182 | 183 | ### 包的发布 184 | 185 | 具体流程和 npm 官方一致。 186 | (只不过现在仓库地址指向我们建立的私有仓库,可以更自由地进行实验。) 187 | 188 | 下面简单重现一下使用步骤。 189 | (详细步骤可参考[这篇文章](https://www.jianshu.com/p/36d3e0e00157)) 190 | 191 | #### 开发一个 package 192 | 193 | 建立一个新的目录用以开发一个新的 package。 194 | 195 | ```bash 196 | mkdir test-lib-local 197 | cd test-lib-local 198 | npm init -y 199 | ``` 200 | 201 | 可以看到 `package.json` 中默认有 `"main": "index.js"`, 202 | 表示 cjs 规范中的文件入口。 203 | 那么(新建这个文件并)添加简单代码: 204 | 205 | ```javascript 206 | // index.js 207 | module.exports = 'check1234'; 208 | ``` 209 | 210 | #### 发布这个 package 211 | 212 | 执行 `npm adduser`(或 alias `npm login`)登录, 213 | 执行 `npm publish` 发布。 214 | 如果控制台看到以下信息,则说明发布成功。 215 | 216 | ```shell 217 | npm notice 218 | + test-lib-local@1.0.0 219 | ``` 220 | 221 | #### 调用这个 package 222 | 223 | 参考之前的章节,建立新的项目、链接到本地仓库,并安装我们新发布的包: 224 | `npm i test-lib-local` 225 | 测试安装是否正常: 226 | 227 | ```javascript 228 | // .js 229 | const lib = require('test-lib-local'); 230 | console.log(lib); // -> 'check1234' 231 | ``` 232 | 233 | 此时可以切换回官方仓库看看,再进行安装应该是不成功的, 234 | 因为我们的包发布在私有仓库中,并不是在官方仓库中。 235 | 236 | ### 权限管理 237 | 238 | verdaccio 的权限管理(以及注册登录等等)功能目前还是比简单的。 239 | 并且不支持用户分组,可配置程度相比 cnpm 要弱。 240 | 也没有设计接口,只能通过修改配置文件并重启程序的方式刷新。 241 | 242 | ```yaml 243 | packages: 244 | '@my-custom-lib/*': 245 | access: username1 246 | publish: username1 247 | # 其他设置 ... 248 | '**': 249 | access: $all 250 | publish: $authenticated 251 | # 其他设置 ... 252 | ``` 253 | -------------------------------------------------------------------------------- /docs/note/10.frontend/04.react/1.react-hooks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: React Hooks 学习指南 3 | date: 2019-11-17 13:17:17 4 | permalink: /frontend/react-hooks 5 | categories: 6 | - 前端开发 7 | - 前端工具 8 | tags: 9 | - react 10 | --- 11 | 12 | # React Hooks 学习指南 13 | 14 | ## Hooks 简介 15 | 16 | ### 什么是 React Hooks 17 | 18 | > Hooks 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 19 | 20 | 换句话说:只用函数 + Hooks 来完成组件编写。 21 | 22 | Hooks 隐藏了 Class 写法中生命周期的概念, 23 | 或者说 React 自己尽量帮你处理了生命周期。 24 | 25 | ### 为什么要用 Hooks 26 | 27 | 如果你喜欢写 FP 而不是 OOP 风格的代码, 28 | 那么你可能早就开始用函数来写 Presentational Components 了。 29 | 30 | 但是函数组件有自己的局限性, 31 | 而 Hooks 突破了函数组件的局限性, 32 | 实现了一些 Class 组件才有的功能。 33 | 34 | ## 学习 Hooks 35 | 36 | ### 概览 37 | 38 | - 耗时:从入门到熟悉需要大约 10~20 小时(个人估计) 39 | - 难点: 40 | - 理解 FP 范式(并知道 Hooks 并不是纯 FP) 41 | - 理解 JS 执行原理 42 | - 探索最佳实践 43 | - 工具: 44 | - [react@16.8+](https://www.npmjs.com/package/react) 45 | - `webpack/parcel/cli` 46 | 47 | ### 学习路线 48 | 49 | - 前置学习 50 | - 理解 functional programming 51 | - side effect 52 | - [JavaScript 进阶指南](/frontend/javascript-advanced) 53 | - 了解 React 基本概念 54 | - 理解 展示组件、容器组件 的区别 55 | - 学习 Context 的特性 56 | - 学习 Hooks 57 | - 练习所有 React 自带的基本 Hooks API 58 | - 结合 TypeScript 59 | - 了解下 react-use(社区 Hooks) 60 | - 对比 Hooks 和 Class 写法的异同 61 | - 实战 62 | - 敲点小型应用 Demo 63 | - 结合 redux/rxjs 64 | - 进阶 65 | - 编写自己的 custom hooks 66 | - 阅读 Hooks 相关源码 67 | - 迷思 68 | - useEffect 的作用和运用 69 | - 探索最佳实践 70 | 71 | ## 资料 72 | 73 | ### 我的学习代码 74 | 75 | - [React - Learn By Doing](https://github.com/seognil-study/learn-by-doing/tree/master/react) 76 | 77 | ### 自学教材 78 | 79 | - [Hooks API 索引](https://zh-hans.reactjs.org/docs/hooks-reference.html) 80 | - [How to useContext in React? - RWieruch](https://www.robinwieruch.de/react-usecontext-hook) 81 | - [【译】什么时候使用 useMemo 和 useCallback](https://jancat.github.io/post/2019/translation-usememo-and-usecallback/) 82 | - [如何錯誤地使用 React hooks useCallback 來保存相同的 function instance](https://medium.com/@as790726/%E5%A6%82%E4%BD%95%E9%8C%AF%E8%AA%A4%E5%9C%B0%E4%BD%BF%E7%94%A8-react-hooks-usecallback-%E4%BE%86%E4%BF%9D%E5%AD%98%E7%9B%B8%E5%90%8C%E7%9A%84-function-instance-7744984bb0a6) 83 | 84 | ### 实战 85 | 86 | - [示例 - React](https://zh-hans.reactjs.org/community/examples.html) 87 | - [react-use](https://github.com/streamich/react-use) 88 | 89 | ### 进阶 90 | 91 | - [React Hooks in TypeScript](https://medium.com/@jrwebdev/react-hooks-in-typescript-88fce7001d0d) 92 | - [useEffect 完整指南](https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/) 93 | - [useEffect vs. useLayoutEffect in plain, approachable language](https://blog.logrocket.com/useeffect-vs-uselayouteffect/) 94 | - [精读《React Hooks 最佳实践》](https://zhuanlan.zhihu.com/p/81752821) 95 | - [精读《怎么用 React Hooks 造轮子》](https://github.com/dt-fe/weekly/blob/v2/080.%E7%B2%BE%E8%AF%BB%E3%80%8A%E6%80%8E%E4%B9%88%E7%94%A8%20React%20Hooks%20%E9%80%A0%E8%BD%AE%E5%AD%90%E3%80%8B.md) 96 | 97 | ### 扩展阅读 98 | 99 | - [V8 将为 React hooks 改进数组解构的性能](https://zhuanlan.zhihu.com/p/49077183) 100 | 101 | ## Hooks 知识体系 102 | 103 | ### Hooks 主要概念 104 | 105 | Hooks 主要是 `useXXX` 系列 API, 106 | 以及实现 Hooks 机制的 React 内部代码(resolveDispatcher 等)。 107 | 108 | - 常用 API 109 | - useContext 110 | - useState 111 | - useReducer 112 | - useRef 113 | - useEffect 114 | - useLayoutEffect 115 | - useCallback 116 | - useMemo 117 | 118 | 另外社区中还衍生出了更多 API:[react-use](https://github.com/streamich/react-use) 119 | 120 | ## Hooks 典型代码 121 | 122 | ### Hooks 大致用法 123 | 124 | - useState 125 | ```javascript 126 | const Comp = () => { 127 | const [state, setState] = useState(initialState) 128 | const handler = (e) => setState(newState || prevState => nextState) 129 | return
{state.myKey}
130 | } 131 | ``` 132 | - useReducer 133 | ```javascript 134 | const Comp = () => { 135 | const [state, dispatch] = useReducer( 136 | reducer, 137 | initialState, 138 | ); 139 | return ( 140 |
dispatch(action)}> 141 | {state.myKey} 142 |
143 | ); 144 | }; 145 | ``` 146 | - useCallback 147 | ```javascript 148 | const Comp = () => { 149 | const sameFn = useCallback(fn, [byDeps]); 150 | return
sameFn()}>
; 151 | }; 152 | ``` 153 | - useMemo 154 | ```javascript 155 | const Comp = () => { 156 | const sameResult = useMemo(fn, [byDeps]); 157 | return
{sameResult}
; 158 | }; 159 | ``` 160 | - useContext 161 | ```javascript 162 | const MyContext = createContext(null); 163 | const Comp = () => { 164 | const color = useContext(MyContext); 165 | return

Hello World

; 166 | }; 167 | const App = () => ( 168 | 169 | 170 | 171 | ); 172 | ``` 173 | - useRef 174 | ```javascript 175 | const Comp = () => { 176 | const refer = useRef(null); 177 | return ( 178 |
refer.current.innerHTML} 181 | >
182 | ); 183 | }; 184 | ``` 185 | - useEffect 186 | ```javascript 187 | const Comp = () => { 188 | const sideEffectFn = () => { 189 | myLogic(); 190 | return cancelSideEffectFn(); 191 | }; 192 | useEffect(sideEffectFn, [byDeps]); 193 | return
; 194 | }; 195 | ``` 196 | - useLayoutEffect 197 | ```javascript 198 | const Comp = () => { 199 | const sideEffectFn = () => { 200 | myDOMLogic(); 201 | return cancelSideEffectFn(); 202 | }; 203 | useLayoutEffect(sideEffectFn, [byDeps]); 204 | return
; 205 | }; 206 | ``` 207 | - useImperativeHandle 208 | ```javascript 209 | const ChildInput = forwardRef((props, parentRef) => { 210 | const realRef = useRef(null); 211 | useImperativeHandle(parentRef, () => realRef.current); 212 | return ( 213 | 214 | ); 215 | }); 216 | ``` 217 | 218 | ## Hooks 相关 219 | 220 | ### 使用上的注意点 221 | 222 | - 函数组件,在函数体中使用 Hooks API。 223 | - 为了表现出清晰的逻辑,Hooks 最好在函数代码的顶层结构中使用。 224 | 225 | ### Hooks 大致原理 226 | 227 | > 代码没有黑魔法 228 | 229 | 以 useState 为例,直接追踪代码关系(删减了部分细节代码) 230 | 231 | ```javascript 232 | // in 'react' 233 | function useState(initialState) { 234 | var dispatcher = resolveDispatcher(); 235 | return dispatcher.useState(initialState); 236 | } 237 | 238 | function resolveDispatcher() { 239 | return ReactCurrentDispatcher.current; 240 | } 241 | 242 | // in 'react-dom' 243 | HooksDispatcherOnMount = { 244 | useState: function (initialState) { 245 | return mountState(initialState); 246 | }, 247 | }; 248 | HooksDispatcherOnUpdate = { 249 | useState: function (initialState) { 250 | return updateState(initialState); 251 | }, 252 | }; 253 | ``` 254 | 255 | 观察代码可以发现: 256 | `dispatcher` 是 React 提供和维护的一个公共对象, 257 | React 会在不同生命周期(`mount`、`update`)提供不同的 `dispatcher`, 258 | 而不同的 `dispatcher` 包含不同的(相应的)处理方法。 259 | 260 | 函数组件代码中看上去调用了同一个 Hooks API, 261 | 但实际上会在不同时期取到不同的方法, 262 | 也就实现了以前 Class 写法中的生命周期的效果。 263 | 264 | ### Hooks 和 Class 的差异 265 | 266 | Hooks 写法和之前的 Class 写法算是截然不同的范式。 267 | 268 | Runtime 层面的直观差异是: 269 | 270 | - Hooks 组件每次渲染时,函数内可能所有东西都是重新声明的。 271 | (比如依赖 `setState` 的简单的 `onClickHandler`) 272 | - Class 组件,`render()` 中的局部方法一般都指向原型上的同一个,不会重新声明。 273 | 274 | 这算是在内存和性能上的差异(注意不是好坏)。 275 | 276 | 根据这一状况, 277 | Hooks API 自带了一些简单的优化措施(如 第二参数) 278 | 279 | ### 第二参数和优化 280 | 281 | - useEffect 282 | - useCallback 283 | - useMemo 284 | 285 | 以上方法都有第二个可选参数,用作依赖对比,目的是减少重复执行。 286 | 但是,依赖对比也需要一定的计算开销(在 React 内部,至少也有十来行)。 287 | 288 | 所以理解 JS 执行原理并加以权衡, 289 | 单行的简单 `onClickSetStateHandler` 可以不包裹到 `useCallback` 里。 290 | 291 | 可以只在以下情况使用 `useCallback`: 292 | 293 | - 避免重复执行 294 | - 需要同一个函数(如 timer) 295 | - 缓存大开销的函数(如 fetch) 296 | 297 | 也可以根据团队标准全部使用 `useCallback`,降低心智负担。 298 | 299 | ### Hooks 的运用 300 | 301 | 随着 Hooks 的普及和社区的发展, 302 | 函数组件能做的事情越来越多了, 303 | 甚至可以尝试只使用函数组件来写整个应用。 304 | 305 | 对于大型前端软件来说,也可以采取以下方案: 306 | 307 | - 直接由更专业的外部工具(如 redux、rxjs、ramda) 308 | 来处理复杂逻辑业务(如 sideEffect 实体、fetch 竞态、memo 计算) 309 | - React 只负责渲染相关逻辑 310 | 311 | 这样也就不用太关心 Hooks 本身的优化技巧了。 312 | 313 | 需要根据实际情况灵活运用。 314 | -------------------------------------------------------------------------------- /docs/note/10.frontend/05.state-management/3.rxjs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: RxJS 学习指南 3 | date: 2019-11-07 21:10:43 4 | permalink: /frontend/rxjs 5 | categories: 6 | - 前端开发 7 | - 前端工具 8 | tags: 9 | - rxjs 10 | --- 11 | 12 | # RxJS 学习指南 13 | 14 | ## RxJS 简介 15 | 16 | ### 什么是 ReactiveX 17 | 18 | ReactiveX 是一组采用响应式流的异步编程 API 标准,不同语言下都有实现了该 API 的具体库,例如 RxJS、RxJava、RxSwift 等。 19 | 它的核心思想是,将离散的**多个事件**视为**一个流**来操控,流可以(通过操作符)进行各种变换(映射、采样、合并等)。 20 | 21 | ### 什么是 RxJS 22 | 23 | RxJS 是 ReactiveX 的 JS 版实现,RxJS 之于事件处理,相当于 Lodash 之于数据处理。 24 | 25 | RxJS 在 Angular 中作为重要的数据底层,但是其本身是一个独立的库,可以在其他场景下使用,例如配合 React + Observable-hooks 作为全局状态管理器。 26 | 27 | ### 为什么要用 RxJS 28 | 29 | 能够更方便地梳理和管控异步逻辑。 30 | 31 | ## 学习 RxJS 32 | 33 | ### 概览 34 | 35 | - 耗时:从入门到熟悉需要大约 15~30 小时 36 | - 难点: 37 | - 理解 Stream 范式 38 | - 熟悉 API 全貌并综合运用 39 | - 工具: 40 | - [rxjs](https://github.com/ReactiveX/rxjs) 41 | - [observable-hooks](https://github.com/crimx/observable-hooks)(for React hooks) 42 | 43 | ### 学习路线 44 | 45 | - 前置学习 46 | - 理解 RxJS 的编程理念 47 | - 编程范式 48 | - [Functional Programming](/cs/introduction-to-functional-programming) 49 | - Reactive Programming 50 | - Stream Programming 51 | - 设计模式 52 | - 观察者模式(事件绑定机制) 53 | - 迭代器模式(事件流的遍历机制) 54 | - ([TypeScript](/cs/typescript-language-basic)) 55 | - 学习 RxJS 56 | - 掌握 RxJS 核心概念 57 | - Observable 及其上下游 58 | - 多播操作符、Subject 59 | - Scheduler 60 | - 尝试 RxJS 所有(类型)的 API 61 | - 同类 API 之间的效果差异 62 | - 相同效果的流可以有多种实现方式 63 | - 题目/实战 64 | - 练习实现具体功能,加深理解 65 | - 结合 React/Vue 在项目中使用 66 | - 进阶 67 | - 实现一个自己的 Observable 68 | - 阅读 RxJS 源码实现 69 | - 迷思 70 | - 如何手动结束/关闭一个 Observable 71 | - 内存管理和垃圾回收 72 | 73 | ## 资料 74 | 75 | ### 我的学习代码 76 | 77 | - [RxJs - Learn By Doing](https://github.com/seognil-study/learn-by-doing/tree/master/rxjs) 78 | 79 | ### 关于 响应式编程 的扩展阅读 80 | 81 | - [Introduction to Reactive Programming](https://egghead.io/courses/introduction-to-reactive-programming) 82 | - [The introduction to Reactive Programming you've been missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) 83 | - [RxJS 入门指引和初步应用](https://zhuanlan.zhihu.com/p/25383159) 84 | - [RxJS-响应式流编程](http://blueskyawen.com/2017/12/24/rxjs/) 85 | - [流动的数据——使用 RxJS 构造复杂单页应用的数据逻辑](https://github.com/xufei/blog/issues/38) 86 | 87 | ### RxJS 自学教材 88 | 89 | - 教程 90 | - [Top Ten RxJS Concepts](https://fireship.io/lessons/rxjs-basic-pro-tips/):一些基本概念和 API 的示例 91 | - [Learn RxJS](https://www.learnrxjs.io/) :非常完整的 RxJS 教程站点,涵盖了大部分 API ,有代码片段及小型 Demo 92 | - [RxJS - Introduction](https://rxjs-dev.firebaseapp.com/guide/overview):官方文档教程板块 93 | - 动画/演示/Demo 94 | - [Launchpad for RxJS](https://reactive.how/rxjs/) :(v6)动画演示(一部分),API 按类型整理划分 95 | - [RxJS example + marble diagram](https://thinkrx.io/rxjs/interval/) :(v6)通过代码生成的弹珠台 96 | - [RxJS Marbles](https://rxmarbles.com/) :弹珠台,可直接拖动,只有动画 97 | - 书籍 98 | - [深入浅出 RxJS](https://book.douban.com/subject/30217949/) (v5) 99 | 100 | ### 实战 101 | 102 | - [Recipes - Learn RxJS](https://www.learnrxjs.io/recipes/):Learn RxJS 中的 Demo 板块 103 | - [我所了解的 RxJS](https://juejin.im/post/5ca56f42f265da30982748e6#heading-13) 104 | 105 | ## RxJS 知识体系 106 | 107 | ### RxJS 主要概念 108 | 109 | - **Observable** 110 | - Observable: stream 序列;有多种创建方式,例如 `timer`、`fromEvent` 等 111 | - operator: 操作符,对 Observable 进行形变;例如 `map`、`merge` 等 112 | - **subscribe** 113 | - subscribe: 订阅(Observable 的方法) 114 | - Observer: 观察者/消费者方法集合(业务方法,传给 subscribe() 的) 115 | - subscription: 订阅关系(subscribe 函数返回的对象) 116 | - unsubscribe: 结束订阅方法(Subscription 提供的) 117 | - **Subject**: 多播的 Observable(可以作为 Observable 和 Subscription 的一个胶水层) 118 | - **Scheduler**:调度器,用来调整事件触发的策略,例如 `asyncScheduler`、`animationFrameScheduler` (见名知意) 119 | 120 | * Cold vs Hot Observable 121 | - Cold:多次订阅产生多个独立的事件流(用途例如:`interval`) 122 | - Hot:多次订阅共享同一个事件流(用途例如:`fromEvent`、`Subject`) 123 | 124 | ## RxJS 典型代码 125 | 126 | ### RxJS 基本用法 127 | 128 | #### 伪代码 129 | 130 | ```javascript 131 | // * -------- 新建一个 Observable 132 | 133 | Ob = Observable() 134 | // * (可选)通过不同的操作符对原始 stream 进行加工处理 135 | .pipe( 136 | map((a) => b), 137 | filter((b) => b > 0), 138 | debounceTime(200), 139 | ); 140 | 141 | // * -------- 订阅 (以及多种传参方式) 142 | 143 | Subscription = Ob.subscribe((v) => {}); 144 | 145 | Subscription = Ob.subscribe( 146 | (v) => {}, 147 | (e) => {}, 148 | () => {}, 149 | ); 150 | 151 | Subscription = Ob.subscribe({ 152 | next(v) {}, 153 | error(e) {}, 154 | complete() {}, 155 | }); 156 | 157 | // * -------- 取消订阅 158 | 159 | Subscription.unsubscribe(); 160 | ``` 161 | 162 | #### 具体代码 v5 163 | 164 | ```javascript 165 | // Node.js 166 | 167 | import { Observable } from 'rxjs'; 168 | 169 | const ob$ = Observable.interval(500).map((e) => e * 2); 170 | 171 | const sub$ = ob$.subscribe((e) => console.warn(e)); 172 | 173 | setTimeout(() => sub$.unsubscribe(), 3000); 174 | ``` 175 | 176 | #### 具体代码 v6 177 | 178 | ```javascript 179 | // Node.js 180 | 181 | import { interval } from 'rxjs'; 182 | import { map } from 'rxjs/operators'; 183 | 184 | const ob$ = interval(500).pipe(map((e) => e * 2)); 185 | 186 | const sub$ = ob$.subscribe((e) => console.warn(e)); 187 | 188 | setTimeout(() => sub$.unsubscribe(), 3000); 189 | ``` 190 | 191 | ### RxJS 实用代码 192 | 193 | ```javascript 194 | // * interval of requestAnimationFrame, tick frame time (ms) 195 | const rafInterval$ = () => 196 | of(Date.now(), animationFrameScheduler).pipe( 197 | map((start) => Date.now() - start), 198 | repeat(), 199 | ); 200 | ``` 201 | 202 | ## RxJS 相关 203 | 204 | ### RxJS 和 TypeScript 205 | 206 | RxJS 源码是 TypeScript 写的,对 TS 支援度很不错 207 | 208 | 但目前还有些未完美覆盖的情况,例如: 209 | 210 | ```typescript 211 | // * 没有正确识别 212 | pipe(publish()); // => Observable 213 | 214 | // * 需要手动指定 type 215 | pipe(publish()) as ConnectableObservable; 216 | ``` 217 | 218 | - [Pipe operator cannot infer return type as ConnectableObservable #2972](https://github.com/ReactiveX/rxjs/issues/2972) 219 | - [Property 'connect' does not exist on type 'Observable\' | RXJS multicast](https://stackoverflow.com/questions/54265143/property-connect-does-not-exist-on-type-observableany-rxjs-multicast) 220 | 221 | ### RxJS 版本 222 | 223 | 截稿时 RxJS 最新的版本是 `v6` 224 | (`v7` 处于 alpha 中) 225 | `v6` 和 `v5` 的主要差别在于 API 名和语法 226 | 227 | 比如为了实现函数式调用风格, 228 | 操作符 `do` 重命名成了 `tap` (因为 `do` 是 JS 保留字) 229 | 230 | 新项目直接用 `v6` 即可 231 | 老项目也可以用兼容包升级 232 | 233 | - [RxJS v5.x to v6 Update Guide](https://rxjs-dev.firebaseapp.com/guide/v6/migration) 234 | - [rxjs CHANGELOG](https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md) 235 | 236 | ### 命名习惯 237 | 238 | ```javascript 239 | const myStream$ = interval(500); 240 | ``` 241 | 242 | Stream 相关的命名一般用 `$` 做后缀,是一种共识,但也没有硬性规定。 243 | (就像使用 `jQuery` 会用 `$` 作为变量前缀一样) 244 | -------------------------------------------------------------------------------- /docs/note/10.frontend/08.javascript-test/4.cypress.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Cypress 学习指南 3 | date: 2020-01-29 20:31:10 4 | permalink: /frontend/cypress 5 | categories: 6 | - 前端开发 7 | - 前端工具 8 | tags: 9 | - cypress 10 | --- 11 | 12 | # Cypress 学习指南 13 | 14 | ## Cypress 简介 15 | 16 | ### 什么是 Cypress 17 | 18 | 一个前端测试工具 19 | 20 | - Cypress 能测试什么 21 | - - E2E 测试 22 | - 集成测试 23 | - 单元测试(因为内嵌了 Mocha) 24 | - 任何在浏览器中运行的内容 25 | 26 | * Cypress 提供的一些功能 27 | - 时间旅行 28 | - 自动等待(类似 Jest 中的 wait) 29 | - 以同步风格的代码完成异步操作 30 | - 网络流量控制 31 | - 截屏 32 | - 持续集成 33 | 34 | - Cypress 语法设计(及内置对象) 35 | - jQuery + 链式调用 36 | - Promise(Bluebird) 37 | - Mocha + Chai 38 | 39 | ### 为什么要用 Cypress 40 | 41 | - 当你需要 E2E 测试 42 | - 在 [2019 年 JavaScript 明星项目](https://risingstars.js.org/2019/zh#section-test-framework) 的测试分类中位于第二名 43 | - 比其他同类 E2E 测试工具更简单、灵活、健壮 44 | 45 | ## 学习 Cypress 46 | 47 | ### 概览 48 | 49 | - 耗时:从入门到熟悉基本概念,大约需要 8~16 小时 50 | - 难点:充分利用需要花一定时间学习和配置(报告、覆盖率、CI 等) 51 | - 工具:[cypress](https://docs.cypress.io/guides/getting-started/installing-cypress) 52 | 53 | ### 学习路线 54 | 55 | - 前置学习 56 | - [前端开发入门指南](/note/frontend-development-cookbook) 57 | - ([Jest](/frontend/jest)) 58 | - (有一定实际应用开发经验) 59 | - 学习 Cypress 60 | - 了解 Cypress 的组成,全面阅读文档 61 | - 掌握基本使用 62 | - 实战 63 | - 在业务中编写测试 64 | - 进一步熟悉各 API 的大量细节 65 | - 为项目调整 Cypress 配置,使用高级功能 66 | 67 | ## 资料 68 | 69 | ### 自学教材 70 | 71 | - [Cypress End-to-End Testing](https://www.youtube.com/watch?v=7N63cMKosIE):10 分钟,Cypress 概览 72 | - [Cypress 官方文档](https://docs.cypress.io/guides/overview/why-cypress.html#In-a-nutshell) 73 | - [API](https://docs.cypress.io/api/api/table-of-contents.html) 74 | - [最佳实践](https://docs.cypress.io/guides/references/best-practices.html) 75 | 76 | ### 实战 77 | 78 | - [Cypress - Learn By Doing](https://github.com/seognil-study/learn-by-doing/tree/master/testing/cypress) 79 | - [cypress-example-recipes](https://github.com/cypress-io/cypress-example-recipes) 80 | 81 | ## Cypress 知识体系 82 | 83 | ### Cypress 概览 84 | 85 | #### 安装/初始化 86 | 87 | ```bash 88 | # 在已有项目中安装 cypress 89 | npm install cypress --save-dev 90 | 91 | # 接着运行这个命令,cypress 将初始化并生成一堆用例 92 | npx cypress open 93 | ``` 94 | 95 | #### [文件结构](https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests.html#Folder-Structure) 96 | 97 | - **/cypress** 98 | - **/fixtures** (mock 数据) 99 | - example.json 100 | - **/integration** (测试文件) 101 | - **/examples** 102 | - example.spec.js (一般格式为 `*.spec.js`) 103 | - **/plugins** (用于配置安装的 [插件](https://docs.cypress.io/guides/tooling/plugins-guide.html),task 系统) 104 | - index.js 105 | - **/support** (用于调整 [自定义选项](https://docs.cypress.io/guides/references/configuration.html)) 106 | - commands.js 107 | - index.js 108 | - /screenshots (默认截屏文件夹) 109 | - **cypress.json** 110 | 111 | #### 测试文件 典型代码 112 | 113 | ```typescript 114 | /// 115 | 116 | describe('描述', () => { 117 | before(() => console.log('---- Test Start! ----')); 118 | beforeEach(() => cy.visit('https://witch.url')); 119 | afterEach(() => cy.clearCookies()); 120 | 121 | it('测试用户交互', () => { 122 | cy.get('#app').children('.intro').click(); 123 | cy.contains('Welcome').should('be.exist'); 124 | }); 125 | 126 | it('测试显示文本', () => { 127 | cy.get('div').should('have.text', 'Hello'); 128 | // * 另一种风格 129 | cy.get('div').should(($div) => { 130 | const text = $div.text(); 131 | expect(text).to.match(/hello/i); 132 | }); 133 | }); 134 | }); 135 | ``` 136 | 137 | 大致分为几个部分 138 | 139 | - TypeScript 自动完成支持(第一行的注释) 140 | - 运行器和生命周期(`describe`、`it`、`before` 等) 141 | - 元素查找和操作(`cy` 相关命令) 142 | - 断言/测试(`should`、`expect`、`assert` 多种风格) 143 | 144 | #### Cypress 对象 145 | 146 | [`Cypress` 和 `cy` 的区别](https://docs.cypress.io/api/events/catalog-of-events.html#Cypress) 147 | 148 | - `Cypress`:全局对象,影响所有测试 149 | - [内置工具](https://docs.cypress.io/api/utilities/_.html) 150 | - [`Cypress._`](https://docs.cypress.io/api/utilities/_.html#Syntax):[Lodash](https://lodash.com/) 151 | - [`Cypress.$`](https://docs.cypress.io/api/utilities/$.html):[jQuery](https://jquery.com/) 152 | - [`Cypress.Blob`](https://docs.cypress.io/api/utilities/blob.html):[blob-utli](https://github.com/nolanlawson/blob-util) 153 | - [`Cypress.minimatch()`](https://docs.cypress.io/api/utilities/minimatch.html):[minimatch](https://github.com/isaacs/minimatch) 154 | - [`new Cypress.Promise(fn)`](https://docs.cypress.io/api/utilities/promise.html):[Bluebird](https://github.com/petkaantonov/bluebird) 155 | - [全局 API](https://docs.cypress.io/api/cypress-api/custom-commands.html) 156 | - `cy`:在每个测试中相互独立 157 | - [测试命令](https://docs.cypress.io/api/commands/and.html) 158 | 159 | ### 测试/断言 160 | 161 | [Cypress 中内置的断言](https://docs.cypress.io/guides/references/assertions.html) 包含了几种类型: 162 | 163 | - **Chai**:断言 164 | - `expect('test').to.be.a('string')`:BDD 风格 165 | - `assert.equal(3, 3, 'vals equal')`:TDD 风格 166 | - **Chai jQuery**:关于 DOM 的断言 167 | - `expect(\$el).to.have.attr('foo', 'bar')` 168 | - **Sinon-Chai**:关于函数调用情况的断言 169 | - `expect(spy).to.be.called` 170 | - **`.should()`**:在 Cypress 中封装了以上所有可用断言 171 | - `cy.get('li.selected').should('have.length', 3)`:should 172 | - `cy.get('div').should(($div) => { expect($div)... })`:BDD 173 | 174 | 注意到 [Cypress 使用 Mocha BDD 风格的生命周期](https://docs.cypress.io/guides/references/bundled-tools.html#Mocha), 175 | 不同测试的命名风格: 176 | 177 | | Mocha BDD | Mocha TDD | Jest | 178 | | :------------------- | :-------------- | :---------- | 179 | | `describe`/`context` | `suite` | `describe` | 180 | | `specify`/`it` | `test` | `test`/`it` | 181 | | `before` | `setup` | `beforeAll` | 182 | | `after` | `teardown` | `afterAll` | 183 | | `beforeEach` | `suiteSetup` | `before` | 184 | | `afterEach` | `suiteTeardown` | `after` | 185 | 186 | ### `cy` 命令 187 | 188 | 用来编写测试 189 | 190 | - 测试 191 | - `should`:断言 192 | - `then`:类似 Promise 的 then 193 | - `each`:遍历执行(对于数组) 194 | - `spread`:then 的 each 版 195 | - 查询 196 | - `contains`、`get` 197 | - `children`、`closest`、`find` 198 | - `eq`、`filter`、`not` 199 | - `first`、`last` 200 | - `next`、`nextAll`、`nextUntil` 201 | - `parent`、`parents`、`parentsUntil` 202 | - `prev`、`prevAll`、`prevUntil` 203 | - `siblings` 204 | - `window`、`document`、`title` 205 | - `its`:取得对象中的字段,如 `cy.get('ul li').its('length')` 206 | - `root`:当前上下文的根元素节点 207 | - `within`:设定上下文元素(类似 JS 中的 with) 208 | - 操作 209 | - 用户操作 210 | - `click`、`dblclick`、`rightclick` 211 | - `blur`、`focus`、`focused` 212 | - ~~`hover`~~:不支持 213 | - `trigger`:触发事件 214 | - 表单/输入框 215 | - `check`、`uncheck`、`select` 216 | - `clear`:清除文本框 217 | - `type`:输入文本框 218 | - `submit` 219 | - `scrollIntoView`、`scrollTo` 220 | - `invoke`:调用对象中的函数,如 `cy.get('div').invoke('show')` 221 | - 浏览器 222 | - `viewport`:设置应用窗口大小 223 | - `clearCookie`、`clearCookies`、`getCookie`、`getCookies`、`setCookie` 224 | - `clearLocalStorage` 225 | - 网络请求 226 | - `visit`、`reload`:访问 227 | - `hash`、`location`、`url`:获取 228 | - `go`:历史跳转,相当于 `window.history.go` 229 | - `request`:HTTP 请求 230 | - `server`:启动一个服务 231 | - `route`:跳转路由 232 | - 功能性 233 | - 任务 234 | - `log`、`debug`、`pause` 235 | - `exec`:执行 shell 命令 236 | - `readFile`、`writeFile` 237 | - `screenshot`:截屏到 `/screenshots` 238 | - `fixture`:读取 `/fixtures` 中文件内容 239 | - `task`:执行 `/plugins` 中声明的事件 240 | - 语法糖 241 | - `as`:设置为别名 242 | - `and`:进行多个测试 243 | - `end`:截断当前测试(后续链式调用将重新计算) 244 | - `wrap`:包装一个对象(以便支持 cy 命令) 245 | - 调用监听 246 | - `spy`:监听对象中的函数 247 | - `stub`:替换对象中的函数(用于监听) 248 | - Timer 249 | - `clock`:覆写原生时钟(将会影响 setTimeout 等原生函数) 250 | - `tick`:跳过时间,加快测试速度(需要先 `cy.clock()`) 251 | - `wait`:显式等待(不推荐使用) 252 | 253 | ### `Cypress` API 254 | 255 | 包含定制选项方法,或公共静态方法 256 | 257 | - 定制 258 | - `Commands`:添加自定义命令 259 | - `Cookies`:测试时的 Cookie 行为控制 260 | - `Screenshot`:截屏参数配置 261 | - `SelectorPlayground`:调整选择器规则 262 | - `Server`:调整 `cy.server()` 默认参数 263 | - `config`:修改 Cypress 的 [配置选项](https://docs.cypress.io/guides/references/configuration.html) 264 | - `env`:管理自定义全局变量 265 | - `log`:配置 log 参数 266 | - 辅助 267 | - `dom`:一组 dom 相关方法 268 | - 如 `Cypress.dom.isHidden($el)` 269 | - `isCy`:是否是 cy 对象 270 | - 环境信息 271 | - `arch`:获取 CPU 架构,来源于 Node `os.arch()` 272 | - `browser`:获取浏览器信息 273 | - `platform`:获取操作系统名字 274 | - `spec`:当前测试文件信息 275 | - `version`:版本号 276 | 277 | ### 事件 278 | 279 | 事件绑定机制是 [Node Events](https://nodejs.org/api/events.html), 280 | 用法如:`Cypress.on`/`cy.on` 281 | 282 | - 应用(页面)事件 283 | - `uncaught:exception` 284 | - `window:confirm`、`window:alert`、`window:before:load`、`window:load`、`window:before:unload`、`window:unload` 285 | - `url:changed` 286 | - Cypress 事件 287 | - `fail` 288 | - `viewport:changed` 289 | - `scrolled` 290 | - `command:enqueued`、`command:start`、`command:end`、`command:retry` 291 | - `log:added`、`log:changed` 292 | - `test:before:run`、`test:after:run` 293 | 294 | ## Cypress 典型代码 295 | 296 | 查看上文中的 [实战链接](#%e5%ae%9e%e6%88%98) 及 [典型代码](#%e6%b5%8b%e8%af%95%e6%96%87%e4%bb%b6-%e5%85%b8%e5%9e%8b%e4%bb%a3%e7%a0%81) 297 | -------------------------------------------------------------------------------- /docs/note/10.frontend/frontend-hardcore-overview/frontend-hardcore-overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 硬核前端(劝退篇) 3 | date: 2019-12-14 22:03:19 4 | permalink: /frontend/frontend-hardcore-overview 5 | categories: 6 | - 前端开发 7 | tags: 8 | - 杂谈 9 | --- 10 | 11 | # 硬核前端(劝退篇) 12 | 13 | ## 当个前端工程师 14 | 15 | ### 这算是前端**工程师**吗? 16 | 17 | 你以为前端就是切图写页面吗? 18 | 19 | 你以为互联网行业有高工资,前端又好像门槛相对比较低, 20 | 报了个培训班学了三个月,找到工作拿个十几 K 就喜大普奔吗? 21 | 22 | 你以为写了个仿饿了么、仿网易云、写了个轮播, 23 | 学了下 React/Vue 用法(甚至还读了源码), 24 | 就算前端入门了吗?就了解前端了吗? 25 | 26 | 不不不,这只是最初的阶段。 27 | 28 | ![dk-effect](./img/dk-effect.jpg) 29 | 30 | #### 那前端还能做些什么 31 | 32 | [这个程序员写的免费在线 PS,让他三十岁前财务自由](https://zhuanlan.zhihu.com/p/70636726) 33 | 34 | [拆解一款 Webgl 渲染器](https://zhuanlan.zhihu.com/p/28108991) 35 | 36 | [从 VSCode 看大型 IDE 技术架构](https://zhuanlan.zhihu.com/p/96041706) 37 | 38 | [页面可视化搭建工具前生今世](https://zhuanlan.zhihu.com/p/37171897) 39 | 40 | #### 前端行业的近况 41 | 42 | > 每 18 至 24 个月,前端都会难一倍。 —— 赫门 / 2015 “深 JS”大会 43 | 44 | [在 2016 年学 JavaScript 是一种什么样的体验?](https://zhuanlan.zhihu.com/p/22782487) 45 | 46 | > 在你学会一项前端技术的时候,另外三项新技术已经发布了。不仅如此,你刚学会的那个也已经被弃用了。 47 | > —— [[译] 为何前端开发如此不稳定](https://juejin.im/post/5b1f2f1ae51d4506894983ae) 48 | 49 | [为什么很多技术都觉得前端很简单?](https://www.zhihu.com/question/353545736/answer/935917542) 50 | 51 | [未来的前端工程师](https://juejin.im/post/5a474c8ff265da430a50ea57) 52 | 53 | [给 2019 前端的 5 个建议](https://github.com/camsong/blog/issues/11) 54 | 55 | [「2019 JSConf.Asia - 尤雨溪」在框架设计中寻求平衡](https://zhuanlan.zhihu.com/p/76622839) 56 | 57 | [现代 Web 开发的现状与未来(JSDC 2019 演讲全文)](https://zhuanlan.zhihu.com/p/88616149) 58 | 59 | [这些年的体验技术部 · 前端工程 - 与云共舞,未来已来](https://www.yuque.com/afx/about/basement) 60 | 61 | [《蚂蚁前端研发最佳实践》文字稿](https://github.com/sorrycc/blog/issues/90) 62 | 63 | [VS Code 成主宰、Vue 备受热捧!2019 前端开发趋势必读](https://zhuanlan.zhihu.com/p/97741102) 64 | 65 | ![stateofjs2019](./img/stateofjs2019-dark-fs8.png) 66 | 67 | [2019 年 JavaScript 明星项目](https://risingstars.js.org/2019/zh) 68 | [2018 年 JavaScript 明星项目](https://risingstars.js.org/2018/zh) 69 | [The State of JavaScript 2019](https://2019.stateofjs.com/zh/) 70 | 71 | ### 所以,前端工程师是什么? 72 | 73 | > 前端工程师首先是个程序员,其次也是个软件工程师。 74 | 75 | 前端工程师应该掌握扎实的 JS、CS 理论知识和编程功底。 76 | 并将工作尽可能得工程化。 77 | 78 | 虚假的前端工程师: 79 | 80 | ![fe-naive](./img/fe-naive-fs8.png) 81 | 82 | 真正的前端工程师: 83 | 84 | ![fe-hardcore](./img/fe-hardcore-fs8.png) 85 | 86 | #### 如何成为优秀的前端工程师 87 | 88 | 简单的道理:不会就学 89 | 90 | 并且要学习的是精华的、核心的、通用的、本质的部分, 91 | 而不是 API 和用法的表皮。 92 | 93 | > 众所周知,技术会过时。 94 | > 有的工作准入门槛低,但这不等于简单。 95 | > 你应该做的是去学习基本功。比如啥操作系统,算法,编程语言,体系结构这些。 96 | > —— [半衰期](https://zhuanlan.zhihu.com/p/84927997) 97 | 98 | [打破框架的范式之争](https://zhuanlan.zhihu.com/p/82958907) 99 | 100 | > 很多时候,人们排斥一个新技术,并不是因为新技术不好,而是这可能让自己多年精通的老手艺带来的 “竞争优势” 完全消失。可能一个织布老专家手工织布效率是入门学员的 5 倍,但换上织布机器后,这个差异很快会被抹平,老织布专家面临被淘汰的危机,所以维护这份老手艺就是维护他自己的利益。希望每个团队中的老织布工人都能主动引入织布机。 101 | > —— [精读《unstated 与 unstated-next 源码》](https://zhuanlan.zhihu.com/p/93500556) 102 | 103 | ## 小结 104 | 105 | > 生产力决定生产关系:生产力对生产关系起着决定作用、支配作用,其主要表现在两个方面:第一,生产力的性质决定生产关系的性质。第二,生产力的发展变化决定生产关系的改变。 106 | > 生产关系反作用于生产力:这种反作用表现为两种情况:第一,适合生产力的性质和发展要求的先进的生产关系,促进生产力的发展;第二,不适合生产力的性质和发展要求的落后的生产关系,阻碍生产力的发展。 107 | > —— [马克思主义哲学](https://zh.wikipedia.org/wiki/%E5%8E%86%E5%8F%B2%E5%94%AF%E7%89%A9%E4%B8%BB%E4%B9%89) 108 | 109 | > 通常来说,我们都会认为高工资来自于高技能。但从逻辑上来说,这是不对的。因为从经济学角度来说,高工资只能来自于高利润,这是一个很容易理解的收支平衡问题。 110 | > 而 IT 行业之所以能拥有高利润,是因为过去的这些年,IT 行业确实极大的促进了生产力的发展。所以,才会有高利润溢价推高程序员的工资。 111 | > —— [非程序员说编程有什么难的,作为程序员,该怎么回答这个问题? - 沈世钧](https://www.zhihu.com/question/356294204/answer/935303946) 112 | 113 | 如果看完本文中的链接,你的感受是: 114 | 115 | > 卧槽!这都什么东西?球球你们别学了,我跟不上了。 116 | 117 | 那么你**可能**不太适合这个行业, 118 | 建议赶紧转行,找一份真正适合自己的工作, 119 | 而不是强行进入这个行业,当个切图仔调包侠。 120 | 然后过两三年才发现自己不适合这个工种, 121 | 并且由于高深的技术又不会、搬砖又拼不过年轻人,只能被裁员这样子。 122 | ( 战 术 劝 退 ) 123 | 124 | ![go-home](./img/go-home.jpeg) 125 | 126 | 如果你的感受是: 127 | 128 | > 卧槽!爽文!搞技术太酷了!打开了新世界!我来! 129 | 130 | 那么恭喜,说明你有一定的技术储备和技术思维, 131 | 并且拥有相当的技术热情,你**可能**非常有机会! 132 | 欢迎你!期待你能创造更多价值! 133 | -------------------------------------------------------------------------------- /docs/note/10.frontend/frontend-hardcore-overview/img/dk-effect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/10.frontend/frontend-hardcore-overview/img/dk-effect.jpg -------------------------------------------------------------------------------- /docs/note/10.frontend/frontend-hardcore-overview/img/fe-hardcore-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/10.frontend/frontend-hardcore-overview/img/fe-hardcore-fs8.png -------------------------------------------------------------------------------- /docs/note/10.frontend/frontend-hardcore-overview/img/fe-naive-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/10.frontend/frontend-hardcore-overview/img/fe-naive-fs8.png -------------------------------------------------------------------------------- /docs/note/10.frontend/frontend-hardcore-overview/img/go-home.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/10.frontend/frontend-hardcore-overview/img/go-home.jpeg -------------------------------------------------------------------------------- /docs/note/10.frontend/frontend-hardcore-overview/img/stateofjs2019-dark-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/10.frontend/frontend-hardcore-overview/img/stateofjs2019-dark-fs8.png -------------------------------------------------------------------------------- /docs/note/10.frontend/frontend-hardcore-overview/img/stateofjs2019tshirt-illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/10.frontend/frontend-hardcore-overview/img/stateofjs2019tshirt-illustration.png -------------------------------------------------------------------------------- /docs/note/20.computer-science/map-of-computer-science-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/20.computer-science/map-of-computer-science-fs8.png -------------------------------------------------------------------------------- /docs/note/21.tool-skills/01.git/img/git-cheatsheet-cn.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/21.tool-skills/01.git/img/git-cheatsheet-cn.jpeg -------------------------------------------------------------------------------- /docs/note/21.tool-skills/01.git/img/git-flow-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/21.tool-skills/01.git/img/git-flow-fs8.png -------------------------------------------------------------------------------- /docs/note/21.tool-skills/01.git/img/git-mindmap-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/21.tool-skills/01.git/img/git-mindmap-fs8.png -------------------------------------------------------------------------------- /docs/note/21.tool-skills/02.markdown.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown 学习指南 3 | date: 2019-12-26 12:27:58 4 | permalink: /cs/markdown 5 | categories: 6 | - 计算机科学 7 | tags: 8 | - 工具 9 | - markdown 10 | --- 11 | 12 | # Markdown 学习指南 13 | 14 | ## Markdown 简介 15 | 16 | ### 什么是 Markdown 17 | 18 | > Markdown 是一种轻量级标记语言。它允许人们“使用易读易写的纯文本格式编写文档,然后转换成有效的 XHTML(或者 HTML)文档”。 19 | > 当前许多网站都广泛使用 Markdown 来撰写帮助文档或是用于论坛上发表消息。例如:GitHub、reddit、Diaspora、Stack Exchange、OpenStreetMap 、SourceForge 等。甚至 Markdown 能被使用来撰写电子书。 20 | 21 | 文件后缀常用 `.md` 或 `.markdown`, 22 | Markdown 的配套工具有语法高亮、解析工具等… 23 | 24 | GitHub 大多数项目中的 `README.md` 就是用 Markdown 写的项目说明, 25 | 本站的所有文章也都是用 Markdown 写的。 26 | 27 | 当 Markdown 自身规则无法满足时,**也可以**写任意合法的 **HTML** 代码。 28 | 29 | ### 什么是 TOC 30 | 31 | Table Of Contents 的缩写,表示目录。 32 | 33 | 由于 Markdown 的规则具有约束性, 34 | 能够很方便地根据 Markdown 内容生成目录, 35 | 有很多工具可以自动化地做这个事情。 36 | 37 | ### 为什么要学习使用 Markdown 38 | 39 | - 写起来简便 40 | - 写 GitHub 的 `README` 41 | - 为了看懂别人的内容 42 | 43 | ## 学习 Markdown 44 | 45 | ### 概览 46 | 47 | - 耗时:几分钟 48 | - 难点:无 49 | - 工具:一大堆 50 | 51 | ### 学习路线 52 | 53 | - 前置学习 54 | - HTML 55 | - 学习 Markdown 56 | - Markdown 全部基本语法 57 | - 了解:不同工具可能会有自己的扩展语法 58 | - 实战 59 | - 写写学习笔记 60 | - 给自己的项目写 Readme 61 | 62 | ## 资料 63 | 64 | ### 自学教材 65 | 66 | - [Mastering Markdown](https://guides.github.com/features/mastering-markdown/) 67 | - [Markdown Cheatsheet](https://github.com/tchapi/markdown-cheatsheet) 68 | - [Markdown - Learn X in Y minutes](https://learnxinyminutes.com/docs/markdown/) 69 | 70 | ### 写作软件(桌面) 71 | 72 | 我个人不用其他的写作软件… 73 | 在 [学习方法论](/study/crash-course-study-skills) 一文中,我提到我使用 “云盘 + VS Code” 的知识管理模式 74 | 75 | 对于 Markdown 写作,我自己主要是: 76 | 77 | - [VS Code](https://code.visualstudio.com/) 78 | - Markdown 插件:[Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) 79 | - 语法高亮:[Dracula](https://draculatheme.com/) 80 | - 格式化:[Prettier](https://prettier.io/) 81 | - 编译发布:[VuePress](https://vuepress.vuejs.org/zh/) 82 | 83 | Markdown 的某些特性可能有多种写法, 84 | 使用格式化工具可以保持编码风格统一。 85 | 86 | 而现成的编译器可能会集成代码块语法高亮等功能。 87 | 88 | ### 写作软件(在线) 89 | 90 | - [马克飞象](https://maxiang.io/) 91 | - [DILLINGER](https://dillinger.io/) 92 | 93 | ### Markdown JS 解析器 94 | 95 | - [markdown-it](https://github.com/markdown-it/markdown-it) 96 | - [marked](https://github.com/markedjs/marked) 97 | - [markdown-js](https://github.com/evilstreak/markdown-js) 98 | 99 | ### 工具 100 | 101 | - [markdown-here](https://github.com/adam-p/markdown-here) 102 | - [doctoc](https://github.com/thlorenz/doctoc) 103 | - [github-markdown-toc](https://github.com/ekalinin/github-markdown-toc) 104 | 105 | ## Markdown 典型代码 106 | 107 | ```markdown 108 | 109 | 110 | # H1 111 | 112 | ## H2 113 | 114 | ###### H6 115 | 116 | 117 | 118 | **粗体 strong** 119 | _斜体 em_ 120 | ~~删除线 s~~ 121 | 122 | 注意:以上标记如果边界处有空格,根据工具不同可能会造成解析失败 123 | 例如: _ 可能无效 _ 124 | 125 | 126 | 127 | 像这样用反引号包起来 → `exit vim` 128 | 使用场景:JavaScript 中有 `var` 关键字。 129 | 130 | 131 | 132 |

也可以使用任意合法 HTML 标签

133 | 134 | ``` 135 | 136 | ```markdown 137 | 138 | 139 | > 以右尖括号开头的段落表示引用 140 | > 支持很多其他 **Markdown 语法** 141 | >
包括换行 142 | > 143 | > > 也可以嵌套 144 | > > 本质上是转义成 blockquote 标签 145 | 146 | 147 | 148 | 一行的最后接两个空格(选中看看) → 149 | 再写另一行,则会形成换行。 150 | 151 | GitHub 好像不加空格也可以自动视为换行 152 | Vuepress 使用的编译器则不行,必须加上空格 153 | 154 | 或者显式地
155 | 156 | 157 | 158 | --- 159 | 160 | --- 161 | 162 | --- 163 | 164 | 这些字符,连续三个以上 165 | 166 | 或者显式地
167 | ``` 168 | 169 | ```markdown 170 | 171 | 172 | [链接文字](https://rualc.me/) 173 | 174 | 编译成: 175 | 链接文字 176 | 177 | 同名链接的写法 ↓ 178 | 179 | 等价于: 180 | [https://rualc.me/](https://rualc.me/) 181 | 182 | VuePress 不支持裸链接直接编译,可以使用同名链接的写法 183 | GitHub 则是直接支持编译 184 | 185 | --- 186 | 187 | [链接也可以分开写][home] 188 | 189 | [home]: https://rualc.me/ '这里可以写注释' 190 | 191 | 192 | 193 | ![图片描述](https://rualc.me/js-nation-square-blue.png) 194 | 195 | 编译成: 196 | 图片描述 197 | ``` 198 | 199 | ```markdown 200 | 201 | 202 | - 列表项 203 | - 子项 204 | - 子项 205 | - 属于同一个列表 206 | - 也可以用不同的标记 207 | - 但是需要保持一致(这里是演示) 208 | - 使用格式化工具比较好 209 | 210 | * 不同的一级标记则视为另一个列表 211 | - 子项 212 | 213 | 214 | 215 | 1. 有序列表 216 | 2. 有些工具会自动补齐下一行的数字 217 | 3. 但其实数字值其实无所谓(解析工具自动判断) 218 | 219 | 4. 另起一行不会视为另一个列表(因为自动解析规则) 220 | 5. 请插入
来实现 221 | 222 |
223 | 224 | 1. 像这样才是另一个列表 225 | 226 | 227 | 228 | - [ ] 未完成 `[ ]` 表示未完成 229 | - [ ] 未完成 实际上会编译成 230 | - [x] 已完成 `[x]` 表示已完成 231 | - [ ] 默认可能无法直接编辑(通过 `disabled` 属性实现) 232 | - [x] GitHub 的 issue 页支持直接编辑(并保存) 233 | 234 | 235 | 236 | | 表格 | 第二栏 | 第三栏 | | 237 | | -------- | :------- | -------: | :----: | 238 | | 表格内容 | 左对齐 ↑ | 右对齐 ↑ | 居中 ↑ | 239 | | | 文字 | 文字 | 文字 | 240 | 241 | 建议编写时使用等宽字体 242 | Prettier 格式化可以自动对齐每一栏 243 | ``` 244 | 245 | `````markdown 246 | 247 | 248 | ```javascript 249 | var a = 2; 250 | ``` 251 | 252 | 253 | 254 | ````markdown 255 | ``` 256 | 三个 ` 表示代码块 后面可以指定语言(也可以不) 257 | ``` 258 | 259 | 代码块可以像这样嵌套 ↑, 260 | 写法上类似 #,只要多写几个反引号,则内部不会转义 261 | 262 | 其实这个版块整个都被包裹在代码块里 263 | 所以你看到的 Markdown 代码都没有被转义 264 | 265 | 可以到这里看看本文的 Markdown 源码是怎么写的: 266 | https://raw.githubusercontent.com/seognil/fe-foundation/master/docs/cs/markdown.md 267 | ```` 268 | ````` 269 | -------------------------------------------------------------------------------- /docs/note/21.tool-skills/31.introduction-to-terminal.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 命令行 简介 3 | date: 2019-11-09 18:25:16 4 | permalink: /workspace/introduction-to-terminal 5 | categories: 6 | - 开发环境 7 | tags: 8 | - 命令行 9 | - mac 10 | --- 11 | 12 | # 命令行 简介 13 | 14 | ## 什么是 命令行 15 | 16 | > 命令行界面(英语:Command-Line Interface,缩写:CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后,予以执行。也有人称之为字符用户界面(character user interface, CUI)。 17 | 18 | - [Computers 101: terminals, kernels and shells](https://www.integralist.co.uk/posts/terminal-shell/) 19 | - [终端、Shell、tty 和控制台(console)有什么区别?](https://www.zhihu.com/question/21711307) 20 | - [什麼是程序 (Process) - 鳥哥的 Linux 私房菜](http://linux.vbird.org/linux_basic/0440processcontrol.php) 21 | 22 | ## 打开和使用 命令行 23 | 24 | 打开系统自带的终端,然后使用命令行界面: 25 | 26 | - Mac(Terminal) 27 | - 按 Cmd+Space 打开 `Spotlight Search` 或 `聚焦搜索` 28 | - 键入 `terminal` 或 `终端` 29 | - 选择 `Terminal.app` 或 `终端` 启动 30 | - Windows(CMD 或 PowerShell) 31 | - 按 Win 键(或鼠标点击屏幕左下角的徽标),打开 Windows 菜单 32 | - 键入 `cmd` 或 `powershell` 33 | - 选择 `CMD` 或 `命令提示符` 或 `Windows PowerShell` 启动 34 | 35 | 将会启动一个黑色的窗口,然后: 36 | 37 | - 键入 `ls` 或 `dir` 并回车 38 | 39 | 这个命令将会在终端中,打印显示当前文件夹下的所有文件。 40 | 这样就完成了一个基本的命令行操作。 41 | 42 | 这是我的终端界面 ↓(参考下一篇文章 [打造趁手的终端](/workspace/terminal-settings)) 43 | 44 | ![iterm2](./iterm2-showcase.png) 45 | 46 | ## 为什么要使用 命令行 47 | 48 | - 很多优秀工具 _只有_ 或 _优先_ 提供命令行的版本(如 Node.js、Brew) 49 | - 命令行很方便 50 | - 相比定位鼠标,敲键盘可以直接通过肌肉记忆完成,鲁棒性高 51 | - 常用工作流可以封装成代码脚本,一组快捷键或几个字符就能轻松执行 52 | - 降低资源消耗(如远程登录) 53 | 54 | ## 命令行 相关 55 | 56 | ### 命令行 中的退出/中断 57 | 58 | 有一个著名的问题: 59 | [How To Exit Vim? Multiple Ways To Quit Vim Editor](https://itsfoss.com/how-to-exit-vim/) 60 | 61 | VI 或 VIM 是一个 Linux 上流行的命令行编辑器, 62 | 常用于远程登录时的文件编辑。 63 | 64 | 它的退出命令是通过键入 `:q` 并回车 65 | 66 | 其他不同工具的退出方式可能是以下几种之一: 67 | Ctrl+CCtrl+DQ、 68 | `exit`、`quit`、`exit()` 69 | 70 | ### 命令的帮助文档 71 | 72 | 一般来说,不可能记住所有命令的所有用法, 73 | 这时候,懂的如何查询文档就非常重要。 74 | 75 | 在命令行中,有以下几种查询方式: 76 | 77 | - 命令**内置**的 `help` 子命令, 78 | 用法例如: `git help`、`git --help`、`git add --help` 79 | - `man`:Unix 系统和 PowerShell **自带**的命令, 80 | 用法例如:`man ls` 81 | - `tldr`:一个需要 [安装](https://github.com/tldr-pages/tldr) 的工具,能够显示其他命令的**常见用法**, 82 | 用法例如:`tldr ls`、`tldr git`、`tldr git add` 83 | 84 | * [explainshell](https://explainshell.com/):一个在线解释网站,能够解释你输入的命令和参数 85 | 86 | ### 管道 87 | 88 | Unix 中有管道的概念,用于拼接不同命令, 89 | 将上一个命令的输出当做下一个命令的输入, 90 | 实现命令的组合运用。 91 | 92 | 命令的拼接有两种主要方式: 93 | 94 | [管道 (Unix)]() 95 | 下面 `ls` 和 `tail` 是两个独立的命令,`|` 是管道 96 | 97 | ```bash 98 | ls -l | tail -n 2 99 | ``` 100 | 101 | [xargs](https://zh.wikipedia.org/wiki/Xargs) 102 | 下面 `where` 和 `ls` 是两个命令,`xargs` 用于传递参数 103 | 104 | ```bash 105 | where bash | xargs ls -la 106 | ``` 107 | 108 | ### 环境变量 109 | 110 | 使用 terminal 时,每个新窗口都将基于系统环境变量和启动配置建立一个独立的会话, 111 | 所谓环境变量,也就是 `PATH`, 112 | 所谓启动配置,也就是 `~/.bashrc`、`~/.zshrc` 等配置文件, 113 | 114 | 任何未固化的数据和设定都将在窗口关闭后丢失, 115 | 所以需要根据需求自己调整配置文件。 116 | (参考后文中的提到的 `dotfile`) 117 | 118 | 有一个名为 `tmux` 的命令行工具,可以在一个窗口内显示和管理多个窗口(session) 119 | 120 | ### 术语解释 121 | 122 | - **Terminal**:终端,曾经指一类计算机硬件,现在泛指 Terminal emulator,也就是虚拟终端(一类软件) 123 | - **shell**:壳层,前接 Terminal、后接 Kernel 的一层接口,指终端软件启动后窗口中的看到的内容 124 | 125 | * **CLI**:Command-line interface,命令行界面 126 | * **GUI**:Graphical user interface,图形用户界面 127 | * **Unix-like**:泛指所有具有类似 Unix 表现和行为的系统。 128 | 129 | - **Kernel**:内核,系统底层代码 130 | - **console**:控制台,曾经指一类计算机硬件,现在泛指调试面板(如浏览器的) 131 | - **tty**:来源于 Teletypewriter 的缩写,指上世纪计算机硬件终端的打字机部分,现在泛指虚拟终端的输入界面 132 | - **session**:会话,指一组执行命令的环境,由虚拟终端提供。 133 | 创建多个会话(表现为多窗口或切换)可以并行处理不同任务。 134 | - **PATH**:环境变量,系统提供的配置入口,用于检索可执行文件 135 | 136 | * **dotfile**:泛指以 `'.'` 开头的文本文件,在 Unix-like 系统中是隐藏文件, 137 | 一般用作程序配置,例如:`.bashrc`,复制粘贴该文件即可直接同步配置 138 | - 一个高赞配置 [Mathias’s dotfiles](https://github.com/mathiasbynens/dotfiles) 139 | - 我的 [基本环境自动配置脚本(未完成)](https://github.com/seognil/dotfiles) 140 | * **rc**:常用于 dotfile 文件名的结尾,表示这是配置文件 141 | (rc 可解释为 runcom、run commands、runtime configuration 等) 142 | 如:`.bashrc、.zshrc、.npmrc` 143 | 144 | - **ping**:命令行中检查地址可访问性的工具,例如 `ping rualc.me` 145 | - **curl**:是 Client URL 的缩写,命令行中的地址访问工具,例如 `curl -L rualc.me` 146 | 147 | ### 不同的 shell 148 | 149 | 不同的 shell,语法有一些差别。 150 | 在选择自己的主力 shell 时,根据自己的喜好,以及需要注意兼容性。 151 | 152 | - [Introduction to if - Bash](http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html) 153 | - [Conditionals (If, Else, Switch) - Fish](https://fishshell.com/docs/current/tutorial.html#tut_conditionals) 154 | 155 | ```bash 156 | # bash 157 | function comp { 158 | local value=$1 159 | if [ $value -gt 100 ]; then 160 | echo "'$value' is in (100, Inf)" 161 | elif [ $value -gt 50 ]; then 162 | echo "'$value' is in (50, 100]" 163 | else 164 | echo "'$value' is in (-Inf, 50)" 165 | fi 166 | } 167 | 168 | # fish 169 | function comp 170 | set -l value $argv[0] 171 | if [ $value -gt 100 ] 172 | echo "'$value' is in (100, Inf)" 173 | else if [ $value -gt 50 ] 174 | echo "'$value' is in (50, 100]" 175 | else 176 | echo "'$value' is in (-Inf, 50)" 177 | end 178 | end 179 | ``` 180 | 181 | ### proxy 和 registry 182 | 183 | 对于网路,理解相关概念能够更好地运用它 184 | 185 | #### proxy 186 | 187 | proxy 是指“代理”,作用可能是以下之一 188 | 189 | - 授权访问(防火墙) 190 | - 加密通讯(安全性) 191 | - 节约网络流量(内网) 192 | - 网络质量优化(稳定性) 193 | 194 | #### registry 195 | 196 | 在命令行中下载工具,实际上是从某个地址传输数据。 197 | (如 `github.com`、`npmjs.org`) 198 | 199 | 根据自己的网络环境,进行“换源”操作,或许可以提高下载速度, 200 | 如调整 `brew remote`、`npm registry` 等。 201 | -------------------------------------------------------------------------------- /docs/note/21.tool-skills/32.terminal-settings.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 打造趁手的终端 3 | date: 2019-11-09 18:25:16 4 | permalink: /workspace/terminal-settings 5 | categories: 6 | - 开发环境 7 | tags: 8 | - 命令行 9 | - mac 10 | - zsh 11 | - brew 12 | --- 13 | 14 | # 打造趁手的终端 15 | 16 | ## 代理(proxy) 17 | 18 | 在上一篇文章 [命令行简介](/workspace/introduction-to-terminal) 中,我们提到代理有诸多好处,正确配置或能直接提高生产效率。给浏览器、软件、Terminal 或是其他工具配置代理,不同工具的配置方式可能不同。 19 | 20 | 对于 Terminal 来说是通过命令来配置(参考 [Set HTTP(s) Proxy in Windows Command Line / MAC Terminal](https://itectec.com/set-https-proxy-in-windows-command-line-environment/) 这篇文章): 21 | 22 | ```shell 23 | # 其中的 http://127.0.0.1:1080 改成自己的代理地址 24 | 25 | # mac 26 | export ALL_PROXY='http://127.0.0.1:1080' 27 | 28 | # windows 29 | set http_proxy='http://127.0.0.1:1080' 30 | set https_proxy='http://127.0.0.1:1080' 31 | ``` 32 | 33 | 可以根据需要到自己的 shell 配置文件(如 `~/.bashrc`、`~/.zshrc`)中,封装成函数,以便更方便地控制启用。 34 | 35 | ```bash 36 | # ~/.zshrc 37 | function proxyon() { 38 | export ALL_PROXY='http://127.0.0.1:1080' 39 | } 40 | 41 | function proxyoff() { 42 | unset ALL_PROXY 43 | } 44 | 45 | # (启动 shell 时)直接运行 proxyon,启用代理 46 | proxyon 47 | ``` 48 | 49 | 测试代理的连通性,可以在 terminal 中尝试用 `curl` 命令访问网站: 50 | 51 | ```shell 52 | curl google.com 53 | # curl zhihu.com 54 | # curl baidu.com 55 | ``` 56 | 57 | 如果能成功返回 HTML 结果,而不是无响应或错误信息,即说明配置有效: 58 | 59 | 60 | ```html 61 | 62 | 301 Moved 63 |

301 Moved

64 | The document has moved 65 | here. 66 | 67 | ``` 68 | 69 | ## Homebrew 70 | 71 | > 从命令行中安装工具和软件 72 | 73 | MacOS 生态有中有一个名为 [Homebrew](https://brew.sh/) 的命令行工具(需要额外安装) 74 | 75 | 它类似 Linux 中的 `apt` 或 `yum`,Windows 中的 [Chocolatey](https://chocolatey.org/)。 76 | 或类似 Node.js 的 `npm`、Python 的 `pip`、PHP 的 `composer` … 77 | 78 | 虽然上述各种工具是不同生态中的不同工具,但它们有一个共同点:通过命令行安装其他程序。不需要再通过浏览器手动点击下载,软件环境的配置过程能够更方便和高效。 79 | 80 | ### 安装 Homebrew 81 | 82 | (可以先调整好代理,这样 brew 的下载速度可能会更快。) 83 | 84 | [安装 Homebrew](https://brew.sh/): 85 | 86 | ```shell 87 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 88 | ``` 89 | 90 | 安装完成后在命令行中键入命令 `brew`,将会打印 brew 自带的帮助文档: 91 | 92 | ```shell 93 | Example usage: 94 | brew search TEXT|/REGEX/ 95 | brew info [FORMULA|CASK...] 96 | brew install FORMULA|CASK... 97 | brew update 98 | brew upgrade [FORMULA|CASK...] 99 | brew uninstall FORMULA|CASK... 100 | brew list [FORMULA|CASK...] 101 | 102 | Troubleshooting: 103 | brew config 104 | brew doctor 105 | brew install --verbose --debug FORMULA|CASK 106 | 107 | Contributing: 108 | brew create URL [--no-fetch] 109 | brew edit [FORMULA|CASK...] 110 | 111 | Further help: 112 | brew commands 113 | brew help [COMMAND] 114 | man brew 115 | https://docs.brew.sh 116 | ``` 117 | 118 | 然后我们尝试使用,例如 node 的安装卸载: 119 | 120 | ```shell 121 | brew install node 122 | brew uninstall node 123 | brew upgrade node 124 | brew info node 125 | ``` 126 | 127 | brew 整合了 formula(针对命令行工具如 `node`) 和 cask(针对 GUI 软件如 `visual-studio-code`)。 128 | 129 | ```shell 130 | brew install node 131 | brew install visual-studio-code 132 | brew list 133 | brew list --formula 134 | brew list --cask 135 | ``` 136 | 137 | #### (可选)安装 brew-cask-upgrade 138 | 139 | [brew-cask-upgrade](https://github.com/buo/homebrew-cask-upgrade) 是 `brew upgrade --cask` 的社区增强版工具。cask 默认的升级策略是跳过那些本身自带更新功能的软件,而 cu 的管理更细致。 140 | 141 | #### 小贴士:软件仓库 142 | 143 | 上述提到的管理工具本身都是下载管理工具,它们不保存第三方软件的安装包,而只是维护下载地址。如果某软件的下载地址不在维护列表内,无法检索到也就无法安装了。 144 | 145 | 这时候就需要设置额外的地址进行下载安装。 146 | (一般会借助 `sh`、`wget`、`curl` 等命令进行下载和安装) 147 | 148 | 例如在 Ubuntu 中安装 Node.js: 149 | 150 | ```shell 151 | sudo apt-get install -y nodejs 152 | ``` 153 | 154 | 默认的 apt 源并不维护最新的 Node.js 版本,所以如果需要安装较新的 _Node.js 16_,就需要进行额外配置(参考 [Installation instructions - NodeSource](https://github.com/nodesource/distributions/blob/master/README.md#debinstall) 这篇文章): 155 | 156 | ```shell 157 | curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - 158 | sudo apt-get install -y nodejs 159 | ``` 160 | 161 | ## 打造趁手的终端 {#zsh} 162 | 163 | 个人使用的命令行基本作业环境是:`iTerm2 + zsh + oh-my-zsh`,来代替 MacOS 自带的 `Terminal.app + bash` 方案。 164 | 165 | (另一个流行的配置集是:[Spaceship ZSH](https://github.com/denysdovhan/spaceship-prompt)) 166 | 167 | - [iTerm2](https://iterm2.com/):一个 terminal 168 | - `brew install iterm2` 169 | - [zsh](https://github.com/ohmyzsh/ohmyzsh/wiki/Installing-ZSH#how-to-install-zsh-on-many-platforms):一个 shell 170 | - `brew install zsh` 171 | - (安装完后会自动生成启动配置文件 `~/.zshrc`,可以在这个文件中进行深入定制) 172 | - [Oh My Zsh](https://github.com/ohmyzsh/ohmyzsh#getting-started):一个流行的 zsh 配置集 173 | - `sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"` 174 | - [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting/blob/master/INSTALL.md#oh-my-zsh):命令语法高亮插件 175 | - (这个是较新的版本,brew 源较旧)`git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting` 176 | - 修改 `~/.zshrc` 文件 `plugins=([...] zsh-syntax-highlighting)` 177 | - [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions/blob/master/INSTALL.md#oh-my-zsh):根据 history 的自动补全插件 178 | - (这个是较新的版本,brew 源较旧)`git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions` 179 | - 修改 `~/.zshrc` 文件 `plugins=([...] zsh-autosuggestions)` 180 | 181 | 接着可以参考我的另一篇文章 [Mac 和软件](/workspace/mac),安装一些其他的工具。 182 | 183 | ![iterm2-showcase](./iterm2-showcase.png) 184 | -------------------------------------------------------------------------------- /docs/note/21.tool-skills/iterm2-showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seognil/fe-foundation/74290e0ec2a3f0d8cea2c719c6e1dd21a3c2fbb0/docs/note/21.tool-skills/iterm2-showcase.png -------------------------------------------------------------------------------- /docs/note/99.about/about-me.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 关于我(2019) 3 | date: 2020-01-13 21:16:36 4 | permalink: /about/me 5 | categories: 6 | - 关于 7 | tags: 8 | - 关于我 9 | --- 10 | 11 | # 关于我(2019) 12 | 13 | ## 我自己 14 | 15 | 目前状态 16 | 17 | - 技能 18 | - 略懂点 JS 19 | - 写过些功能、优化和修复 20 | - 做过点架构改进: 21 | 公司 40 万行 JS 的老项目 22 | 从 ES5/jQuery/Backbone/Underscore/Require.js 23 | 到 TS/React Hooks/Redux/RxJS/Ramda/Webpack 24 | - 学习中 25 | - 修炼 TS 26 | - 学习现代化、工程化前端开发 27 | - 学习 CS 28 | - 其他 29 | - 写文章 30 | - 做了些技术文档翻译 31 | 32 | ## 价值产出 33 | 34 | 给 2019 年(工作以外的部分)做个小结吧 35 | 36 | ### 写文章 37 | 38 | > repo:[seognil/fe-foundation](https://github.com/seognil/fe-foundation) 39 | 40 | (从 2019/10 起)开始系统地写文章,目前有几个系列: 41 | 42 | - [前端入门指南系列](/note/frontend-development-cookbook) 43 | - [JavaScript 语言学习系列](/frontend/javascript-foundation) 44 | - [其他学习指南系列](/study/crash-course-study-skills) 45 | 46 | 主要的目的有两个: 47 | 48 | - 梳理自己的知识体系 49 | - 教朋友学前端 50 | 51 | 然而目前完成度可能只达到的 30% 52 | 还有很多篇没写、或者写了草稿没整理的 53 | ~~毕竟写得比朋友们学得快就好了(~~ 54 | 55 | 正式发布的文章: 56 | `cloc` 统计约 五千行 57 | `wc -m` 统计约 17 万字(符) 58 | 59 | 争取明年先完整写完(然后进入日常更新模式) 60 | 61 | ### 开源贡献 62 | 63 | > repo 分类:[seognil-contributor](https://github.com/seognil-contributor) 64 | 65 | #### 翻译和校对 66 | 67 | 完成的工作: 68 | 69 | - [2019 年 JavaScript 明星项目](https://risingstars.js.org/2019/zh):[翻译](https://github.com/bestofjs/javascript-risingstars/pull/49) 70 | - [2018 年 JavaScript 明星项目](https://risingstars.js.org/2018/zh):[翻译](https://github.com/bestofjs/javascript-risingstars/pull/39) 71 | - [The State of JavaScript 2019](https://2019.stateofjs.com/zh/):[翻译](https://github.com/StateOfJS/State-of-JS-2019/pull/50) 72 | - [约定式提交](https://www.conventionalcommits.org/zh-hans/v1.0.0-beta.4/):[校对](https://github.com/conventional-commits/conventionalcommits.org/pull/124)、[改进](https://github.com/conventional-commits/conventionalcommits.org/pull/126)、[版本更新](https://github.com/conventional-commits/conventionalcommits.org/pull/155) 73 | - [Typescript-Handbook](https://github.com/zhongsp/TypeScript):[翻译](https://github.com/zhongsp/TypeScript/pull/274)了 [TS 官方文档中的一章](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html) 74 | - [用 TypeScript 写 React & Redux - 完全指南](https://github.com/seognil-contributor/react-redux-typescript-guide):[翻译](https://github.com/piotrwitek/react-redux-typescript-guide/pull/199)(但还未合并) 75 | - [开始 – React 官方文档](https://zh-hans.reactjs.org/docs/getting-started.html):React 官方翻译计划几篇文章 [翻译和校对](https://github.com/reactjs/zh-hans.reactjs.org/pulls?q=is%3Apr+is%3Aclosed+author%3Aseognil) 76 | 77 | 原本目的有几个: 78 | 79 | - 了解 GitHub 社区(和开源项目协作流程) 80 | - 锻炼英语 81 | - 了解前端和相关生态的知识 82 | - (回馈社区) 83 | 84 | 但是做翻译实在太累了: 85 | 包括翻译和校对、理解和斟酌,尽力追求翻译质量。 86 | 导致我的产出速度大致是每小时一千(汉)字,太花时间了。 87 | 这么看收益还低: 88 | 仅对于学习来说,自己直接看英文版好像更有效率, 89 | 大致理解核心意思就行了,毕竟不用考虑分享就不用锱铢必较。 90 | 91 | (而且已经开始看硬核技术资料的人,英语水平应该也不会差,谁会去看汉化版呢…) 92 | 93 | 所以明年不准备搞了,多搞点代码层面的事情好像更有价值一点…… 94 | 95 | 96 | 97 | #### PR 98 | 99 | 做了一些微小的工作: 100 | 101 | - [给 AlloyFinger 修了一个 bug](https://github.com/AlloyTeam/AlloyFinger/pull/85) 102 | - [给 Homebrew cask 提了一个软件升级](https://github.com/Homebrew/homebrew-cask/pull/71677) 103 | 104 | 像上面说的,今年争取多搞点代码的事情。 105 | 106 | ### 造轮子 107 | 108 | > repo 分类:[seognil-lab](https://github.com/seognil-lab) 109 | 110 | 写了点业务中碰到的需求,放在 GitHub 和 npm 上。 111 | 都是些杂七杂八的小玩意儿,后来也没怎么维护和推广,所以基本没产生什么社区影响… 112 | (但是对于工程化的开发模式,基本算是入门并在内部推广了,还算有点收获) 113 | 114 | 部分轮子: 115 | 116 | - [webpack-starter](https://github.com/seognil-lab/webpack-starter) 117 | 已经落地。 118 | 全特性 Webpack 项目模板,作为内部项目技术升级的试验地。 119 | 但还有优化空间(比如热重载没完成) 120 | 121 | - [drag-resize-rotate](https://github.com/seognil-lab/drag-resize-rotate) 122 | 已经落地。 123 | 原本是给常见的 [DRR](https://www.npmjs.com/search?q=drag%20rotate) 功能设计的计算层, 124 | 这样就能方便地支持不同的 UI 层了(比如 jQuery/React/Vue)。 125 | 代码设计上还有优化空间。 126 | 127 | - [vector-math-fp](https://github.com/seognil-lab/vector-math-fp) 128 | 已经落地。 129 | 函数式风格的 2D 平面计算库, 130 | 用于几个内部功能,包括上一个提到的 [DRR](https://github.com/seognil-lab/drag-resize-rotate/blob/master/package.json#L66)。 131 | 132 | - [approx-fix](https://github.com/seognil-lab/approx-fix) 133 | 给 vector-math-fp 用的, 134 | 解决 IEEE 754 问题的快速方案。 135 | -------------------------------------------------------------------------------- /docs/note/99.about/about-the-guild.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 关于学习指南系列 3 | date: 2019-11-23 23:38:58 4 | permalink: /about/the-guild 5 | categories: 6 | - 关于 7 | tags: 8 | - 9 | --- 10 | 11 | # 关于学习指南系列 12 | 13 | ## TLDR 14 | 15 | 问:和网上其他的学习教程有什么**区别**? 16 | 17 | 答:这**不是教程**或文档,不包括详尽的知识细节和工具使用方法, 18 | 这**只是指南**,记录了我的学习路径,以及关键知识体系笔记。 19 | 其中包含了其他更详细的教程和技术文章的链接, 20 | 如果没有其他的那些优秀材料,我的指南也就毛将焉附。 21 | 22 | 指南的通常结构大致为: 23 | 24 | - 简介 25 | - 大量优质的学习材料链接 26 | - 我自己整理的结构化知识体系 27 | 28 | 具体参考 [学习指南模板](/study/study-guild-abstraction) 29 | 30 | ## 关于学习指南系列 31 | 32 | ### 背景 33 | 34 | 现在互联网资讯很发达,网络上系统的教程很多, 35 | 我没必要重复造轮子。(我也没这个本事呀 >\_<) 36 | 37 | 不过话说回来, 38 | 作为前端开发者,有谁入门 JS 的时候是直接从 [ECMA-262 官方文档](https://www.ecma-international.org/publications/standards/Ecma-262.htm) 开始的吗… 39 | 至少也是从 [JavaScript - MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript)、[JavaScript 标准参考教程](https://javascript.ruanyifeng.com/) 这样量级的简化版开始的。 40 | 41 | 但是这些文档怎么刷,哪些重点刷,刷完就够了么? 42 | (比如 JS 里的 [BigInt](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt) 是关键知识点吗) 43 | 44 | 这就引出了一个问题: 45 | 46 | > 在学习某个技能的时候,以什么方式从 0 到 1?(之后再从 1 到 Infinity) 47 | 48 | 对我来说,学习的难点不完全在于理解和掌握知识本身。 49 | 更重要的是,如何尽可能地花**更少的时间**理解**最核心的本质**并优先掌握**最实用的部分**。 50 | 51 | 现代化前端开发早已规模化和规范化,需要掌握的技能和工具层出不穷。 52 | 从经济角度看,不可能先花三年五年"精通"所有相关技术再创造工作价值。 53 | (何况说不定技术都更替了…) 54 | 并且在前端以外,还有那么多技术栈,以及丰富多彩的人类社会活动。 55 | 人生苦短 ~~我应该用 Python?~~ 56 | 57 | 我希望能够提高自己的成长速度,来面对这一状况。 58 | 我想,应该有一个合适的方法论来解答这个问题。 59 | 60 | ### 方法 61 | 62 | 基于上述种种,我逐渐学习和整理出了一个[方法论](/study/crash-course-study-skills): 63 | 对于学习任意工具,都能以某种[通用的套路](/study/study-guild-abstraction)完成, 64 | 并且尽可能地理解和掌握最核心的部分。(而不是只学会调 API) 65 | (也就是先解决所谓最难的从 0 到 1 的部分) 66 | 67 | 当完成了一定量基础训练后,形成了良好的技术储备和直觉, 68 | 余下的道路便会在前方自动呈现。 69 | 就有把握解决实际业务中碰到的更多更琐碎和具体的问题了。 70 | 71 | 当大致能够独立完成开发链路的大部分环节, 72 | 这时候,才是专攻和精进某些细分方向的好时机了。 73 | 74 | ### 目的 75 | 76 | 作为该方法论中的一部分, 77 | 我应该将一些内容整理成可查询和迭代的文档体系, 78 | 并且根据方法论的原则,只覆盖我理解的最核心的知识。 79 | 80 | 所以,我开始写"学习指南"系列。 81 | 这个系列基本的目标是: 82 | 83 | - 从 0 入门,并且只包含关键信息 84 | - 以此作为我自己知识体系的梳理 85 | - (能帮助释放我的工作记忆) 86 | 87 | * 顺便的,将经验分享给我的朋友和同事们 88 | * 再顺便的,可能有机会帮助到曾经和我一样迷茫的初学者们。 89 | 90 | 如果你已经学会了某些技术,心想:"我的~~画风~~技术在你之上" 91 | 那么我的这些经验对你来说或许就意义不大了~(毕竟定位差异) 92 | (但一般都会有进阶的部分,我觉得也还是值得一看的…) 93 | 94 | 做了一点微小的工作,谢谢:) 95 | 96 | ## 资料 97 | 98 | ### 我的其他文章 99 | 100 | - [学习方法论](/study/crash-course-study-skills) 101 | - [学习指南模板](/study/study-guild-abstraction) 102 | - [计算机科学入门指南](/cs/crash-course-computer-science) 103 | 104 | ### 学习编程的合理方式 105 | 106 | - [When and why to clean up your code: now, later, never](https://codewithoutrules.com/2018/11/02/when-clean-up-your-code/) 107 | - [我如何零基础转行成为一个自信的前端](https://www.yuque.com/fe9/basic/mchxkr) 108 | - [聊聊 2018 年我所不了解的技术](https://overreacted.io/zh-hans/things-i-dont-know-as-of-2018/) 109 | - [Why I'm so good at coding.](https://www.youtube.com/watch?v=xqgH9j3x2OE) 110 | - [My Story of Being a Self Taught Programmer (Plus Tips and Advice!)](https://www.youtube.com/watch?v=62tsiY5j4_0) 111 | -------------------------------------------------------------------------------- /docs/note/99.about/about-the-site.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 关于本站 3 | date: 2019-12-30 13:52:12 4 | permalink: /about/the-site 5 | categories: 6 | - 关于 7 | tags: 8 | - 9 | --- 10 | 11 | # 关于本站 12 | 13 | ## 系列文章 14 | 15 | 主要在写一些系列文章(更新中): 16 | 17 | - [前端入门指南系列](/note/frontend-development-cookbook) 18 | - [JavaScript 语言学习系列](/frontend/javascript-foundation) 19 | - [其他学习指南系列](/study/crash-course-study-skills) 20 | 21 | 还有一些其他的杂记。 22 | 23 | ## 特色 24 | 25 | - **从零入行前端开发**的学习路线 26 | - 推荐了**大量优秀学习教材**,形式包括视频、文档、书籍、笔记、题库 27 | - **拓宽视野,由浅入深** 28 | 29 | ## 支持 30 | 31 | 如果喜欢我的文章,可以 [到我的 GitHub 点个 ★ Star](https://github.com/seognil/fe-foundation) 支持一下 🎉 32 | 33 | ## 小记 34 | 35 | 近年来,前端已从最早的玩具发展为成体系的系统工程开发, 36 | 逐步赶上了传统软件开发和编程领域的步伐。 37 | 38 | 现在做前端开发,在真正开始写第一行业务代码之前, 39 | 需要很多前置的技术储备,并学习很多工具。 40 | 41 | 前端内的技术教程千千万, 42 | ~~(比如之前在掘金,关于 EventLoop 的文章每个月看到八百遍)~~ 43 | 但是我 _很少_ 看到国内有文章系统地介绍: 44 | 一个现代化的前端工程应该从哪里开始入门和起步, 45 | 在前端体系之外、之前,应该要做,或最好要做什么事情。 46 | 在前端体系之后,还可以做哪些事情,向何处发展。 47 | 48 | 本系列根据我的工作经历,以及各路资料整理而成。 49 | 目标是,在有限的篇幅中,对前端开发的职业规划做一个向导, 50 | 一个只有一台干净电脑(Mac)的新手,如何从零学习并从事前端开发的工作。 51 | 52 | 所基于的开发环境是 MacOS。 53 | (Windows 和 Linux 有部分是相同的,另一部分是有替代方案的) 54 | 55 | 当然,有很多更全面的资料, 56 | 比我有限的人生经验不知道高到哪里去了, 57 | 这些参考资料的链接对应地分散在各个章节中。 58 | 希望对各位读者有所帮助。 59 | 60 | 根据自己的实际情况,**学以致用,循序渐进**,这是坠吼的。 61 | 62 | > —— 此系列写给我的朋友 东神、阿辉 63 | -------------------------------------------------------------------------------- /docs/note/99.about/ref.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mantras 3 | date: 2019-08-08 18:36:05 4 | permalink: /about/ref.html 5 | categories: 6 | - 草稿 7 | tags: 8 | - 9 | --- 10 | 11 | ## Mantras 12 | 13 | > Every Expert Was Once A Beginner. 14 | 15 | > Sic Parvis Magna 16 | > -- Uncharted 4: A Thief's End (2016) 17 | 18 | > Do not be sorry. Be better. 19 | > -- God Of War (2018) 20 | 21 | > a delayed game is eventually good, but a rushed game is forever bad. 22 | > -- Shigeru Miyamoto 宮本 茂 23 | 24 | > 枯れた技術の水平思考 25 | > -- Gunpei Yokoi 横井 軍平 26 | 27 | > Victory Loves Preparation 28 | > -- The Mechanic (2011) 29 | 30 | > Fortis Fortuna Adiuvat 31 | > -- John Wick (2014) 32 | 33 | > Art is pain, life is suffering. 34 | > -- John Wick 3 (2019) 35 | 36 | > Judge less, Observe more 37 | 38 | > The journey is hard and joyful. 39 | > -- HUAWEI 40 | 41 | > Stay hungry, stay foolish 42 | > -- Steve Jobs 43 | 44 | > KEEP CALM AND CALM DOWN 45 | 46 | > 取法其上,得乎其中。取法其中,得乎其下。 47 | > -- 孔子 48 | 49 | > Plato is dear to me, but dearer still is truth. 50 | > -- Aristotle 51 | 52 | > Always learn from the best! 53 | 54 | > Happy Smart Useful 55 | > -- https://sivers.org/hsu 56 | 57 | > Environment Body Mind 58 | > -- https://qotoqot.com/blog/improving-focus/ 59 | 60 | > I hear & I forget. I see & I remember. I do & I understand. 61 | 62 | > Fail Fast, Fail Cheap, Move On. 63 | 64 | > MAKE EPIC SHIT 65 | > -- Evan You 66 | 67 | > Coding With Good Taste 68 | > -- Linus Torvalds 69 | 70 | > Write code that is easy to delete, not easy to extend. 71 | > -- https://programmingisterrible.com/ 72 | 73 | > If you're willing to restrict the flexibility of your approach, 74 | > you can almost always do something better. 75 | > -- John Carmack 76 | 77 | ## 资料(未整理) 78 | 79 | [npm rank](https://gist.github.com/anvaka/8e8fa57c7ee1350e3491) 80 | 81 | [JavaScript 算法与数据结构](https://github.com/trekhleb/javascript-algorithms/blob/master/README.zh-CN.md) 82 | [LeetCode](https://leetcode.com) 83 | 84 | [前端面试每日 3+1(每日三问)](https://github.com/haizlin/fe-interview/blob/master/category/history.md) 85 | [MuYunyun/blog](https://github.com/MuYunyun/blog) 86 | -------------------------------------------------------------------------------- /docs/note/frontend-development-cookbook.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 我的 Web 前端开发知识体系 (2022) 3 | date: 2022-01-29 17:46:00 4 | permalink: /note/frontend-development-cookbook 5 | categories: 6 | - 草稿 7 | tags: 8 | - awesome 9 | --- 10 | 11 | # 我的 Web 前端开发知识体系 (2022) {.cookbook-page} 12 | 13 | --- 14 | 15 | ## 写在前面 16 | 17 | ### Roadmap 资源和技术趋势 18 | 19 | - [JavaScript Rising Stars](https://risingstars.js.org/) 20 | - [Frontend Developer Roadmap](https://roadmap.sh/frontend) 21 | - [State Of JS](https://stateofjs.com/) 22 | - [State Of CSS](https://stateofcss.com/) 23 | - [Web Development In 2022 - A Practical Guide](https://www.youtube.com/watch?v=EqzUcMzfV1w) 24 | - [Programming & Web Development Crash Courses - Traversy Media](https://www.youtube.com/playlist?list=PLillGF-RfqbYeckUaD1z6nviTp31GLTH8) 25 | 26 | ### 我的索引 27 | 28 | - [装了啥](/workspace/awesome-tools) 29 | - [我都从哪学习](/study/where-do-i-learn-from) 30 | - [看了啥](/study/my-reading-list/) 31 | - [学习技巧](/study/crash-course-study-skills) 32 | - [英语](/study/using-english) 33 | 34 | ### 基本开发环境 35 | 36 | - [Mac](/workspace/mac) 37 | - [Chrome](/workspace/chrome) 38 | - [VS Code](/workspace/vscode) 39 | 40 | ## Web 前端 41 | 42 | - [硬核前端(劝退篇)](/frontend/frontend-hardcore-overview) 43 | 44 | ### 前端技术基础 45 | 46 | - [HTML](/frontend/html) 47 | - [CSS](/frontend/css) 48 | - [JavaScript](/cs/javascript-language-basic) 49 | - [TypeScript](/cs/typescript-language-basic) 50 | - [Node.js](/frontend/nodejs-basic) 51 | 52 | ### JavaScript 53 | 54 | - [JavaScript 学习指南 \*](/frontend/javascript-foundation) 55 | - [JavaScript 简介](/frontend/introduction-to-javascript) 56 | - [运行 JavaScript 代码的十几种方式](/frontend/how-to-run-javascript-code) 57 | - [JavaScript 进阶指南 \*](/frontend/javascript-advanced) 58 | - [语法糖、操作符、关键字、特性](/frontend/syntactic-sugar-in-javascript) 59 | - [前端模块化](/frontend/javascript-modules) 60 | - [正则表达式 学习指南](/frontend/javascript-regular-expression) 61 | - [JS Foundation \*](/frontend/javascript-foundation-legacy-version) 62 | 63 | ### npm 和工具 64 | 65 | - [npm](/frontend/introduction-to-npm) 66 | - [用 Proxy 进一步提高 npm 安装速度](/frontend/speeding-up-npm-install) 67 | - [使用 verdaccio 搭建私有 npm 仓库](/frontend/set-up-a-private-npm-registry-using-verdaccio) 68 | 69 | ### React/脚手架 70 | 71 | - [React](/frontend/react-hooks) 72 | - Vite 73 | - Next.js 74 | 75 | ### 规范化 76 | 77 | - ES Lint 78 | - Prettier 79 | - tsconfig.json 80 | - Husky 81 | 82 | ### 状态管理工具 83 | 84 | - Recoil.js 85 | - Mobx 86 | - [RxJS](/frontend/rxjs) 87 | - [Redux](/frontend/redux) 88 | 89 | ### CSS 工具 90 | 91 | - Tailwind / Twind 92 | - @emotion/css 93 | 94 | ### 测试 95 | 96 | - Playwright 97 | - [Jest](/frontend/jest) 98 | - [testing-library](/frontend/testing-library) 99 | - [Cypress](/frontend/cypress) 100 | 101 | ### 部署 102 | 103 | - Github 104 | - Vercel 105 | 106 | ## 其他 107 | 108 | ### 计算机科学 109 | 110 | - [计算机科学](/cs/crash-course-computer-science) 111 | - [函数式编程](/cs/introduction-to-functional-programming) 112 | - 数据结构/算法 113 | - 设计模式 114 | 115 | ### 实用工具 116 | 117 | - [Git](/cs/git) 118 | - [Markdown](/cs/markdown) 119 | - [终端](/workspace/introduction-to-terminal) 120 | - [打造趁手的终端](/workspace/terminal-settings) 121 | - [Python](/cs/python-language-basic) 122 | 123 | ### 杂谈 124 | 125 | - [游戏环境研究笔记(2022-01)](/misc/gaming-set/) 126 | - [用快捷键控制视频播放](/workspace/my-video-player-shortcuts) 127 | - [代码行数统计工具小测](/cs/count-lines-of-code) 128 | - [Ubuntu 服务器基本防护](/misc/linux-basic-security) 129 | - [如何清洁机械键盘](/misc/clean-a-keyboard) 130 | - [关于学习指南系列](/about/the-guild) 131 | - [杂谈:你可学点好吧](/study/dont-waste-your-time-and-money) 132 | - [杂谈:我们为什么需要读书和学习](/study/why-we-need-to-study) 133 | - [关于学习的鸡汤](/study/study-fortune) 134 | 135 | ## 你可以看什么大佬 136 | 137 | - [Anthony Fu](https://github.com/antfu) 138 | - [EGOIST](https://github.com/egoist) 139 | - [Sindre Sorhus](https://github.com/sindresorhus) 140 | 141 | ### (Phodal 写的系列文章) 142 | 143 | - [黄峰达(Phodal Huang) 是谁](https://www.phodal.com/about/) 144 | 145 | * [Phodal's Idea 实战指南](http://ideabook.phodal.com/) 146 | * [GitHub 漫游指南](http://github.phodal.com/) 147 | * [Growth - an app to help you Be Awesome Developer](http://growth.ren/) 148 | * [Growth: 全栈增长工程师指南](https://growth.phodal.com/) 149 | * [Growth: 全栈增长工程师实战](http://growth-in-action.phodal.com/) 150 | * [RePractise](http://repractise.phodal.com/) 151 | * [我的职业是前端工程师](https://ued.party/) 152 | * [Serverless 应用开发指南](http://serverless.ink/) 153 | * [写给软件工程师看的硬件编程指南](https://phodal.github.io/make/) 154 | * [Thinking in Microfrontend (微前端的那些事儿)](https://microfrontends.cn/) 155 | * [系统重构与迁移指南](https://migration.ink/) 156 | * [Developer 进阶书单](https://phodal.github.io/booktree/) 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 183 | -------------------------------------------------------------------------------- /google3ceb9a355a21cbf4.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google3ceb9a355a21cbf4.html -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fe-foundation", 3 | "version": "0.0.0", 4 | "description": "", 5 | "license": "MIT", 6 | "author": "seognil", 7 | "repository": "seognil/fe-foundation", 8 | "publishConfig": { 9 | "registry": "https://prevent.push.to.registry/" 10 | }, 11 | "keywords": [], 12 | "bugs": "https://github.com/seognil/fe-foundation/issues", 13 | "homepage": "https://github.com/seognil/fe-foundation", 14 | "scripts": { 15 | "build": "vuepress build ./docs", 16 | "dev": "vuepress dev ./docs", 17 | "start": "npm run dev", 18 | "preview": "npm run build && serve ./public", 19 | "check-md": "tsup scripts/check-broken-links.ts && node dist/check-broken-links.js", 20 | "redirect": "tsup scripts/update-config-files.ts && node dist/update-config-files.js" 21 | }, 22 | "dependencies": { 23 | "dayjs": "^1.11.6", 24 | "markdown-it-attrs": "^4.1.4", 25 | "transliteration": "^2.3.5", 26 | "vuepress": "^1.9.7", 27 | "vuepress-plugin-medium-zoom": "^1.1.9", 28 | "vuepress-plugin-zooming": "^1.1.8", 29 | "vuepress-theme-vdoing": "^1.12.8" 30 | }, 31 | "devDependencies": { 32 | "@types/markdown-it-attrs": "^4.1.0", 33 | "@types/node": "^17.0.45", 34 | "@types/prettier": "^2.7.1", 35 | "chalk": "^5.1.2", 36 | "globby": "^12.2.0", 37 | "https-proxy-agent": "^5.0.1", 38 | "node-fetch": "^3.3.0", 39 | "ora": "^6.1.2", 40 | "p-limit": "^4.0.0", 41 | "prettier": "^2.7.1", 42 | "prettier-plugin-organize-imports": "^2.3.4", 43 | "serve": "^13.0.4", 44 | "tsup": "^5.12.9", 45 | "typescript": "^4.9.3" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /scripts/301-record.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * first route is the latest route 3 | * 4 | * [ 5 | * to: 6 | * from: 7 | * from: 8 | * ] 9 | * 10 | */ 11 | export const redirectRecords: string[][] = [ 12 | // * ---------------- 13 | 14 | [ 15 | // 16 | '/note/frontend-development-cookbook', 17 | '/note/fe-development-cookbook-old', 18 | '/note/fe-development-cookbook', 19 | '/note/frontend-development-cookbook.html', 20 | ], 21 | 22 | // * ---------------- study 23 | 24 | [ 25 | // 26 | '/study/where-do-i-learn-from', 27 | '/about/where-do-i-learn-from', 28 | '/note/my-reading.html', 29 | ], 30 | 31 | // * ---------------- study 32 | 33 | [ 34 | // 35 | '/study/crash-course-study-skills', 36 | '/note/study-methodology.html', 37 | ], 38 | 39 | [ 40 | // 41 | '/study/using-english', 42 | '/note/english-using.html', 43 | ], 44 | [ 45 | // 46 | '/study/study-fortune', 47 | '/note/study-fortune.html', 48 | ], 49 | [ 50 | // 51 | '/study/study-guild-abstraction', 52 | '/note/study-guild-abstraction.html', 53 | ], 54 | [ 55 | // 56 | '/study/why-we-need-to-study', 57 | '/study/study-the-only-way', 58 | '/note/study-the-only-way.html', 59 | ], 60 | [ 61 | // 62 | '/study/dont-waste-your-time-and-money', 63 | '/study/study-the-costly-way', 64 | '/note/study-the-costly-way.html', 65 | ], 66 | 67 | // * ---------------- workspace 68 | 69 | [ 70 | // 71 | '/workspace/awesome-tools', 72 | '/note/my-workstation.html', 73 | ], 74 | [ 75 | // 76 | '/workspace/mac', 77 | '/note/mac.html', 78 | ], 79 | [ 80 | // 81 | '/workspace/chrome', 82 | '/note/chrome.html', 83 | ], 84 | [ 85 | // 86 | '/workspace/vscode', 87 | '/note/vscode.html', 88 | ], 89 | [ 90 | // 91 | '/workspace/introduction-to-terminal', 92 | '/note/terminal-intro.html', 93 | ], 94 | [ 95 | // 96 | '/workspace/terminal-settings', 97 | '/note/terminal-config.html', 98 | ], 99 | [ 100 | // 101 | '/workspace/my-video-player-shortcuts', 102 | '/note/video-hotkey.html', 103 | ], 104 | 105 | // * ---------------- cs 106 | 107 | [ 108 | // 109 | '/cs/crash-course-computer-science', 110 | '/note/computer-science.html', 111 | ], 112 | [ 113 | // 114 | '/cs/introduction-to-functional-programming', 115 | '/note/functional-programming.html', 116 | ], 117 | [ 118 | // 119 | '/cs/git', 120 | '/note/git.html', 121 | ], 122 | [ 123 | // 124 | '/cs/markdown', 125 | '/note/markdown.html', 126 | ], 127 | [ 128 | // 129 | '/cs/count-lines-of-code', 130 | '/note/cloc.html', 131 | ], 132 | [ 133 | // 134 | '/cs/javascript-language-basic', 135 | '/note/js-basic', 136 | ], 137 | [ 138 | // 139 | '/cs/typescript-language-basic', 140 | '/note/typescript.html', 141 | ], 142 | [ 143 | // 144 | '/cs/python-language-basic', 145 | '/note/python-language-basic', 146 | ], 147 | 148 | // * ---------------- frontend 149 | 150 | [ 151 | // 152 | '/frontend/frontend-hardcore-overview', 153 | '/note/fe-hardcore-overview.html', 154 | ], 155 | [ 156 | // 157 | '/frontend/html', 158 | '/note/html.html', 159 | ], 160 | [ 161 | // 162 | '/frontend/css', 163 | '/note/css.html', 164 | ], 165 | [ 166 | // 167 | '/frontend/javascript-foundation', 168 | '/note/js-foundation.html', 169 | ], 170 | [ 171 | // 172 | '/frontend/introduction-to-javascript', 173 | '/note/js-intro.html', 174 | ], 175 | [ 176 | // 177 | '/frontend/how-to-run-javascript-code', 178 | '/note/how-to-run-js.html', 179 | ], 180 | [ 181 | // 182 | '/frontend/javascript-advanced', 183 | '/note/js-advanced.html', 184 | ], 185 | [ 186 | // 187 | '/frontend/syntactic-sugar-in-javascript', 188 | '/note/syntactic-sugar.html', 189 | ], 190 | [ 191 | // 192 | '/frontend/javascript-modules', 193 | '/note/js-modular.html', 194 | ], 195 | [ 196 | // 197 | '/frontend/javascript-regular-expression', 198 | '/note/regexp.html', 199 | ], 200 | [ 201 | // 202 | '/frontend/javascript-foundation-legacy-version', 203 | '/note/js-foundation-old.html', 204 | ], 205 | [ 206 | // 207 | '/frontend/nodejs-basic', 208 | '/note/node-basic.html', 209 | ], 210 | [ 211 | // 212 | '/frontend/introduction-to-npm', 213 | '/note/npm-overview.html', 214 | ], 215 | [ 216 | // 217 | '/frontend/speeding-up-npm-install', 218 | '/note/npm-speedup.html', 219 | ], 220 | [ 221 | // 222 | '/frontend/set-up-a-private-npm-registry-using-verdaccio', 223 | '/note/npm-verdaccio.html', 224 | ], 225 | [ 226 | // 227 | '/frontend/rxjs', 228 | '/note/rxjs.html', 229 | ], 230 | [ 231 | // 232 | '/frontend/redux', 233 | '/note/redux.html', 234 | ], 235 | [ 236 | // 237 | '/frontend/react-hooks', 238 | '/note/react-hooks.html', 239 | ], 240 | [ 241 | // 242 | '/frontend/redux-observable', 243 | '/note/redux-observable.html', 244 | ], 245 | [ 246 | // 247 | '/frontend/jest', 248 | '/note/jest.html', 249 | ], 250 | [ 251 | // 252 | '/frontend/testing-library', 253 | '/note/testing-library.html', 254 | ], 255 | [ 256 | // 257 | '/frontend/cypress', 258 | '/note/cypress.html', 259 | ], 260 | 261 | // * ---------------- misc 262 | 263 | [ 264 | // 265 | '/misc/linux-basic-security', 266 | '/note/linux-basic-security.html', 267 | ], 268 | [ 269 | // 270 | '/misc/clean-a-keyboard', 271 | '/note/clean-keyboard.html', 272 | ], 273 | 274 | // * ---------------- about 275 | 276 | [ 277 | // 278 | '/about/the-site', 279 | '/note/readme.html', 280 | ], 281 | [ 282 | // 283 | '/about/me', 284 | '/about/', 285 | ], 286 | [ 287 | // 288 | '/about/the-guild', 289 | '/note/about-the-guild.html', 290 | ], 291 | ]; 292 | -------------------------------------------------------------------------------- /scripts/check-broken-links.ts: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import { readFile } from 'fs/promises'; 3 | import { globbySync } from 'globby'; 4 | import HttpsProxyAgent from 'https-proxy-agent'; 5 | import fetch from 'node-fetch'; 6 | import ora from 'ora'; 7 | import pLimit from 'p-limit'; 8 | import { resolve } from 'path'; 9 | 10 | const { blue, red, yellow } = chalk; 11 | 12 | const projRoot = resolve(process.cwd()); 13 | 14 | const files = globbySync('docs/**/*.md', { cwd: projRoot }).filter((e) => !e.includes('@pages')); 15 | 16 | // * ================================================================================ 17 | 18 | interface ParseUnit { 19 | mdlink: string; 20 | text: string; 21 | url: string; 22 | source: string; 23 | } 24 | 25 | const task = async () => { 26 | const contents = await Promise.all( 27 | files.map(async (e) => { 28 | const source = resolve(projRoot, e); 29 | const content = await readFile(source, { encoding: 'utf8' }); 30 | return { content, source }; 31 | }), 32 | ); 33 | 34 | // * ---------------- 35 | 36 | const permalinks = contents 37 | .map(({ content }) => content.match(/\npermalink: (.*)\n/)?.[1]) 38 | .filter((e) => e); 39 | 40 | // * ---------------- 41 | 42 | const flattenLinks: ParseUnit[] = contents 43 | .map(({ content, source }) => { 44 | return { source, mdlinks: [...(content.match(/\[[^\]]+\]\([^\)]+\)/g) ?? [])] }; 45 | }) 46 | .map(({ source, mdlinks }) => mdlinks.map((mdlink) => ({ mdlink, source }))) 47 | .flat(1) 48 | .map(({ mdlink, source }) => { 49 | const [_, text, url] = mdlink.match(/\[([^\]]+)\]\(([^\)]+)\)/)!; 50 | return { mdlink, text, url, source }; 51 | }) 52 | .sort((a, b) => (a.url < b.url ? -1 : 1)); 53 | 54 | const allLinks = Array.from(new Set(flattenLinks.map((e) => e.url))); 55 | 56 | const httpLinks = allLinks.filter((e) => /^https?:/.test(e)); 57 | const anchorLinks = allLinks.filter((e) => /^#/.test(e)); 58 | const mdLinks = allLinks.filter((e) => /^\//.test(e)); 59 | const mdPureLinks = mdLinks.map((e) => e.replace(/#.*/, '')); 60 | const otherLinks = allLinks 61 | .filter((e) => !httpLinks.includes(e)) 62 | .filter((e) => !anchorLinks.includes(e)) 63 | .filter((e) => !mdPureLinks.includes(e)); 64 | 65 | console.log('other links ----------------', otherLinks); 66 | 67 | // console.log('other links ----------------', anchorLinks); 68 | 69 | // * ---------------- md pure links check 70 | 71 | const badMdLinks = mdPureLinks.filter((e) => !permalinks.includes(e)); 72 | error(badMdLinks, flattenLinks); 73 | 74 | // * ---------------- http links check 75 | 76 | // await checkHtml(httpLinks, flattenLinks); 77 | }; 78 | 79 | // * ---------------------------------------------------------------- 80 | 81 | task(); 82 | 83 | // * ================================================================================ 84 | 85 | const error = (urls: string[], flattenLinks: ParseUnit[]) => { 86 | const list = urls.map((url) => flattenLinks.find((e) => e.url === url)); 87 | console.log('bad links ----------------'); 88 | list.forEach((e) => console.warn(`${blue(e?.source)}: ${red(e?.mdlink)}`)); 89 | }; 90 | 91 | // * ================================================================================ 92 | 93 | const checkHtml = async (urls: string[], flattenLinks: ParseUnit[]) => { 94 | const limit = pLimit(8); 95 | 96 | const spinner = ora('Checking Urls').start(); 97 | 98 | const proxyAgent = HttpsProxyAgent(process.env.ALL_PROXY!); 99 | 100 | console.log('bad links ----------------'); 101 | 102 | await Promise.all( 103 | urls 104 | .sort(() => Math.random() - 0.5) 105 | // .slice(0, 5) 106 | .map((url) => 107 | limit(async () => { 108 | spinner.text = url; 109 | return fetch(url, { agent: proxyAgent }) 110 | .then((res) => { 111 | const code = res.status; 112 | const result = { url, code }; 113 | 114 | // * asap // Seognil LC 2021/09/30 115 | if (code !== 200) { 116 | spinner.text = ''; 117 | spinner.render(); 118 | 119 | const e = flattenLinks.find((e) => e.url === url); 120 | console.log(`${blue(e?.source)}: ${red(e?.mdlink)} - ${yellow(code)}`); 121 | 122 | spinner.text = url; 123 | } 124 | 125 | return result; 126 | }) 127 | .catch((err) => { 128 | spinner.text = ''; 129 | spinner.render(); 130 | 131 | const e = flattenLinks.find((e) => e.url === url); 132 | console.log(`${blue(e?.source)}: ${red(e?.mdlink)} - ${yellow(err)}`); 133 | 134 | spinner.text = url; 135 | return null; 136 | }); 137 | }), 138 | ), 139 | ); 140 | 141 | spinner.stop(); 142 | }; 143 | -------------------------------------------------------------------------------- /scripts/list-notes.ts: -------------------------------------------------------------------------------- 1 | import { readFile } from 'node:fs/promises'; 2 | import { join, relative } from 'node:path'; 3 | import { globby } from 'globby'; 4 | 5 | const docDir = join(__dirname, '../docs/'); 6 | 7 | const files = await globby(join(docDir, 'note/**/*.md')); 8 | 9 | const getTitleAndLink = async (filePath: string) => { 10 | const content = await readFile(filePath, 'utf-8'); 11 | 12 | const headPieces = content.split('\n').slice(0, 5).join('\n'); 13 | const title = headPieces.match(/title:\s?(.*)/)?.[1]; 14 | const permalink = headPieces.match(/permalink:\s?(.*)/)?.[1]; 15 | const relativePath = relative(docDir, filePath); 16 | return { title, permalink, filePath, relativePath }; 17 | }; 18 | 19 | const titleAndLines = await Promise.all(files.map(getTitleAndLink)); 20 | 21 | console.log(titleAndLines.map(({ title, permalink }) => `[${title}](${permalink})`).join('\n')); 22 | -------------------------------------------------------------------------------- /scripts/update-config-files.ts: -------------------------------------------------------------------------------- 1 | import { writeFileSync } from 'fs'; 2 | import { resolve } from 'path'; 3 | import { redirectRecords } from './301-record'; 4 | 5 | // * ================================================================================ 6 | 7 | const projRoot = resolve(process.cwd()); 8 | 9 | // * ================================================================================ 10 | 11 | interface FlattenRedirect { 12 | to: string; 13 | from: string; 14 | } 15 | 16 | const flattenList: FlattenRedirect[] = redirectRecords 17 | .sort((a, b) => (a[0] < b[0] ? -1 : 1)) 18 | .map((routes) => { 19 | const [to, ...from] = routes; 20 | return from 21 | .sort((a, b) => (a < b ? -1 : 1)) 22 | .map((oldUrl) => [ 23 | { to, from: oldUrl + '.html' }, 24 | { to, from: oldUrl }, 25 | ]); 26 | }) 27 | .flat(2) 28 | .map(({ to, from }) => ({ to, from: from.replace('/.html', '/index.html') })) 29 | .filter((e) => !e.from.includes('.html.html')) 30 | .filter((e) => e.to !== e.from); 31 | 32 | // * ---------------------------------------------------------------- vue 33 | 34 | interface VuepressRedirect { 35 | path: string; 36 | redirect: string; 37 | } 38 | 39 | const vueRedirectList: VuepressRedirect[] = flattenList.map(({ to, from }) => ({ 40 | path: from, 41 | redirect: to, 42 | })); 43 | 44 | writeFileSync( 45 | resolve(projRoot, './docs/.vuepress/vue-redirect.js'), 46 | `module.exports = ${JSON.stringify(vueRedirectList, null, 2)}`, 47 | ); 48 | 49 | // * ---------------------------------------------------------------- public 50 | 51 | const _redirects = flattenList.map(({ from, to }) => `${from} ${to} 301`).join('\n'); 52 | writeFileSync(resolve(projRoot, './docs/.vuepress/public/_redirects'), _redirects); 53 | 54 | // * ---------------------------------------------------------------- vercel 55 | 56 | const vercelJson = JSON.stringify( 57 | { 58 | github: { silent: true }, 59 | redirects: flattenList.map(({ from, to }) => ({ 60 | source: from, 61 | destination: to, 62 | statusCode: 301, 63 | })), 64 | }, 65 | null, 66 | 2, 67 | ); 68 | writeFileSync(resolve(projRoot, './vercel.json'), vercelJson); 69 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "jsx": "preserve", 6 | "moduleResolution": "node", 7 | "strict": true, 8 | "alwaysStrict": true, 9 | "noImplicitAny": true, 10 | "noImplicitThis": true, 11 | "noImplicitReturns": true, 12 | "esModuleInterop": true, 13 | "declaration": true, 14 | "sourceMap": true, 15 | }, 16 | } -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "github": { 3 | "silent": true 4 | }, 5 | "redirects": [ 6 | { 7 | "source": "/about/index.html", 8 | "destination": "/about/me", 9 | "statusCode": 301 10 | }, 11 | { 12 | "source": "/about/", 13 | "destination": "/about/me", 14 | "statusCode": 301 15 | }, 16 | { 17 | "source": "/note/about-the-guild.html", 18 | "destination": "/about/the-guild", 19 | "statusCode": 301 20 | }, 21 | { 22 | "source": "/note/readme.html", 23 | "destination": "/about/the-site", 24 | "statusCode": 301 25 | }, 26 | { 27 | "source": "/note/cloc.html", 28 | "destination": "/cs/count-lines-of-code", 29 | "statusCode": 301 30 | }, 31 | { 32 | "source": "/note/computer-science.html", 33 | "destination": "/cs/crash-course-computer-science", 34 | "statusCode": 301 35 | }, 36 | { 37 | "source": "/note/git.html", 38 | "destination": "/cs/git", 39 | "statusCode": 301 40 | }, 41 | { 42 | "source": "/note/functional-programming.html", 43 | "destination": "/cs/introduction-to-functional-programming", 44 | "statusCode": 301 45 | }, 46 | { 47 | "source": "/note/js-basic.html", 48 | "destination": "/cs/javascript-language-basic", 49 | "statusCode": 301 50 | }, 51 | { 52 | "source": "/note/js-basic", 53 | "destination": "/cs/javascript-language-basic", 54 | "statusCode": 301 55 | }, 56 | { 57 | "source": "/note/markdown.html", 58 | "destination": "/cs/markdown", 59 | "statusCode": 301 60 | }, 61 | { 62 | "source": "/note/python-language-basic.html", 63 | "destination": "/cs/python-language-basic", 64 | "statusCode": 301 65 | }, 66 | { 67 | "source": "/note/python-language-basic", 68 | "destination": "/cs/python-language-basic", 69 | "statusCode": 301 70 | }, 71 | { 72 | "source": "/note/typescript.html", 73 | "destination": "/cs/typescript-language-basic", 74 | "statusCode": 301 75 | }, 76 | { 77 | "source": "/note/css.html", 78 | "destination": "/frontend/css", 79 | "statusCode": 301 80 | }, 81 | { 82 | "source": "/note/cypress.html", 83 | "destination": "/frontend/cypress", 84 | "statusCode": 301 85 | }, 86 | { 87 | "source": "/note/fe-hardcore-overview.html", 88 | "destination": "/frontend/frontend-hardcore-overview", 89 | "statusCode": 301 90 | }, 91 | { 92 | "source": "/note/how-to-run-js.html", 93 | "destination": "/frontend/how-to-run-javascript-code", 94 | "statusCode": 301 95 | }, 96 | { 97 | "source": "/note/html.html", 98 | "destination": "/frontend/html", 99 | "statusCode": 301 100 | }, 101 | { 102 | "source": "/note/js-intro.html", 103 | "destination": "/frontend/introduction-to-javascript", 104 | "statusCode": 301 105 | }, 106 | { 107 | "source": "/note/npm-overview.html", 108 | "destination": "/frontend/introduction-to-npm", 109 | "statusCode": 301 110 | }, 111 | { 112 | "source": "/note/js-advanced.html", 113 | "destination": "/frontend/javascript-advanced", 114 | "statusCode": 301 115 | }, 116 | { 117 | "source": "/note/js-foundation.html", 118 | "destination": "/frontend/javascript-foundation", 119 | "statusCode": 301 120 | }, 121 | { 122 | "source": "/note/js-foundation-old.html", 123 | "destination": "/frontend/javascript-foundation-legacy-version", 124 | "statusCode": 301 125 | }, 126 | { 127 | "source": "/note/js-modular.html", 128 | "destination": "/frontend/javascript-modules", 129 | "statusCode": 301 130 | }, 131 | { 132 | "source": "/note/regexp.html", 133 | "destination": "/frontend/javascript-regular-expression", 134 | "statusCode": 301 135 | }, 136 | { 137 | "source": "/note/jest.html", 138 | "destination": "/frontend/jest", 139 | "statusCode": 301 140 | }, 141 | { 142 | "source": "/note/node-basic.html", 143 | "destination": "/frontend/nodejs-basic", 144 | "statusCode": 301 145 | }, 146 | { 147 | "source": "/note/react-hooks.html", 148 | "destination": "/frontend/react-hooks", 149 | "statusCode": 301 150 | }, 151 | { 152 | "source": "/note/redux.html", 153 | "destination": "/frontend/redux", 154 | "statusCode": 301 155 | }, 156 | { 157 | "source": "/note/redux-observable.html", 158 | "destination": "/frontend/redux-observable", 159 | "statusCode": 301 160 | }, 161 | { 162 | "source": "/note/rxjs.html", 163 | "destination": "/frontend/rxjs", 164 | "statusCode": 301 165 | }, 166 | { 167 | "source": "/note/npm-verdaccio.html", 168 | "destination": "/frontend/set-up-a-private-npm-registry-using-verdaccio", 169 | "statusCode": 301 170 | }, 171 | { 172 | "source": "/note/npm-speedup.html", 173 | "destination": "/frontend/speeding-up-npm-install", 174 | "statusCode": 301 175 | }, 176 | { 177 | "source": "/note/syntactic-sugar.html", 178 | "destination": "/frontend/syntactic-sugar-in-javascript", 179 | "statusCode": 301 180 | }, 181 | { 182 | "source": "/note/testing-library.html", 183 | "destination": "/frontend/testing-library", 184 | "statusCode": 301 185 | }, 186 | { 187 | "source": "/note/clean-keyboard.html", 188 | "destination": "/misc/clean-a-keyboard", 189 | "statusCode": 301 190 | }, 191 | { 192 | "source": "/note/linux-basic-security.html", 193 | "destination": "/misc/linux-basic-security", 194 | "statusCode": 301 195 | }, 196 | { 197 | "source": "/note/fe-development-cookbook.html", 198 | "destination": "/note/frontend-development-cookbook", 199 | "statusCode": 301 200 | }, 201 | { 202 | "source": "/note/fe-development-cookbook", 203 | "destination": "/note/frontend-development-cookbook", 204 | "statusCode": 301 205 | }, 206 | { 207 | "source": "/note/fe-development-cookbook-old.html", 208 | "destination": "/note/frontend-development-cookbook", 209 | "statusCode": 301 210 | }, 211 | { 212 | "source": "/note/fe-development-cookbook-old", 213 | "destination": "/note/frontend-development-cookbook", 214 | "statusCode": 301 215 | }, 216 | { 217 | "source": "/note/frontend-development-cookbook.html", 218 | "destination": "/note/frontend-development-cookbook", 219 | "statusCode": 301 220 | }, 221 | { 222 | "source": "/note/study-methodology.html", 223 | "destination": "/study/crash-course-study-skills", 224 | "statusCode": 301 225 | }, 226 | { 227 | "source": "/note/study-the-costly-way.html", 228 | "destination": "/study/dont-waste-your-time-and-money", 229 | "statusCode": 301 230 | }, 231 | { 232 | "source": "/study/study-the-costly-way.html", 233 | "destination": "/study/dont-waste-your-time-and-money", 234 | "statusCode": 301 235 | }, 236 | { 237 | "source": "/study/study-the-costly-way", 238 | "destination": "/study/dont-waste-your-time-and-money", 239 | "statusCode": 301 240 | }, 241 | { 242 | "source": "/note/study-fortune.html", 243 | "destination": "/study/study-fortune", 244 | "statusCode": 301 245 | }, 246 | { 247 | "source": "/note/study-guild-abstraction.html", 248 | "destination": "/study/study-guild-abstraction", 249 | "statusCode": 301 250 | }, 251 | { 252 | "source": "/note/english-using.html", 253 | "destination": "/study/using-english", 254 | "statusCode": 301 255 | }, 256 | { 257 | "source": "/about/where-do-i-learn-from.html", 258 | "destination": "/study/where-do-i-learn-from", 259 | "statusCode": 301 260 | }, 261 | { 262 | "source": "/about/where-do-i-learn-from", 263 | "destination": "/study/where-do-i-learn-from", 264 | "statusCode": 301 265 | }, 266 | { 267 | "source": "/note/my-reading.html", 268 | "destination": "/study/where-do-i-learn-from", 269 | "statusCode": 301 270 | }, 271 | { 272 | "source": "/note/study-the-only-way.html", 273 | "destination": "/study/why-we-need-to-study", 274 | "statusCode": 301 275 | }, 276 | { 277 | "source": "/study/study-the-only-way.html", 278 | "destination": "/study/why-we-need-to-study", 279 | "statusCode": 301 280 | }, 281 | { 282 | "source": "/study/study-the-only-way", 283 | "destination": "/study/why-we-need-to-study", 284 | "statusCode": 301 285 | }, 286 | { 287 | "source": "/note/my-workstation.html", 288 | "destination": "/workspace/awesome-tools", 289 | "statusCode": 301 290 | }, 291 | { 292 | "source": "/note/chrome.html", 293 | "destination": "/workspace/chrome", 294 | "statusCode": 301 295 | }, 296 | { 297 | "source": "/note/terminal-intro.html", 298 | "destination": "/workspace/introduction-to-terminal", 299 | "statusCode": 301 300 | }, 301 | { 302 | "source": "/note/mac.html", 303 | "destination": "/workspace/mac", 304 | "statusCode": 301 305 | }, 306 | { 307 | "source": "/note/video-hotkey.html", 308 | "destination": "/workspace/my-video-player-shortcuts", 309 | "statusCode": 301 310 | }, 311 | { 312 | "source": "/note/terminal-config.html", 313 | "destination": "/workspace/terminal-settings", 314 | "statusCode": 301 315 | }, 316 | { 317 | "source": "/note/vscode.html", 318 | "destination": "/workspace/vscode", 319 | "statusCode": 301 320 | } 321 | ] 322 | } --------------------------------------------------------------------------------