├── site ├── static │ └── .gitkeep ├── .eslintignore ├── build │ ├── logo.png │ ├── vue-loader.conf.js │ ├── build.js │ ├── check-versions.js │ ├── webpack.base.conf.js │ ├── utils.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── config │ ├── prod.env.js │ ├── dev.env.js │ └── index.js ├── src │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── notFound.vue │ │ ├── loading.vue │ │ └── Index.vue │ ├── router │ │ └── index.js │ ├── App.vue │ └── main.js ├── .editorconfig ├── .gitignore ├── .babelrc ├── .postcssrc.js ├── README.md ├── .eslintrc.js ├── index.html └── package.json ├── assets ├── dot.png ├── new.png └── rss.gif ├── data ├── .rss.json.swp ├── tags.json ├── rss.json └── links.json ├── server ├── once.js ├── package.json ├── app.js ├── utils.js ├── update.js ├── writemd.js ├── fetch.js ├── links.json └── yarn.lock ├── details ├── tags │ ├── oop.md │ ├── git-svn.md │ ├── job-interview.md │ ├── vue.md │ ├── 肺炎疫情.md │ ├── typescript.md │ ├── dev-mobile.md │ ├── dev-game.md │ ├── server.md │ ├── miniprogram.md │ ├── react.md │ ├── front-end-advanced.md │ ├── audio-video.md │ ├── canvas-image.md │ ├── optimization.md │ ├── nodejs.md │ ├── other.md │ ├── pack-build.md │ ├── browser.md │ ├── css.md │ └── javascript.md └── 张鑫旭-鑫空间-鑫生活.md ├── package.json ├── now.json ├── .gitignore ├── templates ├── DETAILS.md ├── TAGS.md ├── TIMELINE.md └── README.md ├── .github └── workflows │ └── main.yml ├── TIMELINE.md ├── TAGS.md └── README.md /site/static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w4ctech/front-end-rss/HEAD/assets/dot.png -------------------------------------------------------------------------------- /assets/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w4ctech/front-end-rss/HEAD/assets/new.png -------------------------------------------------------------------------------- /assets/rss.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w4ctech/front-end-rss/HEAD/assets/rss.gif -------------------------------------------------------------------------------- /data/.rss.json.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w4ctech/front-end-rss/HEAD/data/.rss.json.swp -------------------------------------------------------------------------------- /site/.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | /src/components/Index.vue 6 | -------------------------------------------------------------------------------- /site/build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w4ctech/front-end-rss/HEAD/site/build/logo.png -------------------------------------------------------------------------------- /site/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /site/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w4ctech/front-end-rss/HEAD/site/src/assets/logo.png -------------------------------------------------------------------------------- /server/once.js: -------------------------------------------------------------------------------- 1 | const handlerUpdate = require('./update') 2 | 3 | // node once.js 执行一次,手动更新 4 | handlerUpdate() -------------------------------------------------------------------------------- /details/tags/oop.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 面向对象❤️ 4 | 5 | 6 | > 关键字:`面向对象` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/git-svn.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## Git、SVN 4 | 5 | 6 | > 关键字:`Git`、`SVN` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/job-interview.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 招聘面试 4 | 5 | 6 | > 关键字:`招聘`、`面试` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/vue.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## Vue 4 | 5 | 6 | > 关键字:`Vue`、`ElementUI` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/肺炎疫情.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 肺炎疫情 4 | 5 | 6 | > 关键字:`肺炎`、`肺炎疫情`、`武汉肺炎` 7 | 8 | 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "install": "cd server && cnpm install", 4 | "update": "cd server && node once.js", 5 | "auto": "cd server && node app.js" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /details/tags/typescript.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## TypeScript 4 | 5 | 6 | > 关键字:`TypeScript` 7 | 8 | 9 | -------------------------------------------------------------------------------- /site/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /details/tags/dev-mobile.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 移动开发、Flutter相关 4 | 5 | 6 | > 关键字:`Flutter`、`PWA`、`移动开发` 7 | 8 | 9 | -------------------------------------------------------------------------------- /site/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /details/tags/dev-game.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 游戏开发 4 | 5 | 6 | > 关键字:`游戏`、`Three.js`、`Create.js`、`Matter.js` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/server.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 服务端相关 4 | 5 | 6 | > 关键字:`Nginx`、`Docker`、`GraphQL`、`REST`、`gRPC` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/miniprogram.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 小程序 4 | 5 | 6 | > 关键字:`小程序`、`Taro`、`MPVue`、`Wepy`、`Chameleon` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/react.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## React 4 | 5 | 6 | > 关键字:`React`、`Rax`、`Nerv`、`Redux`、`useEffect`、`Hooks` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/front-end-advanced.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 前端进阶相关 4 | 5 | 6 | > 关键字:`AST`、`GPU`、`WebAssembly`、`Vim`、`HTTP`、`算法`、`全栈` 7 | 8 | 9 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /details/tags/audio-video.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 音视频相关 4 | 5 | 6 | > 关键字:`WebVR`、`WebRTC`、`Video`、`Audio`、`图像`、`音频`、`视频`、`直播`、`摄像头`、`播放器` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/canvas-image.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## Canvas、SVG、图像 4 | 5 | 6 | > 关键字:`Canvas`、`SVG`、`WebGL`、`3D`、`PNG`、`WebP`、`RGB`、`GUI` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/optimization.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 性能优化 4 | 5 | 6 | > 关键字:`性能`、`优化`、`加载`、`SEO`、`Hints`、`Prefetch`、`Prerender`、`Preload` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/nodejs.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## NodeJS 4 | 5 | 6 | > 关键字:`Node`、`Node.js`、`Express`、`Koa`、`egg.js`、`pandora.js`、`Electron`、`V8` 7 | 8 | 9 | -------------------------------------------------------------------------------- /details/tags/other.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 其它 4 | 5 | 6 | 7 | 8 | - [2025-12-04-单IMG标签的图片内阴影效果实现](https://www.zhangxinxu.com/wordpress/2025/12/img-inset-shadow/) -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "site/package.json", 6 | "use": "@now/static-build" 7 | } 8 | ], 9 | "routes": [ 10 | { 11 | "src": "/(.*)", 12 | "dest": "site/$1" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /site/src/components/notFound.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /details/tags/pack-build.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## Webpack、NPM、构建相关 4 | 5 | 6 | > 关键字:`Webpack`、`Lerna`、`Rollup`、`NPM`、`NPX`、`Yarn`、`Gulp`、`Grunt`、`Babel`、`ESLint`、`TSLint`、`构建` 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | .svn 5 | 6 | ._* 7 | 8 | .Spotlight-V100 9 | .Trashes 10 | 11 | Thumbs.db 12 | ehthumbs.db 13 | 14 | Desktop.ini 15 | 16 | $RECYCLE.BIN/ 17 | 18 | .idea 19 | 20 | *.sublime-* 21 | 22 | .vscode 23 | 24 | node_modules 25 | *.js.map 26 | package-lock.json 27 | ./email.sh 28 | -------------------------------------------------------------------------------- /details/tags/browser.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 浏览器相关 4 | 5 | 6 | > 关键字:`Chrome`、`Chromium`、`IE`、`Firefox`、`Safari`、`Webkit`、`Edge`、`WebSocket`、`GET`、`POST`、`CORS`、`URL`、`浏览器`、`调试`、`缓存`、`跨域`、`请求`、`安全`、`状态码`、`重绘`、`重排`、`渲染` 7 | 8 | 9 | 10 | - [2025-11-28-醒醒,该使用CookieStore新建和管理cookie了](https://www.zhangxinxu.com/wordpress/2025/11/js-cookiestore-cookie/) -------------------------------------------------------------------------------- /templates/DETAILS.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: <%= obj.currentDate %>。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## <%= obj.title %> 4 | 5 | <% if(obj.keywords){ %> 6 | > 关键字:`<%= obj.keywords.replace(/(\?)|([:])/g, '').split('|').join('`、`') %>` 7 | <% } %> 8 | 9 | <% _.each(obj.items, function(item){ var itemTitle = obj.formatTitle(item.title); %> 10 | - [<%= item.date %>-<%= itemTitle %>](<%= item.link %>) <% }) %> -------------------------------------------------------------------------------- /site/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": [ 12 | ["import", { 13 | "libraryName": "vant", 14 | "libraryDirectory": "es", 15 | "style": true 16 | }], 17 | "transform-vue-jsx", 18 | "transform-runtime" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /site/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": { 9 | browsers: ['Android >= 4.0', 'iOS >= 7'] 10 | }, 11 | 'postcss-pxtorem': { 12 | rootValue: 16, 13 | propList: ['*'] 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /site/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '@/components/Index' 4 | import notFound from '@/components/notFound' 5 | Vue.use(Router) 6 | 7 | export default new Router({ 8 | mode: 'history', 9 | routes: [ 10 | { 11 | path: '/', 12 | name: 'Index', 13 | component: Index 14 | }, { 15 | path: '/404', 16 | name: 'notFound', 17 | component: notFound 18 | }, { 19 | path: '*', 20 | redirect: '/404' 21 | } 22 | ] 23 | }) 24 | -------------------------------------------------------------------------------- /details/tags/css.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## CSS 4 | 5 | 6 | > 关键字:`CSS`、`Sass`、`Less`、`scale`、`transform`、`transition`、`animation`、`border`、`background`、`font-weight`、`font-face`、`flex`、`display`、`position`、`居中`、`动画` 7 | 8 | 9 | 10 | - [2025-12-12-CSS-progress函数简介](https://www.zhangxinxu.com/wordpress/2025/12/css-progress-function/) 11 | - [2025-11-24-巧用CSS-::details-content伪元素实现任意展开动画](https://www.zhangxinxu.com/wordpress/2025/11/css-details-target-content-open/) -------------------------------------------------------------------------------- /site/README.md: -------------------------------------------------------------------------------- 1 | # site 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /site/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | 16 | 28 | -------------------------------------------------------------------------------- /details/tags/javascript.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## JavaScript 4 | 5 | 6 | > 关键字:`JavaScript`、`ECMAScript`、`JS`、`ES6`、`Promise`、`document`、`await`、`async`、`decorator`、`module`、`import`、`catch`、`console`、`setInterval`、`Worker`、`fetch`、`this`、`bind`、`DataTransfer`、`ArrayBuffer`、`Component`、`DOM`、`H5`、`HTML5`、`组件`、`正则`、`数组`、`事件`、`深拷贝`、`数据代理`、`变量`、`函数式`、`声明式`、`异步`、`表单`、`滚动`、`scroll`、`防抖`、`适配`、`路由`、`模块化` 7 | 8 | 9 | 10 | - [2025-11-17-介绍下与CSS自定义组件相关的:state函数](https://www.zhangxinxu.com/wordpress/2025/11/css-state-function/) -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: rss 2 | 3 | on: 4 | schedule: 5 | - cron: "0 23 * * *" 6 | jobs: 7 | front-rss-bot: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | - name: Set up Node 13 | uses: actions/setup-node@v1 14 | with: 15 | node-version: 10.x 16 | - name: configure 17 | run: | 18 | git config --global user.name "w4ctech" 19 | git config --global user.email "w3ctech@qq.com" 20 | - name: working 21 | run: cd server && npm install && node once.js 22 | -------------------------------------------------------------------------------- /site/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /details/张鑫旭-鑫空间-鑫生活.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](../README.md)、[标签分类](../TAGS.md)、[时间分类](../TIMELINE.md) 2 | 3 | ## 张鑫旭-鑫空间-鑫生活 4 | 5 | 6 | 7 | 8 | - [2025-12-12-CSS-progress函数简介](https://www.zhangxinxu.com/wordpress/2025/12/css-progress-function/) 9 | - [2025-12-04-单IMG标签的图片内阴影效果实现](https://www.zhangxinxu.com/wordpress/2025/12/img-inset-shadow/) 10 | - [2025-11-28-醒醒,该使用CookieStore新建和管理cookie了](https://www.zhangxinxu.com/wordpress/2025/11/js-cookiestore-cookie/) 11 | - [2025-11-24-巧用CSS-::details-content伪元素实现任意展开动画](https://www.zhangxinxu.com/wordpress/2025/11/css-details-target-content-open/) 12 | - [2025-11-17-介绍下与CSS自定义组件相关的:state函数](https://www.zhangxinxu.com/wordpress/2025/11/css-state-function/) -------------------------------------------------------------------------------- /templates/TAGS.md: -------------------------------------------------------------------------------- 1 | > 提示:只是根据标题文案简单匹配分类 2 | 3 | :alarm_clock: 更新时间: <%= obj.currentDate %>。[来源分类](./README.md)、[时间分类](./TIMELINE.md) 4 | 5 | ## 标签分类 6 | <% _.each(obj.tags, function(e){ %> 7 | - [<%= e.tag %>](#<%= e.tag.toLowerCase() %>) <% }) %> 8 | 9 | ## 文章链接 10 | <% _.each(obj.tags, function(e){ %> 11 |
12 | 13 | <%= e.tag %> 14 | 15 |

16 | 17 | <% if(e.keywords){ %> 18 | > 关键字:`<%= e.keywords.replace(/(\?)|([:])/g, '').split('|').join('`、`') %>` 19 | <% } %> 20 | 21 | <% _.each(e.items.slice(0,20), function(item){ var itemTitle = obj.formatTitle(item.title); %> 22 | - [【<%= item.rssTitle %>】<%= itemTitle %>](<%= item.link %>)<% }) %> 23 | - [......【查看更多】......](./details/tags/<%= e.filename %>.md) 24 | 25 |
⬆返回顶部
26 |
27 | <% }) %> 28 | -------------------------------------------------------------------------------- /site/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import '@vant/touch-emulator' 5 | import { Search, Icon, Popup, Cell, CellGroup, Tag, Divider, Skeleton } from 'vant' 6 | import infiniteScroll from 'vue-infinite-scroll' 7 | import App from './App' 8 | import router from './router' 9 | import moment from 'moment' 10 | import axios from "axios" 11 | Vue.prototype.bus = new Vue() 12 | Vue.config.productionTip = false 13 | Vue.prototype.$moment = moment 14 | Vue.prototype.$axios = axios 15 | Vue.use(infiniteScroll).use(Search).use(Icon).use(Popup).use(Cell).use(CellGroup).use(Tag).use(Divider).use(Skeleton) 16 | 17 | /* eslint-disable no-new */ 18 | new Vue({ 19 |   el: '#app', 20 |   router, 21 |   components: { App }, 22 |   template: '' 23 | }) 24 | 25 | -------------------------------------------------------------------------------- /site/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parserOptions: { 6 | parser: 'babel-eslint' 7 | }, 8 | env: { 9 | browser: true, 10 | }, 11 | extends: [ 12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 14 | 'plugin:vue/essential', 15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 16 | 'standard' 17 | ], 18 | // required to lint *.vue files 19 | plugins: [ 20 | 'vue' 21 | ], 22 | // add your custom rules here 23 | rules: { 24 | // allow async-await 25 | 'generator-star-spacing': 'off', 26 | // allow debugger during development 27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /templates/TIMELINE.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: <%= obj.currentDate %>。[来源分类](./README.md)、[标签分类](./TAGS.md) 2 | 3 | ## 时间分类 4 | 5 | 6 | <% _.each(obj.dataYears, function(year){ %> 7 | 8 | 9 | 10 | <% _.each((new Array(12)), function(e, idx){ idx++; idx = idx < 10 ? ('0' + idx) : idx; var date = year + '-' + idx; %> 11 | <% }) %> 12 | 13 | <% }) %> 14 |
<%= year %>年
<% if(obj.dataKeys.indexOf(date) > -1) { %><%= idx %>月<% } else { %><%= idx %>月<% } %>
15 | 16 | ## 文章链接 17 | <% _.each(obj.dataKeys, function(e){ %> 18 |
19 | 20 | <%= e %> 21 | 22 | 23 | <% _.each(obj.dataObj[e], function(item){ var itemTitle = obj.formatTitle(item.title); %> 24 | - [【<%= item.rssTitle %>】<%= item.date %>-<%= itemTitle %>](<%= item.link %>) <% }) %> 25 | 26 |
⬆返回顶部
27 |
28 | <% }) %> 29 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front-end-rss", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "dependencies": { 6 | "async": "^2.6.1", 7 | "axios": "^0.19.1", 8 | "clone-deep": "^4.0.0", 9 | "later": "^1.2.0", 10 | "moment": "^2.22.2", 11 | "query-string": "^6.8.1", 12 | "rimraf": "^3.0.0", 13 | "rss-parser": "^3.4.3", 14 | "simple-git": "^1.102.0", 15 | "underscore": "^1.12.1" 16 | }, 17 | "description": "front-end-rss", 18 | "devDependencies": {}, 19 | "scripts": { 20 | "test": "echo \"Error: no test specified\" && exit 1", 21 | "update": "node once.js" 22 | }, 23 | "author": "w4ctech", 24 | "license": "MIT", 25 | "repository": { 26 | "type": "git", 27 | "url": "git://github.com/w4ctech/front-end-rss.git" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/w4ctech/front-end-rss/issues" 31 | }, 32 | "homepage": "https://github.com/w4ctech/front-end-rss#readme" 33 | } 34 | -------------------------------------------------------------------------------- /site/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | w4ctech—深自缄默 如云漂泊 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 29 | 30 | -------------------------------------------------------------------------------- /site/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /TIMELINE.md: -------------------------------------------------------------------------------- 1 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](./README.md)、[标签分类](./TAGS.md) 2 | 3 | ## 时间分类 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
2025年
01月02月03月04月05月06月07月08月09月10月11月12月
26 | 27 | ## 文章链接 28 | 29 |
30 | 31 | 2025-12 32 | 33 | 34 | 35 | - [【张鑫旭-鑫空间-鑫生活】2025-12-12-CSS-progress函数简介](https://www.zhangxinxu.com/wordpress/2025/12/css-progress-function/) 36 | - [【张鑫旭-鑫空间-鑫生活】2025-12-04-单IMG标签的图片内阴影效果实现](https://www.zhangxinxu.com/wordpress/2025/12/img-inset-shadow/) 37 | 38 |
⬆返回顶部
39 |
40 | 41 |
42 | 43 | 2025-11 44 | 45 | 46 | 47 | - [【张鑫旭-鑫空间-鑫生活】2025-11-28-醒醒,该使用CookieStore新建和管理cookie了](https://www.zhangxinxu.com/wordpress/2025/11/js-cookiestore-cookie/) 48 | - [【张鑫旭-鑫空间-鑫生活】2025-11-24-巧用CSS-::details-content伪元素实现任意展开动画](https://www.zhangxinxu.com/wordpress/2025/11/css-details-target-content-open/) 49 | - [【张鑫旭-鑫空间-鑫生活】2025-11-17-介绍下与CSS自定义组件相关的:state函数](https://www.zhangxinxu.com/wordpress/2025/11/css-state-function/) 50 | 51 |
⬆返回顶部
52 |
53 | 54 | -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 |

Front-End RSS

点击右上角 Watch 订阅 最新前端技术文章

2 | https://front-end-rss.w4ctech.cn 3 |
4 | 5 | ## 6 | 7 | - 项目目的:每天定时抓取最新前端技术文章,并推送到 GitHub 方便查看 8 | - 文章来源:RSS 订阅源 9 | - 定时抓取:每30分钟一次 10 | - 文章分类:[标签分类](./TAGS.md)、[时间分类](./TIMELINE.md) 11 | 12 | ## 13 | 14 | :alarm_clock: 更新时间: <%= obj.currentDate %>,:rocket: 更新条数: +<%= obj.newData.length %>, ![](assets/dot.png) 表示有更新 15 | 16 | ## 来源分类 17 | <% _.each(obj.linksJson, function(e){ var rssTitle = obj.formatTitle(e.title); %> 18 | - [<%= rssTitle %>](#<%= rssTitle.toLowerCase() %>)<% if (e.rss in obj.newData.rss){ %>![](assets/dot.png) <% } %> <% }) %> 19 | 20 | ## 文章链接 21 | <% _.each(obj.linksJson, function(e){ var rssTitle = obj.formatTitle(e.title); %> 22 |
23 | 24 | <%= rssTitle %> 25 | 26 | 27 | <% _.each(e.items.slice(0,20), function(item, index){ var itemTitle = obj.formatTitle(item.title); %> 28 | - [<%= item.date %>-<%= itemTitle %>](<%= item.link %>) <% if (e.rss in obj.newData.rss && item.link in obj.newData.links){ %>![](assets/new.png) <% } %> <% }) %> 29 | - [......【查看更多】......](./details/<%= e.title %>.md) 30 | 31 |
⬆返回顶部
32 |
33 | <% }) %> 34 | 35 | ## 其它 36 | 感谢 [RSSHub](https://github.com/DIYgod/RSSHub) 提供的微信公众号 RSS 链接 Fork自 [ChanceYu](https://github.com/ChanceYu/front-end-rss) 37 | -------------------------------------------------------------------------------- /site/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /server/app.js: -------------------------------------------------------------------------------- 1 | const later = require('later') 2 | 3 | const handlerUpdate = require('./update') 4 | 5 | // node app.js 设置自动更新 6 | later.date.localTime() 7 | later.setInterval(handlerUpdate, { 8 | schedules: [ 9 | { h: [00], m: [00] }, 10 | { h: [00], m: [30] }, 11 | { h: [01], m: [00] }, 12 | { h: [01], m: [30] }, 13 | { h: [02], m: [00] }, 14 | { h: [02], m: [30] }, 15 | { h: [03], m: [00] }, 16 | { h: [03], m: [30] }, 17 | { h: [04], m: [00] }, 18 | { h: [04], m: [30] }, 19 | { h: [05], m: [00] }, 20 | { h: [05], m: [30] }, 21 | { h: [06], m: [00] }, 22 | { h: [06], m: [30] }, 23 | { h: [07], m: [00] }, 24 | { h: [07], m: [30] }, 25 | { h: [08], m: [00] }, 26 | { h: [08], m: [30] }, 27 | { h: [09], m: [00] }, 28 | { h: [09], m: [30] }, 29 | { h: [10], m: [00] }, 30 | { h: [10], m: [30] }, 31 | { h: [11], m: [00] }, 32 | { h: [11], m: [30] }, 33 | { h: [12], m: [00] }, 34 | { h: [12], m: [30] }, 35 | { h: [13], m: [00] }, 36 | { h: [13], m: [30] }, 37 | { h: [14], m: [00] }, 38 | { h: [14], m: [30] }, 39 | { h: [15], m: [00] }, 40 | { h: [15], m: [30] }, 41 | { h: [16], m: [00] }, 42 | { h: [16], m: [30] }, 43 | { h: [17], m: [00] }, 44 | { h: [17], m: [30] }, 45 | { h: [18], m: [00] }, 46 | { h: [18], m: [30] }, 47 | { h: [19], m: [00] }, 48 | { h: [19], m: [30] }, 49 | { h: [20], m: [00] }, 50 | { h: [20], m: [30] }, 51 | { h: [21], m: [00] }, 52 | { h: [21], m: [30] }, 53 | { h: [22], m: [00] }, 54 | { h: [22], m: [30] }, 55 | { h: [23], m: [00] }, 56 | { h: [23], m: [30] } 57 | ] 58 | }) 59 | -------------------------------------------------------------------------------- /server/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const moment = require('moment') 4 | 5 | const RESP_ROOT = '../'; 6 | const RESP_PATH = path.join(RESP_ROOT) 7 | const RSS_PATH = path.join(RESP_ROOT + '/data/rss.json') 8 | const LINKS_PATH = path.join(RESP_ROOT + '/data/links.json') 9 | const TAGS_PATH = path.join(RESP_ROOT + '/data/tags.json') 10 | const README_PATH = path.join(RESP_ROOT + '/README.md') 11 | const README_TEMPLATE_PATH = path.join(RESP_ROOT + '/templates/README.md') 12 | const TAGS_MD_PATH = path.join(RESP_ROOT + '/TAGS.md') 13 | const TAGS_TEMPLATE_PATH = path.join(RESP_ROOT + '/templates/TAGS.md') 14 | const TIMELINE_MD_PATH = path.join(RESP_ROOT + '/TIMELINE.md') 15 | const TIMELINE_TEMPLATE_PATH = path.join(RESP_ROOT + '/templates/TIMELINE.md') 16 | const DETAILS_TEMPLATE_PATH = path.join(RESP_ROOT + '/templates/DETAILS.md') 17 | 18 | module.exports = { 19 | /** 20 | * 文件路径 21 | */ 22 | PATH: { 23 | RESP_PATH, 24 | RSS_PATH, 25 | LINKS_PATH, 26 | TAGS_PATH, 27 | README_PATH, 28 | README_TEMPLATE_PATH, 29 | TAGS_MD_PATH, 30 | TAGS_TEMPLATE_PATH, 31 | TIMELINE_MD_PATH, 32 | TIMELINE_TEMPLATE_PATH, 33 | DETAILS_TEMPLATE_PATH, 34 | }, 35 | 36 | /** 37 | * 格式化标题 38 | */ 39 | formatTitle: function(title, isRsshub){ 40 | // https://front-rss.herokuapp.com 41 | if(isRsshub){ 42 | let matches = title.match(/“(.*)”/) 43 | 44 | if(matches && matches[1]){ 45 | title = matches[1] 46 | } 47 | } 48 | return title.replace('', '').replace(/[\[\]\(\)]/g, '').replace(/\s+/g, '-') 49 | }, 50 | 51 | /** 52 | * 格式化时间 53 | */ 54 | getNowDate: function(){ 55 | return moment().format('YYYY-MM-DD HH:mm:ss') 56 | }, 57 | 58 | /** 59 | * 获取 links.json 数据 60 | */ 61 | getLinksJson: function(){ 62 | return JSON.parse(fs.readFileSync(LINKS_PATH).toString()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /site/config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'cheap-module-eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | cssSourceMap: true 44 | }, 45 | 46 | build: { 47 | // Template for index.html 48 | index: path.resolve(__dirname, '../dist/index.html'), 49 | 50 | // Paths 51 | assetsRoot: path.resolve(__dirname, '../dist'), 52 | assetsSubDirectory: 'static', 53 | assetsPublicPath: '/', 54 | 55 | /** 56 | * Source Maps 57 | */ 58 | 59 | productionSourceMap: true, 60 | // https://webpack.js.org/configuration/devtool/#production 61 | devtool: '#source-map', 62 | 63 | // Gzip off by default as many popular static hosts such as 64 | // Surge or Netlify already gzip all static assets for you. 65 | // Before setting to `true`, make sure to: 66 | // npm install --save-dev compression-webpack-plugin 67 | productionGzip: false, 68 | productionGzipExtensions: ['js', 'css'], 69 | 70 | // Run the build command with an extra argument to 71 | // View the bundle analyzer report after build finishes: 72 | // `npm run build --report` 73 | // Set to `true` or `false` to always turn it on or off 74 | bundleAnalyzerReport: process.env.npm_config_report 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "site", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "w4ctech ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "lint": "eslint --ext .js,.vue src", 11 | "build": "node build/build.js" 12 | }, 13 | "dependencies": { 14 | "@vant/touch-emulator": "^1.1.0", 15 | "axios": "^0.19.1", 16 | "dayjs": "^1.8.16", 17 | "moment": "^2.24.0", 18 | "vant": "^2.2.9", 19 | "vue": "^2.5.2", 20 | "vue-infinite-scroll": "^2.0.2", 21 | "vue-router": "^3.0.1" 22 | }, 23 | "devDependencies": { 24 | "autoprefixer": "^7.1.2", 25 | "babel-core": "^6.22.1", 26 | "babel-eslint": "^8.2.1", 27 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 28 | "babel-loader": "^7.1.1", 29 | "babel-plugin-import": "^1.12.2", 30 | "babel-plugin-syntax-jsx": "^6.18.0", 31 | "babel-plugin-transform-runtime": "^6.22.0", 32 | "babel-plugin-transform-vue-jsx": "^3.5.0", 33 | "babel-preset-env": "^1.3.2", 34 | "babel-preset-stage-2": "^6.22.0", 35 | "chalk": "^2.0.1", 36 | "copy-webpack-plugin": "^4.0.1", 37 | "css-loader": "^0.28.0", 38 | "eslint": "^4.15.0", 39 | "eslint-config-standard": "^10.2.1", 40 | "eslint-friendly-formatter": "^3.0.0", 41 | "eslint-loader": "^1.7.1", 42 | "eslint-plugin-import": "^2.7.0", 43 | "eslint-plugin-node": "^5.2.0", 44 | "eslint-plugin-promise": "^3.4.0", 45 | "eslint-plugin-standard": "^3.0.1", 46 | "eslint-plugin-vue": "^4.0.0", 47 | "extract-text-webpack-plugin": "^3.0.0", 48 | "file-loader": "^1.1.4", 49 | "friendly-errors-webpack-plugin": "^1.6.1", 50 | "html-webpack-plugin": "^2.30.1", 51 | "node-notifier": "^5.1.2", 52 | "optimize-css-assets-webpack-plugin": "^3.2.0", 53 | "ora": "^1.2.0", 54 | "portfinder": "^1.0.13", 55 | "postcss-import": "^11.0.0", 56 | "postcss-loader": "^2.0.8", 57 | "postcss-pxtorem": "^4.0.1", 58 | "postcss-url": "^7.2.1", 59 | "rimraf": "^2.6.0", 60 | "semver": "^5.3.0", 61 | "shelljs": "^0.7.6", 62 | "uglifyjs-webpack-plugin": "^1.1.1", 63 | "url-loader": "^0.5.8", 64 | "vue-loader": "^13.3.0", 65 | "vue-style-loader": "^3.0.1", 66 | "vue-template-compiler": "^2.5.2", 67 | "webpack": "^3.6.0", 68 | "webpack-bundle-analyzer": "^2.9.0", 69 | "webpack-dev-server": "^2.9.1", 70 | "webpack-merge": "^4.1.0" 71 | }, 72 | "engines": { 73 | "node": ">= 6.0.0", 74 | "npm": ">= 3.0.0" 75 | }, 76 | "browserslist": [ 77 | "> 1%", 78 | "last 2 versions", 79 | "not ie <= 8" 80 | ] 81 | } -------------------------------------------------------------------------------- /site/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | const createLintingRule = () => ({ 12 | test: /\.(js|vue)$/, 13 | loader: 'eslint-loader', 14 | enforce: 'pre', 15 | include: [resolve('src'), resolve('test')], 16 | options: { 17 | formatter: require('eslint-friendly-formatter'), 18 | emitWarning: !config.dev.showEslintErrorsInOverlay 19 | } 20 | }) 21 | 22 | module.exports = { 23 | context: path.resolve(__dirname, '../'), 24 | entry: { 25 | app: './src/main.js' 26 | }, 27 | output: { 28 | path: config.build.assetsRoot, 29 | filename: '[name].js', 30 | publicPath: process.env.NODE_ENV === 'production' 31 | ? config.build.assetsPublicPath 32 | : config.dev.assetsPublicPath 33 | }, 34 | resolve: { 35 | extensions: ['.js', '.vue', '.json'], 36 | alias: { 37 | 'vue$': 'vue/dist/vue.esm.js', 38 | '@': resolve('src'), 39 | } 40 | }, 41 | module: { 42 | rules: [ 43 | // ...(config.dev.useEslint ? [createLintingRule()] : []), 44 | { 45 | test: /\.vue$/, 46 | loader: 'vue-loader', 47 | options: vueLoaderConfig 48 | }, 49 | { 50 | test: /\.js$/, 51 | loader: 'babel-loader', 52 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] 53 | }, 54 | { 55 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 56 | loader: 'url-loader', 57 | options: { 58 | limit: 10000, 59 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 60 | } 61 | }, 62 | { 63 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 64 | loader: 'url-loader', 65 | options: { 66 | limit: 10000, 67 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 68 | } 69 | }, 70 | { 71 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 72 | loader: 'url-loader', 73 | options: { 74 | limit: 10000, 75 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 76 | } 77 | } 78 | ] 79 | }, 80 | node: { 81 | // prevent webpack from injecting useless setImmediate polyfill because Vue 82 | // source contains it (although only uses it if it's native). 83 | setImmediate: false, 84 | // prevent webpack from injecting mocks to Node native modules 85 | // that does not make sense for the client 86 | dgram: 'empty', 87 | fs: 'empty', 88 | net: 'empty', 89 | tls: 'empty', 90 | child_process: 'empty' 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /server/update.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const async = require('async') 4 | const moment = require('moment') 5 | const Parser = require('rss-parser') 6 | const Git = require('simple-git') 7 | const _ = require('underscore') 8 | const cloneDeep = require('clone-deep') 9 | const rimraf = require('rimraf') 10 | const utils = require('./utils') 11 | const writemd = require('./writemd') 12 | const fetch = require('./fetch') 13 | 14 | const { 15 | RESP_PATH, 16 | RSS_PATH, 17 | LINKS_PATH, 18 | TAGS_PATH, 19 | README_PATH, 20 | README_TEMPLATE_PATH, 21 | TAGS_MD_PATH, 22 | TAGS_TEMPLATE_PATH, 23 | TIMELINE_MD_PATH, 24 | TIMELINE_TEMPLATE_PATH, 25 | } = utils.PATH 26 | 27 | let rssJson = [] 28 | let linksJson = [] 29 | 30 | // 本次更新的 rss 和链接数据 31 | let newData = { 32 | length: 0, 33 | titles: [], 34 | rss: {}, 35 | links: {} 36 | } 37 | 38 | /** 39 | * 更新 git 仓库 40 | */ 41 | function handlerUpdate(){ 42 | fs.copyFile('./links.json','../data/links.json',function(err){ 43 | if(err){ 44 | console.log('something wrong was happened') 45 | } 46 | else{ 47 | console.log('copy file succeed'); 48 | } 49 | }) 50 | rimraf('../details/*',function (msg) { 51 | console.log('删除了details目录'+msg) 52 | fs.mkdir('../details/tags',res=>{ 53 | if (res) { 54 | return console.error(res); 55 | } 56 | console.log("details/tags目录创建成功。"); 57 | }) 58 | }) 59 | console.log(utils.getNowDate() + ' - 开始更新抓取'); 60 | Git(RESP_PATH) 61 | .pull() 62 | .exec(handlerFeed); 63 | } 64 | 65 | /** 66 | * 提交修改到 git 仓库 67 | */ 68 | function handlerCommit(){ 69 | console.log(utils.getNowDate() + ' - 完成抓取,即将上传'); 70 | Git(RESP_PATH) 71 | .add('./*') 72 | .commit('更新: ' + newData.titles.join('、')) 73 | .push(['-u', 'origin', 'master'], () => console.log('完成抓取和上传!','更新了'+newData.titles.join('、'))); 74 | } 75 | 76 | /** 77 | * 处理订阅源 78 | */ 79 | function handlerFeed(){ 80 | rssJson = require(RSS_PATH) 81 | linksJson = require(LINKS_PATH) 82 | 83 | newData = { 84 | length: 0, 85 | titles: [], 86 | rss: {}, 87 | links: {} 88 | } 89 | 90 | let parallels = [] 91 | 92 | rssJson.forEach((item, index) => { 93 | let jsonItem = linksJson[index] || {} 94 | 95 | parallels.push(function(cb){ 96 | fetch(newData, linksJson, index, jsonItem, item, cb); 97 | }) 98 | }) 99 | 100 | async.parallel(parallels, (err, result) => { 101 | if(newData.length){ 102 | fs.writeFileSync(LINKS_PATH, JSON.stringify(result, null, 2), 'utf-8') 103 | writemd(newData) 104 | handlerCommit() 105 | }else{ 106 | console.log(utils.getNowDate() + ' - 无需更新'); 107 | } 108 | }) 109 | } 110 | 111 | module.exports = handlerUpdate 112 | -------------------------------------------------------------------------------- /site/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const packageConfig = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | 12 | return path.posix.join(assetsSubDirectory, _path) 13 | } 14 | 15 | exports.cssLoaders = function (options) { 16 | options = options || {} 17 | 18 | const cssLoader = { 19 | loader: 'css-loader', 20 | options: { 21 | sourceMap: options.sourceMap 22 | } 23 | } 24 | 25 | const postcssLoader = { 26 | loader: 'postcss-loader', 27 | options: { 28 | sourceMap: options.sourceMap 29 | } 30 | } 31 | 32 | // generate loader string to be used with extract text plugin 33 | function generateLoaders (loader, loaderOptions) { 34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 35 | 36 | if (loader) { 37 | loaders.push({ 38 | loader: loader + '-loader', 39 | options: Object.assign({}, loaderOptions, { 40 | sourceMap: options.sourceMap 41 | }) 42 | }) 43 | } 44 | 45 | // Extract CSS when that option is specified 46 | // (which is the case during production build) 47 | if (options.extract) { 48 | return ExtractTextPlugin.extract({ 49 | use: loaders, 50 | fallback: 'vue-style-loader' 51 | }) 52 | } else { 53 | return ['vue-style-loader'].concat(loaders) 54 | } 55 | } 56 | 57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 58 | return { 59 | css: generateLoaders(), 60 | postcss: generateLoaders(), 61 | less: generateLoaders('less'), 62 | sass: generateLoaders('sass', { indentedSyntax: true }), 63 | scss: generateLoaders('sass'), 64 | stylus: generateLoaders('stylus'), 65 | styl: generateLoaders('stylus') 66 | } 67 | } 68 | 69 | // Generate loaders for standalone style files (outside of .vue) 70 | exports.styleLoaders = function (options) { 71 | const output = [] 72 | const loaders = exports.cssLoaders(options) 73 | 74 | for (const extension in loaders) { 75 | const loader = loaders[extension] 76 | output.push({ 77 | test: new RegExp('\\.' + extension + '$'), 78 | use: loader 79 | }) 80 | } 81 | 82 | return output 83 | } 84 | 85 | exports.createNotifierCallback = () => { 86 | const notifier = require('node-notifier') 87 | 88 | return (severity, errors) => { 89 | if (severity !== 'error') return 90 | 91 | const error = errors[0] 92 | const filename = error.file && error.file.split('!').pop() 93 | 94 | notifier.notify({ 95 | title: packageConfig.name, 96 | message: severity + ': ' + error.name, 97 | subtitle: filename || '', 98 | icon: path.join(__dirname, 'logo.png') 99 | }) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /data/tags.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "tag": "React", 4 | "filename": "react", 5 | "keywords": "React|Rax|Nerv|Redux|useEffect|Hooks?" 6 | }, 7 | { 8 | "tag": "Vue", 9 | "filename": "vue", 10 | "keywords": "Vue|ElementUI" 11 | }, 12 | { 13 | "tag": "TypeScript", 14 | "filename": "typescript", 15 | "keywords": "TypeScript" 16 | }, 17 | { 18 | "tag": "Webpack、NPM、构建相关", 19 | "filename": "pack-build", 20 | "keywords": "Webpack|Lerna|Rollup|NPM|NPX|Yarn|Gulp|Grunt|Babel|ESLint|TSLint|构建" 21 | }, 22 | { 23 | "tag": "NodeJS", 24 | "filename": "nodejs", 25 | "keywords": "Node|Node.?js|Express|Koa|egg.?js|pandora.?js|Electron|V8" 26 | }, 27 | { 28 | "tag": "小程序", 29 | "filename": "miniprogram", 30 | "keywords": "小程序|Taro|MPVue|Wepy|Chameleon" 31 | }, 32 | { 33 | "tag": "移动开发、Flutter相关", 34 | "filename": "dev-mobile", 35 | "keywords": "Flutter|PWA|移动开发" 36 | }, 37 | { 38 | "tag": "游戏开发", 39 | "filename": "dev-game", 40 | "keywords": "游戏|Three.?js|Create.?js|Matter.?js" 41 | }, 42 | { 43 | "tag": "JavaScript", 44 | "filename": "javascript", 45 | "keywords": "JavaScript|ECMAScript|JS|ES6|Promise|document|await|async|decorator|module|import|catch|console|setInterval|Worker|fetch|this|bind|DataTransfer|ArrayBuffer|Component|DOM|H5|HTML5|组件|正则|数组|事件|深拷贝|数据代理|变量|函数式|声明式|异步|表单|滚动|scroll|防抖|适配|路由|模块化" 46 | }, 47 | { 48 | "tag": "CSS", 49 | "filename": "css", 50 | "keywords": "CSS|Sass|Less|scale|transform|transition|animation|border|background|font-weight|font-face|flex|display|position|居中|动画" 51 | }, 52 | { 53 | "tag": "Canvas、SVG、图像", 54 | "filename": "canvas-image", 55 | "keywords": "Canvas|SVG|WebGL|3D|PNG|WebP|RGB|GUI" 56 | }, 57 | { 58 | "tag": "音视频相关", 59 | "filename": "audio-video", 60 | "keywords": "WebVR|WebRTC|Video|Audio|图像|音频|视频|直播|摄像头|播放器" 61 | }, 62 | { 63 | "tag": "性能优化", 64 | "filename": "optimization", 65 | "keywords": "性能|优化|加载|SEO|Hints|Prefetch|Prerender|Preload" 66 | }, 67 | { 68 | "tag": "浏览器相关", 69 | "filename": "browser", 70 | "keywords": "Chrome|Chromium|IE|Firefox|Safari|Webkit|Edge|WebSocket|GET|POST|CORS|URL|浏览器|调试|缓存|跨域|请求|安全|状态码|重绘|重排|渲染" 71 | }, 72 | { 73 | "tag": "前端进阶相关", 74 | "filename": "front-end-advanced", 75 | "keywords": "AST|GPU|WebAssembly|Vim|HTTP|算法|全栈" 76 | }, 77 | { 78 | "tag": "服务端相关", 79 | "filename": "server", 80 | "keywords": "Nginx|Docker|GraphQL|REST|gRPC" 81 | }, 82 | { 83 | "tag": "Git、SVN", 84 | "filename": "git-svn", 85 | "keywords": "Git|SVN" 86 | }, 87 | { 88 | "tag": "招聘面试", 89 | "filename": "job-interview", 90 | "keywords": "招聘|面试" 91 | }, 92 | { 93 | "tag": "面向对象❤️", 94 | "filename": "oop", 95 | "keywords": "面向对象:" 96 | }, 97 | { 98 | "tag": "肺炎疫情", 99 | "filename": "肺炎疫情", 100 | "keywords": "肺炎|肺炎疫情|武汉肺炎:" 101 | }, 102 | { 103 | "tag": "其它", 104 | "filename": "other", 105 | "keywords": "" 106 | } 107 | ] 108 | -------------------------------------------------------------------------------- /site/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const path = require('path') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 11 | const portfinder = require('portfinder') 12 | 13 | const HOST = process.env.HOST 14 | const PORT = process.env.PORT && Number(process.env.PORT) 15 | 16 | const devWebpackConfig = merge(baseWebpackConfig, { 17 | module: { 18 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 19 | }, 20 | // cheap-module-eval-source-map is faster for development 21 | devtool: config.dev.devtool, 22 | 23 | // these devServer options should be customized in /config/index.js 24 | devServer: { 25 | clientLogLevel: 'warning', 26 | historyApiFallback: { 27 | rewrites: [ 28 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, 29 | ], 30 | }, 31 | hot: true, 32 | contentBase: false, // since we use CopyWebpackPlugin. 33 | compress: true, 34 | host: HOST || config.dev.host, 35 | port: PORT || config.dev.port, 36 | open: config.dev.autoOpenBrowser, 37 | overlay: config.dev.errorOverlay 38 | ? { warnings: false, errors: true } 39 | : false, 40 | publicPath: config.dev.assetsPublicPath, 41 | proxy: config.dev.proxyTable, 42 | quiet: true, // necessary for FriendlyErrorsPlugin 43 | watchOptions: { 44 | poll: config.dev.poll, 45 | } 46 | }, 47 | plugins: [ 48 | new webpack.DefinePlugin({ 49 | 'process.env': require('../config/dev.env') 50 | }), 51 | new webpack.HotModuleReplacementPlugin(), 52 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 53 | new webpack.NoEmitOnErrorsPlugin(), 54 | // https://github.com/ampedandwired/html-webpack-plugin 55 | new HtmlWebpackPlugin({ 56 | filename: 'index.html', 57 | template: 'index.html', 58 | inject: true 59 | }), 60 | // copy custom static assets 61 | new CopyWebpackPlugin([ 62 | { 63 | from: path.resolve(__dirname, '../static'), 64 | to: config.dev.assetsSubDirectory, 65 | ignore: ['.*'] 66 | } 67 | ]) 68 | ] 69 | }) 70 | 71 | module.exports = new Promise((resolve, reject) => { 72 | portfinder.basePort = process.env.PORT || config.dev.port 73 | portfinder.getPort((err, port) => { 74 | if (err) { 75 | reject(err) 76 | } else { 77 | // publish the new Port, necessary for e2e tests 78 | process.env.PORT = port 79 | // add port to devServer config 80 | devWebpackConfig.devServer.port = port 81 | 82 | // Add FriendlyErrorsPlugin 83 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 84 | compilationSuccessInfo: { 85 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], 86 | }, 87 | onErrors: config.dev.notifyOnErrors 88 | ? utils.createNotifierCallback() 89 | : undefined 90 | })) 91 | 92 | resolve(devWebpackConfig) 93 | } 94 | }) 95 | }) 96 | -------------------------------------------------------------------------------- /server/writemd.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const moment = require('moment') 4 | const _ = require('underscore') 5 | const cloneDeep = require('clone-deep') 6 | 7 | const utils = require('./utils') 8 | 9 | const { 10 | RESP_PATH, 11 | RSS_PATH, 12 | LINKS_PATH, 13 | TAGS_PATH, 14 | README_PATH, 15 | README_TEMPLATE_PATH, 16 | TAGS_MD_PATH, 17 | TAGS_TEMPLATE_PATH, 18 | TIMELINE_MD_PATH, 19 | TIMELINE_TEMPLATE_PATH, 20 | DETAILS_TEMPLATE_PATH, 21 | } = utils.PATH 22 | 23 | /** 24 | * 渲染 README.md 文件 25 | */ 26 | function handlerREADME(newData){ 27 | newData = newData || { 28 | length: 0, 29 | titles: [], 30 | rss: {}, 31 | links: {} 32 | } 33 | 34 | let content = fs.readFileSync(README_TEMPLATE_PATH); 35 | 36 | let compiled = _.template(content.toString()); 37 | 38 | content = compiled({ 39 | newData, 40 | currentDate: utils.getNowDate(), 41 | linksJson: utils.getLinksJson(), 42 | formatTitle: utils.formatTitle, 43 | }); 44 | 45 | fs.writeFileSync(README_PATH, content, 'utf-8'); 46 | } 47 | 48 | /** 49 | * 渲染 TAGS.md 文件 50 | */ 51 | function handlerTags(){ 52 | let tags = require(TAGS_PATH); 53 | let data = utils.getLinksJson(); 54 | 55 | tags.forEach((tag, i) => { 56 | tags[i].items = []; 57 | 58 | data.forEach((o) => { 59 | o.items.forEach((item) => { 60 | if(!item.rssTitle && (new RegExp(tag.keywords, 'gi')).test(item.title)){ 61 | item.rssTitle = o.title; 62 | tags[i].items.push(item); 63 | } 64 | }); 65 | }); 66 | 67 | // details/tags/file.md 68 | let detailTpl = fs.readFileSync(DETAILS_TEMPLATE_PATH).toString(); 69 | let detailCompiled = _.template(detailTpl); 70 | const filename = tag.filename + '.md' 71 | 72 | const detailContent = detailCompiled({ 73 | currentDate: utils.getNowDate(), 74 | formatTitle: utils.formatTitle, 75 | title: tags[i].tag, 76 | keywords: tags[i].keywords, 77 | items: tags[i].items 78 | }); 79 | 80 | fs.writeFileSync(path.join(RESP_PATH, 'details/tags/', filename), detailContent, 'utf-8'); 81 | 82 | }); 83 | 84 | let content = fs.readFileSync(TAGS_TEMPLATE_PATH); 85 | let compiled = _.template(content.toString()); 86 | 87 | content = compiled({ 88 | currentDate: utils.getNowDate(), 89 | formatTitle: utils.formatTitle, 90 | tags 91 | }); 92 | 93 | fs.writeFileSync(TAGS_MD_PATH, content, 'utf-8'); 94 | } 95 | 96 | function handlerTimeline(){ 97 | let dataObj = {} 98 | let dataYears = [] 99 | let allLinks = utils.getLinksJson() 100 | 101 | allLinks.forEach((rss) => { 102 | rss.items.forEach((item) => { 103 | let year = item.date.substr(0, 4) 104 | let date = item.date.substr(0, 7) 105 | 106 | if(dataYears.indexOf(year) === -1){ 107 | dataYears.push(year) 108 | } 109 | 110 | item.rssTitle = rss.title; 111 | dataObj[date] = dataObj[date] || [] 112 | dataObj[date].push(item) 113 | }) 114 | }) 115 | 116 | let content = fs.readFileSync(TIMELINE_TEMPLATE_PATH); 117 | 118 | let compiled = _.template(content.toString()); 119 | 120 | content = compiled({ 121 | currentDate: utils.getNowDate(), 122 | dataObj, 123 | formatTitle: utils.formatTitle, 124 | dataYears, 125 | dataKeys: Object.keys(dataObj).sort().reverse() 126 | }); 127 | 128 | fs.writeFileSync(TIMELINE_MD_PATH, content, 'utf-8'); 129 | } 130 | 131 | /** 132 | * 生成每个详情页面 133 | */ 134 | function handlerDetails(newData){ 135 | newData = newData || { 136 | length: 0, 137 | titles: [], 138 | rss: {}, 139 | links: {} 140 | } 141 | let allLinks = utils.getLinksJson() 142 | let content = fs.readFileSync(DETAILS_TEMPLATE_PATH).toString(); 143 | let compiled = _.template(content); 144 | 145 | allLinks.forEach((source) => { 146 | if (source.rss in newData.rss){ 147 | source.currentDate = utils.getNowDate() 148 | source.formatTitle = utils.formatTitle 149 | 150 | content = compiled(source); 151 | 152 | let filename = source.title.replace(/[\\\/]/g, '') 153 | filename += '.md' 154 | 155 | fs.writeFileSync(path.join(RESP_PATH, 'details', filename), content, 'utf-8'); 156 | } 157 | }) 158 | } 159 | 160 | module.exports = function(newData){ 161 | handlerREADME(newData) 162 | handlerTags() 163 | handlerTimeline() 164 | handlerDetails(newData) 165 | } 166 | -------------------------------------------------------------------------------- /data/rss.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "武汉肺炎防疫全纪录(财新网)", 4 | "rss": "https://front-rss.herokuapp.com/coronavirus/caixin" 5 | }, 6 | { 7 | "title": "全国新型肺炎疫情实时动态(丁香园)", 8 | "rss": "https://front-rss.herokuapp.com/coronavirus/dxy" 9 | }, 10 | { 11 | "title": "Vue社区", 12 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/9891" 13 | }, 14 | { 15 | "title": "Vue中文社区", 16 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10315" 17 | }, 18 | { 19 | "title": "VUE全家桶", 20 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10646" 21 | }, 22 | { 23 | "title": "React中文社区", 24 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10445" 25 | }, 26 | { 27 | "title": "前端早读课", 28 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/5760" 29 | }, 30 | { 31 | "title": "前端大全", 32 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/65" 33 | }, 34 | { 35 | "title": "前端开发", 36 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/29" 37 | }, 38 | { 39 | "title": "前端圈", 40 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/166" 41 | }, 42 | { 43 | "title": "前端开发博客", 44 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/169" 45 | }, 46 | { 47 | "title": "前端大学", 48 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/892" 49 | }, 50 | { 51 | "title": "前端外刊评论", 52 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/895" 53 | }, 54 | { 55 | "title": "前端之巅", 56 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/154" 57 | }, 58 | { 59 | "title": "前端迷", 60 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/9457" 61 | }, 62 | { 63 | "title": "全栈前端精选", 64 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/9323" 65 | }, 66 | { 67 | "title": "政采云前端团队", 68 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10195" 69 | }, 70 | { 71 | "title": "前端宇宙", 72 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/8801" 73 | }, 74 | { 75 | "title": "前端瓶子君", 76 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10641" 77 | }, 78 | { 79 | "title": "程序员成长指北", 80 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10108" 81 | }, 82 | { 83 | "title": "Nodejs技术栈", 84 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10545" 85 | }, 86 | { 87 | "title": "张鑫旭-鑫空间-鑫生活", 88 | "rss": "https://www.zhangxinxu.com/wordpress/feed/" 89 | }, 90 | { 91 | "title": "阮一峰的网络日志", 92 | "rss": "http://www.ruanyifeng.com/blog/atom.xml" 93 | }, 94 | { 95 | "title": "京东设计中心", 96 | "rss": "http://jdc.jd.com/feed" 97 | }, 98 | { 99 | "title": "凹凸实验室", 100 | "rss": "https://aotu.io/atom.xml" 101 | }, 102 | { 103 | "title": "奇舞周刊", 104 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/6210" 105 | }, 106 | { 107 | "title": "前端日刊", 108 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/5762" 109 | }, 110 | { 111 | "title": "前端e进阶", 112 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10548" 113 | }, 114 | { 115 | "title": "互联网架构师", 116 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/6304" 117 | }, 118 | { 119 | "title": "InfoQ", 120 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/89" 121 | }, 122 | { 123 | "title": "JavaScript", 124 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/893" 125 | }, 126 | { 127 | "title": "掘金前端", 128 | "rss": "https://front-rss.herokuapp.com/juejin/category/frontend" 129 | }, 130 | { 131 | "title": "前端艺术家&&飞冰早报", 132 | "rss": "https://front-rss.herokuapp.com/jskou/0" 133 | }, 134 | { 135 | "title": "印记中文周刊", 136 | "rss": "https://front-rss.herokuapp.com/docschina/jsweekly" 137 | }, 138 | { 139 | "title": "编程之上", 140 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10647" 141 | }, 142 | { 143 | "title": "知乎日报", 144 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/198" 145 | }, 146 | { 147 | "title": "V2EX", 148 | "rss": "https://front-rss.herokuapp.com/v2ex/topics/latest" 149 | }, 150 | { 151 | "title": "技术头条", 152 | "rss": "https://front-rss.herokuapp.com/blogread/newest" 153 | }, 154 | { 155 | "title": "开发者头条", 156 | "rss": "https://front-rss.herokuapp.com/toutiao/today" 157 | }, 158 | { 159 | "title": "安全热点", 160 | "rss": "https://sec.thief.one/atom.xml" 161 | }, 162 | { 163 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/PQDgZ2jW", 164 | "title": "物联网智库" 165 | } 166 | ] 167 | -------------------------------------------------------------------------------- /server/fetch.js: -------------------------------------------------------------------------------- 1 | const queryString = require('query-string') 2 | const Parser = require('rss-parser') 3 | const moment = require('moment') 4 | 5 | const utils = require('./utils') 6 | 7 | const Fetch = async function(newData, linksJson, linksJsonIndex, jsonItem, rssItem, cb){ 8 | let rssArray = rssItem.rss 9 | let done = false; 10 | 11 | if(typeof rssArray === 'string'){ 12 | rssArray = [ rssArray ] 13 | } 14 | 15 | while(!done){ 16 | await fetchOne(0); 17 | } 18 | 19 | function fetchOne(index, onResolve){ 20 | return new Promise((resolve) => { 21 | onResolve = onResolve || resolve; 22 | 23 | let rss = rssArray[index]; 24 | let callDone = function(){ 25 | onResolve(); 26 | done = true; 27 | cb(null, jsonItem); 28 | } 29 | 30 | if(!rss) return callDone(); 31 | 32 | let parser = new Parser({ 33 | headers: { 34 | 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1' 35 | }, 36 | }); 37 | 38 | // 超时处理 39 | let finished = false; 40 | let timer = setTimeout(() => { 41 | if(!finished){ 42 | console.log(utils.getNowDate() + ' - 超时 RSS: ' + rss); 43 | finished = true 44 | fetchOne(index+1, onResolve); 45 | } 46 | }, 800000); 47 | 48 | console.log(utils.getNowDate() + ' - 开始 RSS: ' + rss); 49 | parser.parseURL(replaceRss(rss), function(err, feed) { 50 | if(finished) return; 51 | finished = true; 52 | clearTimeout(timer); 53 | 54 | let _items = jsonItem.items || [] 55 | let len = _items.length 56 | let items = [] 57 | 58 | if(!feed){ 59 | console.log(utils.getNowDate() + ' - 失败 RSS: ' + rss); 60 | feed = {}; 61 | feed.title = jsonItem.title 62 | feed.link = jsonItem.link 63 | feed.items = [] 64 | } 65 | 66 | feed.items.forEach(el => { 67 | let exist = false 68 | 69 | // for taobaofed 70 | if(/https?:\/\/taobaofed\.org/.test(el.link)) { 71 | el.link = el.link.replace(/https?:\/\/taobaofed\.org/, 'https://fed.taobao.org'); 72 | } 73 | 74 | for(let i = 0; i < len; i++){ 75 | if(isSameLink(_items[i].link, el.link)){ 76 | exist = true 77 | break; 78 | } 79 | } 80 | 81 | if(!exist){ 82 | let date = moment().format('YYYY-MM-DD') 83 | 84 | try{ 85 | date = moment(el.isoDate).format('YYYY-MM-DD') 86 | }catch(e){ 87 | } 88 | 89 | let itemObject = { 90 | title: el.title, 91 | link: el.link, 92 | date: date 93 | } 94 | 95 | items.push(itemObject) 96 | 97 | newData.rss[rss] = true 98 | newData.links[el.link] = true 99 | 100 | done = true; 101 | } 102 | }); 103 | 104 | feed.title = rssItem.title 105 | 106 | if(items.length){ 107 | newData.titles.push(feed.title) 108 | } 109 | 110 | newData.length += items.length 111 | 112 | jsonItem.rss = rss 113 | jsonItem.title = feed.title 114 | jsonItem.link = feed.link 115 | jsonItem.items = items.concat(_items) 116 | 117 | linksJson[linksJsonIndex] = jsonItem 118 | 119 | if(done){ 120 | console.log(utils.getNowDate() + ' - 完成 RSS: ' + rss); 121 | callDone(); 122 | }else{ 123 | fetchOne(index+1, onResolve); 124 | } 125 | }) 126 | }) 127 | } 128 | } 129 | 130 | function isSameLink(link, compare){ 131 | link = link.replace(/&/g, '&'); 132 | compare = compare.replace(/&/g, '&'); 133 | 134 | const oLink = queryString.parseUrl(link); 135 | const oCompare = queryString.parseUrl(compare); 136 | 137 | if(/mp\.weixin/.test(oLink.url)){ 138 | return (oLink.query.sn === oCompare.query.sn) 139 | && (oLink.query.mid === oCompare.query.mid) 140 | }else{ 141 | return link === compare 142 | } 143 | } 144 | 145 | 146 | // 加快速度,使用本地的 RSSHub 147 | let useLocalRSSHub = process.argv.indexOf('LOCAL_RSSHub') > -1 || process.argv.indexOf('--LOCAL_RSSHub') > -1 148 | function replaceRss(rss){ 149 | if(!useLocalRSSHub) return rss 150 | 151 | if(/rsshub\.app/.test(rss)){ 152 | console.log('https://front-rss.herokuapp.com ==> http://127.0.0.1:1200') 153 | } 154 | 155 | return rss.replace('https://front-rss.herokuapp.com', 'http://127.0.0.1:1200') 156 | } 157 | 158 | module.exports = Fetch; 159 | -------------------------------------------------------------------------------- /site/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 13 | 14 | const env = require('../config/prod.env') 15 | 16 | const webpackConfig = merge(baseWebpackConfig, { 17 | module: { 18 | rules: utils.styleLoaders({ 19 | sourceMap: config.build.productionSourceMap, 20 | extract: true, 21 | usePostCSS: true 22 | }) 23 | }, 24 | devtool: config.build.productionSourceMap ? config.build.devtool : false, 25 | output: { 26 | path: config.build.assetsRoot, 27 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 28 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 29 | }, 30 | plugins: [ 31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 32 | new webpack.DefinePlugin({ 33 | 'process.env': env 34 | }), 35 | new UglifyJsPlugin({ 36 | uglifyOptions: { 37 | compress: { 38 | warnings: false 39 | } 40 | }, 41 | sourceMap: config.build.productionSourceMap, 42 | parallel: true 43 | }), 44 | // extract css into its own file 45 | new ExtractTextPlugin({ 46 | filename: utils.assetsPath('css/[name].[contenthash].css'), 47 | // Setting the following option to `false` will not extract CSS from codesplit chunks. 48 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. 49 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 50 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 51 | allChunks: true, 52 | }), 53 | // Compress extracted CSS. We are using this plugin so that possible 54 | // duplicated CSS from different components can be deduped. 55 | new OptimizeCSSPlugin({ 56 | cssProcessorOptions: config.build.productionSourceMap 57 | ? { safe: true, map: { inline: false } } 58 | : { safe: true } 59 | }), 60 | // generate dist index.html with correct asset hash for caching. 61 | // you can customize output by editing /index.html 62 | // see https://github.com/ampedandwired/html-webpack-plugin 63 | new HtmlWebpackPlugin({ 64 | filename: config.build.index, 65 | template: 'index.html', 66 | inject: true, 67 | minify: { 68 | removeComments: true, 69 | collapseWhitespace: true, 70 | removeAttributeQuotes: true 71 | // more options: 72 | // https://github.com/kangax/html-minifier#options-quick-reference 73 | }, 74 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 75 | chunksSortMode: 'dependency' 76 | }), 77 | // keep module.id stable when vendor modules does not change 78 | new webpack.HashedModuleIdsPlugin(), 79 | // enable scope hoisting 80 | new webpack.optimize.ModuleConcatenationPlugin(), 81 | // split vendor js into its own file 82 | new webpack.optimize.CommonsChunkPlugin({ 83 | name: 'vendor', 84 | minChunks (module) { 85 | // any required modules inside node_modules are extracted to vendor 86 | return ( 87 | module.resource && 88 | /\.js$/.test(module.resource) && 89 | module.resource.indexOf( 90 | path.join(__dirname, '../node_modules') 91 | ) === 0 92 | ) 93 | } 94 | }), 95 | // extract webpack runtime and module manifest to its own file in order to 96 | // prevent vendor hash from being updated whenever app bundle is updated 97 | new webpack.optimize.CommonsChunkPlugin({ 98 | name: 'manifest', 99 | minChunks: Infinity 100 | }), 101 | // This instance extracts shared chunks from code splitted chunks and bundles them 102 | // in a separate chunk, similar to the vendor chunk 103 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 104 | new webpack.optimize.CommonsChunkPlugin({ 105 | name: 'app', 106 | async: 'vendor-async', 107 | children: true, 108 | minChunks: 3 109 | }), 110 | 111 | // copy custom static assets 112 | new CopyWebpackPlugin([ 113 | { 114 | from: path.resolve(__dirname, '../static'), 115 | to: config.build.assetsSubDirectory, 116 | ignore: ['.*'] 117 | } 118 | ]) 119 | ] 120 | }) 121 | 122 | if (config.build.productionGzip) { 123 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 124 | 125 | webpackConfig.plugins.push( 126 | new CompressionWebpackPlugin({ 127 | asset: '[path].gz[query]', 128 | algorithm: 'gzip', 129 | test: new RegExp( 130 | '\\.(' + 131 | config.build.productionGzipExtensions.join('|') + 132 | ')$' 133 | ), 134 | threshold: 10240, 135 | minRatio: 0.8 136 | }) 137 | ) 138 | } 139 | 140 | if (config.build.bundleAnalyzerReport) { 141 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 142 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 143 | } 144 | 145 | module.exports = webpackConfig 146 | -------------------------------------------------------------------------------- /server/links.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "rss": "https://rss.w4ctech.cn/coronavirus/caixin", 4 | "title": "武汉肺炎防疫全纪录(财新网)", 5 | "link": "http://m.app.caixin.com/m_topic_detail/1473.html", 6 | "items": [] 7 | }, 8 | { 9 | "rss": "https://rss.w4ctech.cn/coronavirus/dxy", 10 | "title": "全国新型肺炎疫情实时动态(丁香园)", 11 | "link": "https://3g.dxy.cn/newh5/view/pneumonia", 12 | "items": [] 13 | }, 14 | { 15 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/9891", 16 | "title": "Vue社区", 17 | "link": "https://www.ershicimi.com/a/9891", 18 | "items": [] 19 | }, 20 | { 21 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10315", 22 | "title": "Vue中文社区", 23 | "link": "https://www.ershicimi.com/a/10315", 24 | "items": [] 25 | }, 26 | { 27 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10646", 28 | "title": "VUE全家桶", 29 | "link": "https://www.ershicimi.com/a/10646", 30 | "items": [] 31 | }, 32 | { 33 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10445", 34 | "title": "React中文社区", 35 | "link": "https://www.ershicimi.com/a/10445", 36 | "items": [] 37 | }, 38 | { 39 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/5760", 40 | "title": "前端早读课", 41 | "link": "https://www.ershicimi.com/a/5760", 42 | "items": [] 43 | }, 44 | { 45 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/65", 46 | "title": "前端大全", 47 | "link": "https://www.ershicimi.com/a/65", 48 | "items": [] 49 | }, 50 | { 51 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/29", 52 | "title": "前端开发", 53 | "link": "https://www.ershicimi.com/a/29", 54 | "items": [] 55 | }, 56 | { 57 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/166", 58 | "title": "前端圈", 59 | "link": "https://www.ershicimi.com/a/166", 60 | "items": [] 61 | }, 62 | { 63 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/169", 64 | "title": "前端开发博客", 65 | "items": [], 66 | "link": "https://www.ershicimi.com/a/169" 67 | }, 68 | { 69 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/892", 70 | "title": "前端大学", 71 | "items": [], 72 | "link": "https://www.ershicimi.com/a/892" 73 | }, 74 | { 75 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/895", 76 | "title": "前端外刊评论", 77 | "items": [], 78 | "link": "https://www.ershicimi.com/a/895" 79 | }, 80 | { 81 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/154", 82 | "title": "前端之巅", 83 | "link": "https://www.ershicimi.com/a/154", 84 | "items": [] 85 | }, 86 | { 87 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/9457", 88 | "title": "前端迷", 89 | "link": "https://www.ershicimi.com/a/9457", 90 | "items": [] 91 | }, 92 | { 93 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/9323", 94 | "title": "全栈前端精选", 95 | "link": "https://www.ershicimi.com/a/9323", 96 | "items": [] 97 | }, 98 | { 99 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10195", 100 | "title": "政采云前端团队", 101 | "link": "https://www.ershicimi.com/a/10195", 102 | "items": [] 103 | }, 104 | { 105 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/8801", 106 | "title": "前端宇宙", 107 | "link": "https://www.ershicimi.com/a/8801", 108 | "items": [] 109 | }, 110 | { 111 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10641", 112 | "title": "前端瓶子君", 113 | "items": [], 114 | "link": "https://www.ershicimi.com/a/10641" 115 | }, 116 | { 117 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10108", 118 | "title": "程序员成长指北", 119 | "link": "https://www.ershicimi.com/a/10108", 120 | "items": [] 121 | }, 122 | { 123 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10545", 124 | "title": "Nodejs技术栈", 125 | "link": "https://www.ershicimi.com/a/10545", 126 | "items": [] 127 | }, 128 | { 129 | "rss": "https://www.zhangxinxu.com/wordpress/feed/", 130 | "title": "张鑫旭-鑫空间-鑫生活", 131 | "link": "https://www.zhangxinxu.com/wordpress", 132 | "items": [] 133 | }, 134 | { 135 | "rss": "http://www.ruanyifeng.com/blog/atom.xml", 136 | "title": "阮一峰的网络日志", 137 | "link": "http://www.ruanyifeng.com/blog/", 138 | "items": [] 139 | }, 140 | { 141 | "rss": "http://jdc.jd.com/feed", 142 | "title": "京东设计中心", 143 | "items": [], 144 | "link": "https://jdc.jd.com" 145 | }, 146 | { 147 | "rss": "https://aotu.io/atom.xml", 148 | "title": "凹凸实验室", 149 | "link": "/atom.xml", 150 | "items": [] 151 | }, 152 | { 153 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/6210", 154 | "title": "奇舞周刊", 155 | "link": "https://www.ershicimi.com/a/6210", 156 | "items": [] 157 | }, 158 | { 159 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/5762", 160 | "title": "前端日刊", 161 | "link": "https://www.ershicimi.com/a/5762", 162 | "items": [] 163 | }, 164 | { 165 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10548", 166 | "title": "前端e进阶", 167 | "link": "https://www.ershicimi.com/a/10548", 168 | "items": [] 169 | }, 170 | { 171 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/6304", 172 | "title": "互联网架构师", 173 | "link": "https://www.ershicimi.com/a/6304", 174 | "items": [] 175 | }, 176 | { 177 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/89", 178 | "title": "InfoQ", 179 | "link": "https://www.ershicimi.com/a/89", 180 | "items": [] 181 | }, 182 | { 183 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/893", 184 | "title": "JavaScript", 185 | "link": "https://www.ershicimi.com/a/893", 186 | "items": [] 187 | }, 188 | { 189 | "rss": "https://rss.w4ctech.cn/juejin/category/frontend", 190 | "title": "掘金前端", 191 | "link": "https://juejin.im/welcome/frontend", 192 | "items": [] 193 | }, 194 | { 195 | "rss": "https://rss.w4ctech.cn/jskou/0", 196 | "title": "前端艺术家&&飞冰早报", 197 | "link": "http://fe.jskou.com/", 198 | "items": [] 199 | }, 200 | { 201 | "rss": "https://rss.w4ctech.cn/docschina/jsweekly", 202 | "title": "印记中文周刊", 203 | "link": "https://weekly.docschina.org", 204 | "items": [] 205 | }, 206 | { 207 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/10647", 208 | "title": "编程之上", 209 | "link": "https://www.ershicimi.com/a/10647", 210 | "items": [] 211 | }, 212 | { 213 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/198", 214 | "title": "知乎日报", 215 | "link": "https://www.ershicimi.com/a/198", 216 | "items": [] 217 | }, 218 | { 219 | "rss": "https://rss.w4ctech.cn/v2ex/topics/latest", 220 | "title": "V2EX", 221 | "link": "https://www.v2ex.com/", 222 | "items": [] 223 | }, 224 | { 225 | "rss": "https://rss.w4ctech.cn/blogread/newest", 226 | "title": "技术头条", 227 | "link": "http://blogread.cn/news/newest.php", 228 | "items": [] 229 | }, 230 | { 231 | "rss": "https://rss.w4ctech.cn/toutiao/today", 232 | "title": "开发者头条", 233 | "link": "https://toutiao.io", 234 | "items": [] 235 | }, 236 | { 237 | "rss": "https://sec.thief.one/atom.xml", 238 | "title": "安全热点", 239 | "link": "https://sec.thief.one", 240 | "items": [] 241 | }, 242 | { 243 | "rss": "https://rss.w4ctech.cn/wechat/ershicimi/PQDgZ2jW", 244 | "title": "物联网智库", 245 | "link": "https://www.ershicimi.com/p", 246 | "items": [] 247 | } 248 | ] 249 | -------------------------------------------------------------------------------- /TAGS.md: -------------------------------------------------------------------------------- 1 | > 提示:只是根据标题文案简单匹配分类 2 | 3 | :alarm_clock: 更新时间: 2025-12-13 23:00:43。[来源分类](./README.md)、[时间分类](./TIMELINE.md) 4 | 5 | ## 标签分类 6 | 7 | - [React](#react) 8 | - [Vue](#vue) 9 | - [TypeScript](#typescript) 10 | - [Webpack、NPM、构建相关](#webpack、npm、构建相关) 11 | - [NodeJS](#nodejs) 12 | - [小程序](#小程序) 13 | - [移动开发、Flutter相关](#移动开发、flutter相关) 14 | - [游戏开发](#游戏开发) 15 | - [JavaScript](#javascript) 16 | - [CSS](#css) 17 | - [Canvas、SVG、图像](#canvas、svg、图像) 18 | - [音视频相关](#音视频相关) 19 | - [性能优化](#性能优化) 20 | - [浏览器相关](#浏览器相关) 21 | - [前端进阶相关](#前端进阶相关) 22 | - [服务端相关](#服务端相关) 23 | - [Git、SVN](#git、svn) 24 | - [招聘面试](#招聘面试) 25 | - [面向对象❤️](#面向对象❤️) 26 | - [肺炎疫情](#肺炎疫情) 27 | - [其它](#其它) 28 | 29 | ## 文章链接 30 | 31 |
32 | 33 | React 34 | 35 |

36 | 37 | 38 | > 关键字:`React`、`Rax`、`Nerv`、`Redux`、`useEffect`、`Hooks` 39 | 40 | 41 | 42 | - [......【查看更多】......](./details/tags/react.md) 43 | 44 |
⬆返回顶部
45 |
46 | 47 |
48 | 49 | Vue 50 | 51 |

52 | 53 | 54 | > 关键字:`Vue`、`ElementUI` 55 | 56 | 57 | 58 | - [......【查看更多】......](./details/tags/vue.md) 59 | 60 |
⬆返回顶部
61 |
62 | 63 |
64 | 65 | TypeScript 66 | 67 |

68 | 69 | 70 | > 关键字:`TypeScript` 71 | 72 | 73 | 74 | - [......【查看更多】......](./details/tags/typescript.md) 75 | 76 |
⬆返回顶部
77 |
78 | 79 |
80 | 81 | Webpack、NPM、构建相关 82 | 83 |

84 | 85 | 86 | > 关键字:`Webpack`、`Lerna`、`Rollup`、`NPM`、`NPX`、`Yarn`、`Gulp`、`Grunt`、`Babel`、`ESLint`、`TSLint`、`构建` 87 | 88 | 89 | 90 | - [......【查看更多】......](./details/tags/pack-build.md) 91 | 92 |
⬆返回顶部
93 |
94 | 95 |
96 | 97 | NodeJS 98 | 99 |

100 | 101 | 102 | > 关键字:`Node`、`Node.js`、`Express`、`Koa`、`egg.js`、`pandora.js`、`Electron`、`V8` 103 | 104 | 105 | 106 | - [......【查看更多】......](./details/tags/nodejs.md) 107 | 108 |
⬆返回顶部
109 |
110 | 111 |
112 | 113 | 小程序 114 | 115 |

116 | 117 | 118 | > 关键字:`小程序`、`Taro`、`MPVue`、`Wepy`、`Chameleon` 119 | 120 | 121 | 122 | - [......【查看更多】......](./details/tags/miniprogram.md) 123 | 124 |
⬆返回顶部
125 |
126 | 127 |
128 | 129 | 移动开发、Flutter相关 130 | 131 |

132 | 133 | 134 | > 关键字:`Flutter`、`PWA`、`移动开发` 135 | 136 | 137 | 138 | - [......【查看更多】......](./details/tags/dev-mobile.md) 139 | 140 |
⬆返回顶部
141 |
142 | 143 |
144 | 145 | 游戏开发 146 | 147 |

148 | 149 | 150 | > 关键字:`游戏`、`Three.js`、`Create.js`、`Matter.js` 151 | 152 | 153 | 154 | - [......【查看更多】......](./details/tags/dev-game.md) 155 | 156 |
⬆返回顶部
157 |
158 | 159 |
160 | 161 | JavaScript 162 | 163 |

164 | 165 | 166 | > 关键字:`JavaScript`、`ECMAScript`、`JS`、`ES6`、`Promise`、`document`、`await`、`async`、`decorator`、`module`、`import`、`catch`、`console`、`setInterval`、`Worker`、`fetch`、`this`、`bind`、`DataTransfer`、`ArrayBuffer`、`Component`、`DOM`、`H5`、`HTML5`、`组件`、`正则`、`数组`、`事件`、`深拷贝`、`数据代理`、`变量`、`函数式`、`声明式`、`异步`、`表单`、`滚动`、`scroll`、`防抖`、`适配`、`路由`、`模块化` 167 | 168 | 169 | 170 | - [【张鑫旭-鑫空间-鑫生活】介绍下与CSS自定义组件相关的:state函数](https://www.zhangxinxu.com/wordpress/2025/11/css-state-function/) 171 | - [......【查看更多】......](./details/tags/javascript.md) 172 | 173 |
⬆返回顶部
174 |
175 | 176 |
177 | 178 | CSS 179 | 180 |

181 | 182 | 183 | > 关键字:`CSS`、`Sass`、`Less`、`scale`、`transform`、`transition`、`animation`、`border`、`background`、`font-weight`、`font-face`、`flex`、`display`、`position`、`居中`、`动画` 184 | 185 | 186 | 187 | - [【张鑫旭-鑫空间-鑫生活】CSS-progress函数简介](https://www.zhangxinxu.com/wordpress/2025/12/css-progress-function/) 188 | - [【张鑫旭-鑫空间-鑫生活】巧用CSS-::details-content伪元素实现任意展开动画](https://www.zhangxinxu.com/wordpress/2025/11/css-details-target-content-open/) 189 | - [......【查看更多】......](./details/tags/css.md) 190 | 191 |
⬆返回顶部
192 |
193 | 194 |
195 | 196 | Canvas、SVG、图像 197 | 198 |

199 | 200 | 201 | > 关键字:`Canvas`、`SVG`、`WebGL`、`3D`、`PNG`、`WebP`、`RGB`、`GUI` 202 | 203 | 204 | 205 | - [......【查看更多】......](./details/tags/canvas-image.md) 206 | 207 |
⬆返回顶部
208 |
209 | 210 |
211 | 212 | 音视频相关 213 | 214 |

215 | 216 | 217 | > 关键字:`WebVR`、`WebRTC`、`Video`、`Audio`、`图像`、`音频`、`视频`、`直播`、`摄像头`、`播放器` 218 | 219 | 220 | 221 | - [......【查看更多】......](./details/tags/audio-video.md) 222 | 223 |
⬆返回顶部
224 |
225 | 226 |
227 | 228 | 性能优化 229 | 230 |

231 | 232 | 233 | > 关键字:`性能`、`优化`、`加载`、`SEO`、`Hints`、`Prefetch`、`Prerender`、`Preload` 234 | 235 | 236 | 237 | - [......【查看更多】......](./details/tags/optimization.md) 238 | 239 |
⬆返回顶部
240 |
241 | 242 |
243 | 244 | 浏览器相关 245 | 246 |

247 | 248 | 249 | > 关键字:`Chrome`、`Chromium`、`IE`、`Firefox`、`Safari`、`Webkit`、`Edge`、`WebSocket`、`GET`、`POST`、`CORS`、`URL`、`浏览器`、`调试`、`缓存`、`跨域`、`请求`、`安全`、`状态码`、`重绘`、`重排`、`渲染` 250 | 251 | 252 | 253 | - [【张鑫旭-鑫空间-鑫生活】醒醒,该使用CookieStore新建和管理cookie了](https://www.zhangxinxu.com/wordpress/2025/11/js-cookiestore-cookie/) 254 | - [......【查看更多】......](./details/tags/browser.md) 255 | 256 |
⬆返回顶部
257 |
258 | 259 |
260 | 261 | 前端进阶相关 262 | 263 |

264 | 265 | 266 | > 关键字:`AST`、`GPU`、`WebAssembly`、`Vim`、`HTTP`、`算法`、`全栈` 267 | 268 | 269 | 270 | - [......【查看更多】......](./details/tags/front-end-advanced.md) 271 | 272 |
⬆返回顶部
273 |
274 | 275 |
276 | 277 | 服务端相关 278 | 279 |

280 | 281 | 282 | > 关键字:`Nginx`、`Docker`、`GraphQL`、`REST`、`gRPC` 283 | 284 | 285 | 286 | - [......【查看更多】......](./details/tags/server.md) 287 | 288 |
⬆返回顶部
289 |
290 | 291 |
292 | 293 | Git、SVN 294 | 295 |

296 | 297 | 298 | > 关键字:`Git`、`SVN` 299 | 300 | 301 | 302 | - [......【查看更多】......](./details/tags/git-svn.md) 303 | 304 |
⬆返回顶部
305 |
306 | 307 |
308 | 309 | 招聘面试 310 | 311 |

312 | 313 | 314 | > 关键字:`招聘`、`面试` 315 | 316 | 317 | 318 | - [......【查看更多】......](./details/tags/job-interview.md) 319 | 320 |
⬆返回顶部
321 |
322 | 323 |
324 | 325 | 面向对象❤️ 326 | 327 |

328 | 329 | 330 | > 关键字:`面向对象` 331 | 332 | 333 | 334 | - [......【查看更多】......](./details/tags/oop.md) 335 | 336 |
⬆返回顶部
337 |
338 | 339 |
340 | 341 | 肺炎疫情 342 | 343 |

344 | 345 | 346 | > 关键字:`肺炎`、`肺炎疫情`、`武汉肺炎` 347 | 348 | 349 | 350 | - [......【查看更多】......](./details/tags/肺炎疫情.md) 351 | 352 |
⬆返回顶部
353 |
354 | 355 |
356 | 357 | 其它 358 | 359 |

360 | 361 | 362 | 363 | 364 | - [【张鑫旭-鑫空间-鑫生活】单IMG标签的图片内阴影效果实现](https://www.zhangxinxu.com/wordpress/2025/12/img-inset-shadow/) 365 | - [......【查看更多】......](./details/tags/other.md) 366 | 367 |
⬆返回顶部
368 |
369 | 370 | -------------------------------------------------------------------------------- /data/links.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "rss": "https://front-rss.herokuapp.com/coronavirus/caixin", 4 | "title": "武汉肺炎防疫全纪录(财新网)", 5 | "link": "http://m.app.caixin.com/m_topic_detail/1473.html", 6 | "items": [] 7 | }, 8 | { 9 | "rss": "https://front-rss.herokuapp.com/coronavirus/dxy", 10 | "title": "全国新型肺炎疫情实时动态(丁香园)", 11 | "link": "https://3g.dxy.cn/newh5/view/pneumonia", 12 | "items": [] 13 | }, 14 | { 15 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/9891", 16 | "title": "Vue社区", 17 | "link": "https://www.ershicimi.com/a/9891", 18 | "items": [] 19 | }, 20 | { 21 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10315", 22 | "title": "Vue中文社区", 23 | "link": "https://www.ershicimi.com/a/10315", 24 | "items": [] 25 | }, 26 | { 27 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10646", 28 | "title": "VUE全家桶", 29 | "link": "https://www.ershicimi.com/a/10646", 30 | "items": [] 31 | }, 32 | { 33 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10445", 34 | "title": "React中文社区", 35 | "link": "https://www.ershicimi.com/a/10445", 36 | "items": [] 37 | }, 38 | { 39 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/5760", 40 | "title": "前端早读课", 41 | "link": "https://www.ershicimi.com/a/5760", 42 | "items": [] 43 | }, 44 | { 45 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/65", 46 | "title": "前端大全", 47 | "link": "https://www.ershicimi.com/a/65", 48 | "items": [] 49 | }, 50 | { 51 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/29", 52 | "title": "前端开发", 53 | "link": "https://www.ershicimi.com/a/29", 54 | "items": [] 55 | }, 56 | { 57 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/166", 58 | "title": "前端圈", 59 | "link": "https://www.ershicimi.com/a/166", 60 | "items": [] 61 | }, 62 | { 63 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/169", 64 | "title": "前端开发博客", 65 | "items": [], 66 | "link": "https://www.ershicimi.com/a/169" 67 | }, 68 | { 69 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/892", 70 | "title": "前端大学", 71 | "items": [], 72 | "link": "https://www.ershicimi.com/a/892" 73 | }, 74 | { 75 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/895", 76 | "title": "前端外刊评论", 77 | "items": [], 78 | "link": "https://www.ershicimi.com/a/895" 79 | }, 80 | { 81 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/154", 82 | "title": "前端之巅", 83 | "link": "https://www.ershicimi.com/a/154", 84 | "items": [] 85 | }, 86 | { 87 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/9457", 88 | "title": "前端迷", 89 | "link": "https://www.ershicimi.com/a/9457", 90 | "items": [] 91 | }, 92 | { 93 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/9323", 94 | "title": "全栈前端精选", 95 | "link": "https://www.ershicimi.com/a/9323", 96 | "items": [] 97 | }, 98 | { 99 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10195", 100 | "title": "政采云前端团队", 101 | "link": "https://www.ershicimi.com/a/10195", 102 | "items": [] 103 | }, 104 | { 105 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/8801", 106 | "title": "前端宇宙", 107 | "link": "https://www.ershicimi.com/a/8801", 108 | "items": [] 109 | }, 110 | { 111 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10641", 112 | "title": "前端瓶子君", 113 | "items": [], 114 | "link": "https://www.ershicimi.com/a/10641" 115 | }, 116 | { 117 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10108", 118 | "title": "程序员成长指北", 119 | "link": "https://www.ershicimi.com/a/10108", 120 | "items": [] 121 | }, 122 | { 123 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10545", 124 | "title": "Nodejs技术栈", 125 | "link": "https://www.ershicimi.com/a/10545", 126 | "items": [] 127 | }, 128 | { 129 | "rss": "https://www.zhangxinxu.com/wordpress/feed/", 130 | "title": "张鑫旭-鑫空间-鑫生活", 131 | "link": "https://www.zhangxinxu.com/wordpress", 132 | "items": [ 133 | { 134 | "title": "CSS progress()函数简介", 135 | "link": "https://www.zhangxinxu.com/wordpress/2025/12/css-progress-function/", 136 | "date": "2025-12-12" 137 | }, 138 | { 139 | "title": "单IMG标签的图片内阴影效果实现", 140 | "link": "https://www.zhangxinxu.com/wordpress/2025/12/img-inset-shadow/", 141 | "date": "2025-12-04" 142 | }, 143 | { 144 | "title": "醒醒,该使用CookieStore新建和管理cookie了", 145 | "link": "https://www.zhangxinxu.com/wordpress/2025/11/js-cookiestore-cookie/", 146 | "date": "2025-11-28" 147 | }, 148 | { 149 | "title": "巧用CSS ::details-content伪元素实现任意展开动画", 150 | "link": "https://www.zhangxinxu.com/wordpress/2025/11/css-details-target-content-open/", 151 | "date": "2025-11-24" 152 | }, 153 | { 154 | "title": "介绍下与CSS自定义组件相关的:state()函数", 155 | "link": "https://www.zhangxinxu.com/wordpress/2025/11/css-state-function/", 156 | "date": "2025-11-17" 157 | } 158 | ] 159 | }, 160 | { 161 | "rss": "http://www.ruanyifeng.com/blog/atom.xml", 162 | "title": "阮一峰的网络日志", 163 | "link": "http://www.ruanyifeng.com/blog/", 164 | "items": [] 165 | }, 166 | { 167 | "rss": "http://jdc.jd.com/feed", 168 | "title": "京东设计中心", 169 | "items": [], 170 | "link": "https://jdc.jd.com" 171 | }, 172 | { 173 | "rss": "https://aotu.io/atom.xml", 174 | "title": "凹凸实验室", 175 | "link": "/atom.xml", 176 | "items": [] 177 | }, 178 | { 179 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/6210", 180 | "title": "奇舞周刊", 181 | "link": "https://www.ershicimi.com/a/6210", 182 | "items": [] 183 | }, 184 | { 185 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/5762", 186 | "title": "前端日刊", 187 | "link": "https://www.ershicimi.com/a/5762", 188 | "items": [] 189 | }, 190 | { 191 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10548", 192 | "title": "前端e进阶", 193 | "link": "https://www.ershicimi.com/a/10548", 194 | "items": [] 195 | }, 196 | { 197 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/6304", 198 | "title": "互联网架构师", 199 | "link": "https://www.ershicimi.com/a/6304", 200 | "items": [] 201 | }, 202 | { 203 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/89", 204 | "title": "InfoQ", 205 | "link": "https://www.ershicimi.com/a/89", 206 | "items": [] 207 | }, 208 | { 209 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/893", 210 | "title": "JavaScript", 211 | "link": "https://www.ershicimi.com/a/893", 212 | "items": [] 213 | }, 214 | { 215 | "rss": "https://front-rss.herokuapp.com/juejin/category/frontend", 216 | "title": "掘金前端", 217 | "link": "https://juejin.im/welcome/frontend", 218 | "items": [] 219 | }, 220 | { 221 | "rss": "https://front-rss.herokuapp.com/jskou/0", 222 | "title": "前端艺术家&&飞冰早报", 223 | "link": "http://fe.jskou.com/", 224 | "items": [] 225 | }, 226 | { 227 | "rss": "https://front-rss.herokuapp.com/docschina/jsweekly", 228 | "title": "印记中文周刊", 229 | "link": "https://weekly.docschina.org", 230 | "items": [] 231 | }, 232 | { 233 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/10647", 234 | "title": "编程之上", 235 | "link": "https://www.ershicimi.com/a/10647", 236 | "items": [] 237 | }, 238 | { 239 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/198", 240 | "title": "知乎日报", 241 | "link": "https://www.ershicimi.com/a/198", 242 | "items": [] 243 | }, 244 | { 245 | "rss": "https://front-rss.herokuapp.com/v2ex/topics/latest", 246 | "title": "V2EX", 247 | "link": "https://www.v2ex.com/", 248 | "items": [] 249 | }, 250 | { 251 | "rss": "https://front-rss.herokuapp.com/blogread/newest", 252 | "title": "技术头条", 253 | "link": "http://blogread.cn/news/newest.php", 254 | "items": [] 255 | }, 256 | { 257 | "rss": "https://front-rss.herokuapp.com/toutiao/today", 258 | "title": "开发者头条", 259 | "link": "https://toutiao.io", 260 | "items": [] 261 | }, 262 | { 263 | "rss": "https://sec.thief.one/atom.xml", 264 | "title": "安全热点", 265 | "link": "https://sec.thief.one", 266 | "items": [] 267 | }, 268 | { 269 | "rss": "https://front-rss.herokuapp.com/wechat/ershicimi/PQDgZ2jW", 270 | "title": "物联网智库", 271 | "link": "https://www.ershicimi.com/p", 272 | "items": [] 273 | } 274 | ] -------------------------------------------------------------------------------- /server/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | async@^2.6.1: 6 | version "2.6.3" 7 | resolved "https://registry.npm.taobao.org/async/download/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" 8 | integrity sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8= 9 | dependencies: 10 | lodash "^4.17.14" 11 | 12 | axios@^0.19.1: 13 | version "0.19.2" 14 | resolved "https://registry.npm.taobao.org/axios/download/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" 15 | integrity sha1-PqNsXYgY0NX4qKl6bTa4bNwAyyc= 16 | dependencies: 17 | follow-redirects "1.5.10" 18 | 19 | balanced-match@^1.0.0: 20 | version "1.0.0" 21 | resolved "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 22 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 23 | 24 | brace-expansion@^1.1.7: 25 | version "1.1.11" 26 | resolved "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 27 | integrity sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0= 28 | dependencies: 29 | balanced-match "^1.0.0" 30 | concat-map "0.0.1" 31 | 32 | clone-deep@^4.0.0: 33 | version "4.0.1" 34 | resolved "https://registry.npm.taobao.org/clone-deep/download/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" 35 | integrity sha1-wZ/Zvbv4WUK0/ZechNz31fB8I4c= 36 | dependencies: 37 | is-plain-object "^2.0.4" 38 | kind-of "^6.0.2" 39 | shallow-clone "^3.0.0" 40 | 41 | concat-map@0.0.1: 42 | version "0.0.1" 43 | resolved "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 44 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 45 | 46 | debug@=3.1.0: 47 | version "3.1.0" 48 | resolved "https://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 49 | integrity sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE= 50 | dependencies: 51 | ms "2.0.0" 52 | 53 | debug@^4.0.1: 54 | version "4.1.1" 55 | resolved "https://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" 56 | integrity sha1-O3ImAlUQnGtYnO4FDx1RYTlmR5E= 57 | dependencies: 58 | ms "^2.1.1" 59 | 60 | decode-uri-component@^0.2.0: 61 | version "0.2.0" 62 | resolved "https://registry.npm.taobao.org/decode-uri-component/download/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" 63 | integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= 64 | 65 | entities@^1.1.1: 66 | version "1.1.2" 67 | resolved "https://registry.npm.taobao.org/entities/download/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" 68 | integrity sha1-vfpzUplmTfr9NFKe1PhSKidf6lY= 69 | 70 | follow-redirects@1.5.10: 71 | version "1.5.10" 72 | resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" 73 | integrity sha1-e3qfmuov3/NnhqlP9kPtB/T/Xio= 74 | dependencies: 75 | debug "=3.1.0" 76 | 77 | fs.realpath@^1.0.0: 78 | version "1.0.0" 79 | resolved "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 80 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 81 | 82 | glob@^7.1.3: 83 | version "7.1.6" 84 | resolved "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 85 | integrity sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY= 86 | dependencies: 87 | fs.realpath "^1.0.0" 88 | inflight "^1.0.4" 89 | inherits "2" 90 | minimatch "^3.0.4" 91 | once "^1.3.0" 92 | path-is-absolute "^1.0.0" 93 | 94 | inflight@^1.0.4: 95 | version "1.0.6" 96 | resolved "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 97 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 98 | dependencies: 99 | once "^1.3.0" 100 | wrappy "1" 101 | 102 | inherits@2: 103 | version "2.0.4" 104 | resolved "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 105 | integrity sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w= 106 | 107 | is-plain-object@^2.0.4: 108 | version "2.0.4" 109 | resolved "https://registry.npm.taobao.org/is-plain-object/download/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" 110 | integrity sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc= 111 | dependencies: 112 | isobject "^3.0.1" 113 | 114 | isobject@^3.0.1: 115 | version "3.0.1" 116 | resolved "https://registry.npm.taobao.org/isobject/download/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" 117 | integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= 118 | 119 | kind-of@^6.0.2: 120 | version "6.0.3" 121 | resolved "https://registry.npm.taobao.org/kind-of/download/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" 122 | integrity sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0= 123 | 124 | later@^1.2.0: 125 | version "1.2.0" 126 | resolved "https://registry.npm.taobao.org/later/download/later-1.2.0.tgz#f2cf6c4dd7956dd2f520adf0329836e9876bad0f" 127 | integrity sha1-8s9sTdeVbdL1IK3wMpg26YdrrQ8= 128 | 129 | lodash@^4.17.14: 130 | version "4.17.15" 131 | resolved "https://registry.npm.taobao.org/lodash/download/lodash-4.17.15.tgz?cache=0&sync_timestamp=1577793955950&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flodash%2Fdownload%2Flodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 132 | integrity sha1-tEf2ZwoEVbv+7dETku/zMOoJdUg= 133 | 134 | minimatch@^3.0.4: 135 | version "3.0.4" 136 | resolved "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 137 | integrity sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM= 138 | dependencies: 139 | brace-expansion "^1.1.7" 140 | 141 | moment@^2.22.2: 142 | version "2.24.0" 143 | resolved "https://registry.npm.taobao.org/moment/download/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" 144 | integrity sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s= 145 | 146 | ms@2.0.0: 147 | version "2.0.0" 148 | resolved "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 149 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 150 | 151 | ms@^2.1.1: 152 | version "2.1.2" 153 | resolved "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 154 | integrity sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk= 155 | 156 | once@^1.3.0: 157 | version "1.4.0" 158 | resolved "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 159 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 160 | dependencies: 161 | wrappy "1" 162 | 163 | path-is-absolute@^1.0.0: 164 | version "1.0.1" 165 | resolved "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 166 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 167 | 168 | query-string@^6.8.1: 169 | version "6.10.1" 170 | resolved "https://registry.npm.taobao.org/query-string/download/query-string-6.10.1.tgz?cache=0&sync_timestamp=1579245592551&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fquery-string%2Fdownload%2Fquery-string-6.10.1.tgz#30b3505f6fca741d5ae541964d1b3ae9dc2a0de8" 171 | integrity sha1-MLNQX2/KdB1a5UGWTRs66dwqDeg= 172 | dependencies: 173 | decode-uri-component "^0.2.0" 174 | split-on-first "^1.0.0" 175 | strict-uri-encode "^2.0.0" 176 | 177 | rimraf@^3.0.0: 178 | version "3.0.0" 179 | resolved "https://registry.npm.taobao.org/rimraf/download/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b" 180 | integrity sha1-YUF21LMBC3Xlw5DrDulvbcDOu5s= 181 | dependencies: 182 | glob "^7.1.3" 183 | 184 | rss-parser@^3.4.3: 185 | version "3.7.3" 186 | resolved "https://registry.npm.taobao.org/rss-parser/download/rss-parser-3.7.3.tgz#961cd155ca26cb2ba8f52aa7f2321099b8b5ecf0" 187 | integrity sha1-lhzRVcomyyuo9Sqn8jIQmbi17PA= 188 | dependencies: 189 | entities "^1.1.1" 190 | xml2js "^0.4.19" 191 | 192 | sax@>=0.6.0: 193 | version "1.2.4" 194 | resolved "https://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" 195 | integrity sha1-KBYjTiN4vdxOU1T6tcqold9xANk= 196 | 197 | shallow-clone@^3.0.0: 198 | version "3.0.1" 199 | resolved "https://registry.npm.taobao.org/shallow-clone/download/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" 200 | integrity sha1-jymBrZJTH1UDWwH7IwdppA4C76M= 201 | dependencies: 202 | kind-of "^6.0.2" 203 | 204 | simple-git@^1.102.0: 205 | version "1.130.0" 206 | resolved "https://registry.npm.taobao.org/simple-git/download/simple-git-1.130.0.tgz#b689c4163bc021df563a81f256de54482005195d" 207 | integrity sha1-tonEFjvAId9WOoHyVt5USCAFGV0= 208 | dependencies: 209 | debug "^4.0.1" 210 | 211 | split-on-first@^1.0.0: 212 | version "1.1.0" 213 | resolved "https://registry.npm.taobao.org/split-on-first/download/split-on-first-1.1.0.tgz?cache=0&sync_timestamp=1573632118941&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsplit-on-first%2Fdownload%2Fsplit-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" 214 | integrity sha1-9hCv7uOxK84dDDBCXnY5i3gkml8= 215 | 216 | strict-uri-encode@^2.0.0: 217 | version "2.0.0" 218 | resolved "https://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" 219 | integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= 220 | 221 | underscore@^1.12.1: 222 | version "1.12.1" 223 | resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" 224 | integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== 225 | 226 | wrappy@1: 227 | version "1.0.2" 228 | resolved "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 229 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 230 | 231 | xml2js@^0.4.19: 232 | version "0.4.23" 233 | resolved "https://registry.npm.taobao.org/xml2js/download/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" 234 | integrity sha1-oMaVFnUkIesqx1juTUzPWIQ+rGY= 235 | dependencies: 236 | sax ">=0.6.0" 237 | xmlbuilder "~11.0.0" 238 | 239 | xmlbuilder@~11.0.0: 240 | version "11.0.1" 241 | resolved "https://registry.npm.taobao.org/xmlbuilder/download/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" 242 | integrity sha1-vpuuHIoEbnazESdyY0fQrXACvrM= 243 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Front-End RSS

点击右上角 Watch 订阅 最新前端技术文章

2 | https://front-end-rss.w4ctech.cn 3 |
4 | 5 | ## 6 | 7 | - 项目目的:每天定时抓取最新前端技术文章,并推送到 GitHub 方便查看 8 | - 文章来源:RSS 订阅源 9 | - 定时抓取:每30分钟一次 10 | - 文章分类:[标签分类](./TAGS.md)、[时间分类](./TIMELINE.md) 11 | 12 | ## 13 | 14 | :alarm_clock: 更新时间: 2025-12-13 23:00:43,:rocket: 更新条数: +5, ![](assets/dot.png) 表示有更新 15 | 16 | ## 来源分类 17 | 18 | - [武汉肺炎防疫全纪录财新网](#武汉肺炎防疫全纪录财新网) 19 | - [全国新型肺炎疫情实时动态丁香园](#全国新型肺炎疫情实时动态丁香园) 20 | - [Vue社区](#vue社区) 21 | - [Vue中文社区](#vue中文社区) 22 | - [VUE全家桶](#vue全家桶) 23 | - [React中文社区](#react中文社区) 24 | - [前端早读课](#前端早读课) 25 | - [前端大全](#前端大全) 26 | - [前端开发](#前端开发) 27 | - [前端圈](#前端圈) 28 | - [前端开发博客](#前端开发博客) 29 | - [前端大学](#前端大学) 30 | - [前端外刊评论](#前端外刊评论) 31 | - [前端之巅](#前端之巅) 32 | - [前端迷](#前端迷) 33 | - [全栈前端精选](#全栈前端精选) 34 | - [政采云前端团队](#政采云前端团队) 35 | - [前端宇宙](#前端宇宙) 36 | - [前端瓶子君](#前端瓶子君) 37 | - [程序员成长指北](#程序员成长指北) 38 | - [Nodejs技术栈](#nodejs技术栈) 39 | - [张鑫旭-鑫空间-鑫生活](#张鑫旭-鑫空间-鑫生活)![](assets/dot.png) 40 | - [阮一峰的网络日志](#阮一峰的网络日志) 41 | - [京东设计中心](#京东设计中心) 42 | - [凹凸实验室](#凹凸实验室) 43 | - [奇舞周刊](#奇舞周刊) 44 | - [前端日刊](#前端日刊) 45 | - [前端e进阶](#前端e进阶) 46 | - [互联网架构师](#互联网架构师) 47 | - [InfoQ](#infoq) 48 | - [JavaScript](#javascript) 49 | - [掘金前端](#掘金前端) 50 | - [前端艺术家&&飞冰早报](#前端艺术家&&飞冰早报) 51 | - [印记中文周刊](#印记中文周刊) 52 | - [编程之上](#编程之上) 53 | - [知乎日报](#知乎日报) 54 | - [V2EX](#v2ex) 55 | - [技术头条](#技术头条) 56 | - [开发者头条](#开发者头条) 57 | - [安全热点](#安全热点) 58 | - [物联网智库](#物联网智库) 59 | 60 | ## 文章链接 61 | 62 |
63 | 64 | 武汉肺炎防疫全纪录财新网 65 | 66 | 67 | 68 | - [......【查看更多】......](./details/武汉肺炎防疫全纪录(财新网).md) 69 | 70 |
⬆返回顶部
71 |
72 | 73 |
74 | 75 | 全国新型肺炎疫情实时动态丁香园 76 | 77 | 78 | 79 | - [......【查看更多】......](./details/全国新型肺炎疫情实时动态(丁香园).md) 80 | 81 |
⬆返回顶部
82 |
83 | 84 |
85 | 86 | Vue社区 87 | 88 | 89 | 90 | - [......【查看更多】......](./details/Vue社区.md) 91 | 92 |
⬆返回顶部
93 |
94 | 95 |
96 | 97 | Vue中文社区 98 | 99 | 100 | 101 | - [......【查看更多】......](./details/Vue中文社区.md) 102 | 103 |
⬆返回顶部
104 |
105 | 106 |
107 | 108 | VUE全家桶 109 | 110 | 111 | 112 | - [......【查看更多】......](./details/VUE全家桶.md) 113 | 114 |
⬆返回顶部
115 |
116 | 117 |
118 | 119 | React中文社区 120 | 121 | 122 | 123 | - [......【查看更多】......](./details/React中文社区.md) 124 | 125 |
⬆返回顶部
126 |
127 | 128 |
129 | 130 | 前端早读课 131 | 132 | 133 | 134 | - [......【查看更多】......](./details/前端早读课.md) 135 | 136 |
⬆返回顶部
137 |
138 | 139 |
140 | 141 | 前端大全 142 | 143 | 144 | 145 | - [......【查看更多】......](./details/前端大全.md) 146 | 147 |
⬆返回顶部
148 |
149 | 150 |
151 | 152 | 前端开发 153 | 154 | 155 | 156 | - [......【查看更多】......](./details/前端开发.md) 157 | 158 |
⬆返回顶部
159 |
160 | 161 |
162 | 163 | 前端圈 164 | 165 | 166 | 167 | - [......【查看更多】......](./details/前端圈.md) 168 | 169 |
⬆返回顶部
170 |
171 | 172 |
173 | 174 | 前端开发博客 175 | 176 | 177 | 178 | - [......【查看更多】......](./details/前端开发博客.md) 179 | 180 |
⬆返回顶部
181 |
182 | 183 |
184 | 185 | 前端大学 186 | 187 | 188 | 189 | - [......【查看更多】......](./details/前端大学.md) 190 | 191 |
⬆返回顶部
192 |
193 | 194 |
195 | 196 | 前端外刊评论 197 | 198 | 199 | 200 | - [......【查看更多】......](./details/前端外刊评论.md) 201 | 202 |
⬆返回顶部
203 |
204 | 205 |
206 | 207 | 前端之巅 208 | 209 | 210 | 211 | - [......【查看更多】......](./details/前端之巅.md) 212 | 213 |
⬆返回顶部
214 |
215 | 216 |
217 | 218 | 前端迷 219 | 220 | 221 | 222 | - [......【查看更多】......](./details/前端迷.md) 223 | 224 |
⬆返回顶部
225 |
226 | 227 |
228 | 229 | 全栈前端精选 230 | 231 | 232 | 233 | - [......【查看更多】......](./details/全栈前端精选.md) 234 | 235 |
⬆返回顶部
236 |
237 | 238 |
239 | 240 | 政采云前端团队 241 | 242 | 243 | 244 | - [......【查看更多】......](./details/政采云前端团队.md) 245 | 246 |
⬆返回顶部
247 |
248 | 249 |
250 | 251 | 前端宇宙 252 | 253 | 254 | 255 | - [......【查看更多】......](./details/前端宇宙.md) 256 | 257 |
⬆返回顶部
258 |
259 | 260 |
261 | 262 | 前端瓶子君 263 | 264 | 265 | 266 | - [......【查看更多】......](./details/前端瓶子君.md) 267 | 268 |
⬆返回顶部
269 |
270 | 271 |
272 | 273 | 程序员成长指北 274 | 275 | 276 | 277 | - [......【查看更多】......](./details/程序员成长指北.md) 278 | 279 |
⬆返回顶部
280 |
281 | 282 |
283 | 284 | Nodejs技术栈 285 | 286 | 287 | 288 | - [......【查看更多】......](./details/Nodejs技术栈.md) 289 | 290 |
⬆返回顶部
291 |
292 | 293 |
294 | 295 | 张鑫旭-鑫空间-鑫生活 296 | 297 | 298 | 299 | - [2025-12-12-CSS-progress函数简介](https://www.zhangxinxu.com/wordpress/2025/12/css-progress-function/) ![](assets/new.png) 300 | - [2025-12-04-单IMG标签的图片内阴影效果实现](https://www.zhangxinxu.com/wordpress/2025/12/img-inset-shadow/) ![](assets/new.png) 301 | - [2025-11-28-醒醒,该使用CookieStore新建和管理cookie了](https://www.zhangxinxu.com/wordpress/2025/11/js-cookiestore-cookie/) ![](assets/new.png) 302 | - [2025-11-24-巧用CSS-::details-content伪元素实现任意展开动画](https://www.zhangxinxu.com/wordpress/2025/11/css-details-target-content-open/) ![](assets/new.png) 303 | - [2025-11-17-介绍下与CSS自定义组件相关的:state函数](https://www.zhangxinxu.com/wordpress/2025/11/css-state-function/) ![](assets/new.png) 304 | - [......【查看更多】......](./details/张鑫旭-鑫空间-鑫生活.md) 305 | 306 |
⬆返回顶部
307 |
308 | 309 |
310 | 311 | 阮一峰的网络日志 312 | 313 | 314 | 315 | - [......【查看更多】......](./details/阮一峰的网络日志.md) 316 | 317 |
⬆返回顶部
318 |
319 | 320 |
321 | 322 | 京东设计中心 323 | 324 | 325 | 326 | - [......【查看更多】......](./details/京东设计中心.md) 327 | 328 |
⬆返回顶部
329 |
330 | 331 |
332 | 333 | 凹凸实验室 334 | 335 | 336 | 337 | - [......【查看更多】......](./details/凹凸实验室.md) 338 | 339 |
⬆返回顶部
340 |
341 | 342 |
343 | 344 | 奇舞周刊 345 | 346 | 347 | 348 | - [......【查看更多】......](./details/奇舞周刊.md) 349 | 350 |
⬆返回顶部
351 |
352 | 353 |
354 | 355 | 前端日刊 356 | 357 | 358 | 359 | - [......【查看更多】......](./details/前端日刊.md) 360 | 361 |
⬆返回顶部
362 |
363 | 364 |
365 | 366 | 前端e进阶 367 | 368 | 369 | 370 | - [......【查看更多】......](./details/前端e进阶.md) 371 | 372 |
⬆返回顶部
373 |
374 | 375 |
376 | 377 | 互联网架构师 378 | 379 | 380 | 381 | - [......【查看更多】......](./details/互联网架构师.md) 382 | 383 |
⬆返回顶部
384 |
385 | 386 |
387 | 388 | InfoQ 389 | 390 | 391 | 392 | - [......【查看更多】......](./details/InfoQ.md) 393 | 394 |
⬆返回顶部
395 |
396 | 397 |
398 | 399 | JavaScript 400 | 401 | 402 | 403 | - [......【查看更多】......](./details/JavaScript.md) 404 | 405 |
⬆返回顶部
406 |
407 | 408 |
409 | 410 | 掘金前端 411 | 412 | 413 | 414 | - [......【查看更多】......](./details/掘金前端.md) 415 | 416 |
⬆返回顶部
417 |
418 | 419 |
420 | 421 | 前端艺术家&&飞冰早报 422 | 423 | 424 | 425 | - [......【查看更多】......](./details/前端艺术家&&飞冰早报.md) 426 | 427 |
⬆返回顶部
428 |
429 | 430 |
431 | 432 | 印记中文周刊 433 | 434 | 435 | 436 | - [......【查看更多】......](./details/印记中文周刊.md) 437 | 438 |
⬆返回顶部
439 |
440 | 441 |
442 | 443 | 编程之上 444 | 445 | 446 | 447 | - [......【查看更多】......](./details/编程之上.md) 448 | 449 |
⬆返回顶部
450 |
451 | 452 |
453 | 454 | 知乎日报 455 | 456 | 457 | 458 | - [......【查看更多】......](./details/知乎日报.md) 459 | 460 |
⬆返回顶部
461 |
462 | 463 |
464 | 465 | V2EX 466 | 467 | 468 | 469 | - [......【查看更多】......](./details/V2EX.md) 470 | 471 |
⬆返回顶部
472 |
473 | 474 |
475 | 476 | 技术头条 477 | 478 | 479 | 480 | - [......【查看更多】......](./details/技术头条.md) 481 | 482 |
⬆返回顶部
483 |
484 | 485 |
486 | 487 | 开发者头条 488 | 489 | 490 | 491 | - [......【查看更多】......](./details/开发者头条.md) 492 | 493 |
⬆返回顶部
494 |
495 | 496 |
497 | 498 | 安全热点 499 | 500 | 501 | 502 | - [......【查看更多】......](./details/安全热点.md) 503 | 504 |
⬆返回顶部
505 |
506 | 507 |
508 | 509 | 物联网智库 510 | 511 | 512 | 513 | - [......【查看更多】......](./details/物联网智库.md) 514 | 515 |
⬆返回顶部
516 |
517 | 518 | 519 | ## 其它 520 | 感谢 [RSSHub](https://github.com/DIYgod/RSSHub) 提供的微信公众号 RSS 链接 Fork自 [ChanceYu](https://github.com/ChanceYu/front-end-rss) 521 | -------------------------------------------------------------------------------- /site/src/components/loading.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | 56 | -------------------------------------------------------------------------------- /site/src/components/Index.vue: -------------------------------------------------------------------------------- 1 | 99 | 100 | 347 | 348 | 668 | --------------------------------------------------------------------------------