starkwang

starkwang 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织 shudong.wang/about 编辑
编辑

从事web开发多年,前端、后端、服务架构都有涉猎,经历过大公司、创业公司,擅长前端及公司技术选型。

个人动态

starkwang 发布了文章 · 今天 13:11

「代码水平」当我们遇到Switch语句时,可以用Map/Object literal来提高代码的level

来一栗switch语句

function test(feup) {
  switch (feup) {
    case '妲己':
      return ['法师', '控'];
    case '鲁班':
      return ['射手', '腿短'];
    case '安其拉':
      return ['法师', '喜欢读魔法书'];
    case '前端指北':
      return ['成长', '进阶','面试题'];
    default:
      return ['starkwang'];
  }
}

//test results
test(null); // ['starkwang']
test('安其拉'); // ['法师', '喜欢读书']

上面的代码看起来没什么问题,但是我发现它相当冗长。同样的结果也可以通过使用更清晰的 object literal 来实现:

const hero = {
  daji: ['法师', '控'],
  luban: ['射手', '腿短'],
  anqila: ['法师', '喜欢读魔法书'],
  qianduanzhibei:['成长', '进阶','面试题']
};

function test(feup) {
  return hero[feup] || [];
}

或者,你也可以使用 Map 来达到同样的结果:

  const hero = new Map()
    .set('daji', ['法师', '控'])
    .set('luban', ['射手', '腿短'])
    .set('anqila',  ['法师', '喜欢读魔法书'])
    .set('qianduanzhibei', ['成长', '进阶','面试题'])

function test(color) {
  return hero.get(color) || [];
}

Map详细知识了解可以去这了解:https://developer.mozilla.org...

Map 是自 ES2015以来可用的对象类型,允许您存储键值对。

我们应该禁止 switch 语句的使用吗?不要把自己局限于此。就我个人而言,只要有可能,我就会使用 object literal,但我不会设置硬性规则来阻止它,而是使用任何对您的场景有意义的方法。

对于上面的例子,我们实际上可以通过重构代码来使用 Array.filter 实现相同的结果。

const hero = [
    { name: 'daji', ability: '法师' },
    { name: 'luban', ability: '射手' },
    { name: 'anqila', ability: '喜欢读魔法书' },
    { name: 'qianduanzhibei', ability: '成长' }
];

function test(ability) {
  return hero.filter(f => f.ability == ability);
}

总有不止一种方法可以达到同样的结果,当写代码的时候,我们要思考怎么用更优雅的方式来表达,这样当别人review代码的时候,会体现出自己的水平。

查看原文

赞 2 收藏 1 评论 1

starkwang 提出了问题 · 2020-11-09

uni-app怎么用cli 方式打包h5?部署需要

uni-app怎么用cli 方式打包h5?部署需要

关注 2 回答 1

starkwang 发布了文章 · 2020-10-27

解决mac安装zsh 被墙 方案,或者解决安装zshell比较慢的方案

打开这个网址:https://ohmyz.sh/,安装官网的方式比较慢,使用下面的 国内cdn方式。

解决mac安装zsh 被墙 方案,或者比较慢的方案

cdn地址:https://www.devland.cn/snippe...

如何,安装飞速吧!

查看原文

赞 0 收藏 0 评论 2

starkwang 赞了文章 · 2020-07-09

这份 window.location 备忘单,让你更有条理解决地址路径问题!

作者:Samantha Ming
译者:前端小智
来源:medium
点赞再看,微信搜索【大迁世界】关注这个没有大厂背景,但有着一股向上积极心态人。本文 GitHubhttps://github.com/qq44924588... 上已经收录,文章的已分类,也整理了很多我的文档,和教程资料。**

大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】

如果你想获取站点的URL信息,那么window.location对象什么很适合你! 使用其属性获取有关当前页面地址的信息,或使用其方法进行某些页面重定向或刷新💫

https://segmentfault.com/sear...
window.location.origin    → '"https://segmentfault.com'
               .protocol  → 'https:'
               .host      → 'segmentfault.com'
               .hostname  → 'segmentfault.com'
               .port      → ''
               .pathname  → '/search'
               .search    → '?q=前端小智'
               .hash      → '#2'
               .href      → 'https://segmentfault.com/search?q=前端小智#2'
window.location.assign('url')
               .replace('url')
               .reload()
               .toString()

window.location 属性

window.location返回值
.origin站点主地址(协议 + 主机名 + 端口)
.protocol协议架构 (http: 或者 htts:)
.host域名 + 端口
.port端口
.pathname最前页的 '/' 后面跟的路径
.search? 后跟的查询字符串
.hash# 号开始的部分
.href完整网址

host 和 hostname 的区别

在上面的示例中,你可能注意到hosthostname返回相同的值。 那么为什么要这些属性。 好吧,这与端口号有关,让我们来看看。

没有端口的 URL

https://segmentfault.com/search
window.location.host; // 'segmentfault.com'
window.location.hostname; // 'segmentfault.com'

window.location.port; // ''

带端口的 URL

https://segmentfault.com/search"8080
window.location.host; // 'segmentfault.com:8080'
window.location.hostname; // 'segmentfault.com'

window.location.port; // '8080'

因此,host将包括端口号,而hostname将仅返回主机名。

如何更改 URL 属性

我们不仅可以调用location` 属性来检索URL信息,还可以使用它来设置新属性并更改URL。

// 开始 'https://segmentfault.com/'

window.location.pathname = '/tidbits'; // 设置 pathname

// 结果 'https://segmentfault.com/tidbits'

下面是你可以更改的属性的完整列表

// 事例
window.location.protocol = 'https'
               .host     = 'localhost:8080'
               .hostname = 'localhost'
               .port     = '8080'
               .pathname = 'path'
               .search   = 'query string' // (这里不用写 `?`)
               .hash     = 'hash' // (这里不用写 `#`)
               .href     = 'url'

唯一不能设置的属性是window.location.origin,此属性是只读的。

Location 对象

window.location返回一个Location对象。 它为我们提供有关页面当前地址的信息。 但是我们还可以通过几种方式访问​​Location对象。

window.location          → Location
window.document.location → Location
document.location        → Location
location                 → Location

我们这样做的原因是这些是我们浏览器中的全局变量。

clipboard.png

window.location vs location

上面四个属性都指向同一个Location对象。 我个人更喜欢window.location并且实际上会避免使用location。 主要是因为location看起来像一个普通变量,并且我们有时可能会不小心将其命名为变量,这将覆盖全局变量。 举个例子:

// https://www.samanthaming.com

location.protocol; // 'https'

function localFile() {
  const location = '/sam';

  return location.protocol;
  // ❌ undefined
  //    b/c local "location" has override the global variable
}

我想大多数开发人员都知道window是一个全局变量。这样就不太可能引起混淆。老实说,直到我写了这篇文章,我才知道location 是一个全局变量。建议大家多使用 window.location 来代替其它写法。

window.location 方法

方法作用
.assign()加载一个新的文档
.replace()用新的文档替换当前文档
.reload()重新加载当前页面
.reload()返回的URL

大家都说简历没项目写,我就帮大家找了一个项目,还附赠【搭建教程】

window.location.toString

根据 MDN :

此方法返回 URL 的 USVString,它是 Location.href 的只读版本。

换句话说,我们可以这样得到 href 的值:

// https://www.samanthaming.com

window.location.href; // https://www.samanthaming.com
window.location.toString(); // https://www.samanthaming.com

assign vs replace

这两种方法都是重定向或导航到另一个URL。 区别在于assign 是将当前页面保存在历史记录中,因此用户可以使用“后退”按钮导航到该页面。 而使用replace方法时,不会保存它。 让我们来看一个例子。

Assign

1. 打开一个新的空白页
2. 输入 www.samanthaming.com (当前页)

3. 使用 `window.location.assign('https://www.w3schools.com')` 载入新页面
4. 按 "返回上一页"
5. 返回到了 👉 www.samanthaming.com

Replace

1. 打开一个新的空白页
2. 输入 www.samanthaming.com (当前页)

3. 使用 `window.location.assign('https://www.w3schools.com')` 载入新页面
4. 按 "返回上一页"
5. 返回到一个空白页

如何让页面重定向

如何重定向到另一个页面,有3种方法。

window.location.href = 'https://www.samanthaming.com';

window.location.assign('https://www.samanthaming.com');

window.location.replace('https://www.samanthaming.com');

replace vs assign vs href

这三个都可以重定向,区别在于浏览器的历史记录。 hrefassign 会把当前页面保存在历史记录中,而replace则不会。 因此,如果你想创建一种导航无法回到原始页面的体验,请使用replace👍

现在的问题是hrefassign。 我更喜欢assign,因为它是一种方法,因此感觉好像我正在执行一些操作。 还有一个额外的好处是它更易于测试。 我已经编写了许多Jest测试,因此通过使用一种方法,它使其更易于模拟。

window.location.assign = jest.fn();

myUrlUpdateFunction();

expect(window.location.assign).toBeCalledWith('http://my.url');

最终希望备忘单,希望能对你有所帮助,在需要的时候,能快速给你带来答案。

人才们的 【三连】 就是小智不断分享的最大动力,如果本篇博客有任何错误和建议,欢迎人才们留言,最后,谢谢大家的观看。


原文:https://morioh.com/p/b444d291...

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug


交流

文章每周持续更新,可以微信搜索【大迁世界 】第一时间阅读,回复【福利】有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 已经收录,欢迎Star。

查看原文

赞 21 收藏 14 评论 3

starkwang 赞了文章 · 2020-07-05

nodejs最酷炫的模块——child_process - 子进程

什么是child_process

child_process模块是nodejs的一个子进程模块,可以用来创建一个子进程,并执行一些任务。执行一些什么任务呢?shell命令知道吧,有了child_process模块,就可以直接在js里面调用shell命令去完成一些非常酷炫的操作了!!
举个栗子,GitHub码云等git代码托管网站,都会有个webHook功能,当push了新的代码后,服务器可以开辟一个接口去接受这个webHook的请求,并进行git pullnpm run build等命令,从而达到自动化部署的目的!

码云的webHook功能

来个小demo

目录结构

前端直接简单用的vue-cli脚手架新建了个项目,后端是用的express

clipboard.png

前端代码就不晒了,都是脚手架生成的,后端代码主要就是一个server.js和一个执行shell的方法。

backend/server.js

backend/server.js
注意先要安装几个依赖:expressbody-parser
express是主角,不用多说,body-parser是用来解析post请求的参数的。
const express = require('express');
const app = express();
const port = process.env.PORT || 8080;
const www = process.env.WWW || './fontend/dist';
var bodyParser = require('body-parser')//格式化body数据

app.use(bodyParser.urlencoded({extended: false}));//body parser插件配置
app.use(bodyParser.json());//body parser插件配置
const gitPush = require('./service/git-push')//引入写的服务

app.post('/api/git_hook',async (req, res) => {//监听这个接口
    if(req.body.password !== '666'){// 这里校验post请求的密码
        res.send('密码错误')
        return 
    }
    const code = await gitPush()
    res.send('hello world' + code)
})
app.use(express.static(www));
console.log(`serving ${www}`);


app.get('*', (req, res) => {
    res.sendFile(`index.html`, { root: www });
});
app.listen(port, () => console.log(`listening on http://localhost:${port}`));

backend/service/git-push.js

const childProcess = require('child_process');
const path = require('path')

module.exports = async function (params) {
    await createGitPullPromise()
    return await createPackPromise()
}
function createPackPromise(){
    return new Promise((res, rej) => {
        const compile = childProcess.spawn('npm', ['run', 'build'], {cwd: path.resolve(__dirname, '../../fontend')})
        compile.on('close', code => {
            // console.log(code)
            res(code)
        })
    })
}
function createGitPullPromise(){
    return new Promise((res, rej) => {
        const compile = childProcess.spawn('git', ['pull'], {cwd: path.resolve(__dirname, '../../fontend')})
        compile.on('close', code => {
            // console.log(code)
            res(code)
        })
    })
}

小结

child_process模块,主要是用的child_process.spawn(),需要注意的是,这个函数只会创建异步进程,具体的API可以参考官网。异步进程的话,不会阻塞主进程的执行,所以我backend/service/git-push.js里面用async function来进行异步回调的控制。child_process模块还提供了创建同步子进程的方法 child_process.spawnSync,了解nodejs比较多的同学可能会发现,跟异步的方法相比,就是最后面加了个Sync,嗯,也可以这么理解吧。
希望大家多了解下这个模块,多动手操作下,能用到哪里 留下了非常大的想象空间!

查看原文

赞 12 收藏 5 评论 2

starkwang 赞了文章 · 2020-06-28

React 开发性能监测插件-Why Did You Render 初探

Why Did You Render 简介

当我在开发 React 项目时,经常会想,要是有一个工具能实时告知我组件是否有性能问题就好了,这样就能在开发的时候就尽量避免组件过大时的性能问题,以及降低潜在的页面崩溃概率。
然后我就在网上找到了这个工具:@welldone-software/why-did-you-render,它能在我开发 react 组件的时候及时提醒我当前写的组件是否有不必要的重复渲染问题,在开发的时候就避免掉部分性能问题。

why did you render 应当在开发环境里使用。
为避免麻烦,以下why did you render 都简称 why render

官网地址:https://github.com/welldone-s...
文档说明:https://medium.com/welldone-s...

安装使用

  • 安装 npm 包:

    npm install @welldone-software/why-did-you-render --save
  • 开发环境里启用(全局启用,部分组件启用请看官方文档):

    import React from 'react';
    
    if (process.env.WHY_RENDER) {
      const whyDidYouRender = require('@welldone-software/why-did-you-render');
      whyDidYouRender(React, {
        trackAllPureComponents: true,
      });
    }

    官网里是判断 process.env.NODE_ENV === 'development',不过我觉得应该和原有的开发,环境区分开发,新建一个 script,不然容易给同一个项目里其他开发同学造成困扰:

  • package.json新建一个 scripts

    "scripts": {
        "wr": "npm run dev --WHY_RENDER"
    }

    然后我们就可以使用 npm run wr 开发了。

why render 使用

why render 提示信息

当我们启用了 why render 插件开发的时候,如果组件里有不必要的re-render问题时,控制台里会有相关的信息提示(不管是页面加载的时候还是交互的时候都可能会有提示):

image.png

上图里有两种可改进的地方,一个是 props 的 onchange 事件这块导致 RedioGroup 和 Checkbox re-render了;另一个是 state 的值并未改变也导致 re-render。
根据这些提示我们可以针对性优化,一个一个的解决,直至所有的提示都清除。

下面我对各类提示及相应的解决办法归类了一下:

表达式 props

父组件给子组件传的是表达式、函数、组件时触发 re-render提示问题。

<ClassDemo  
regEx={/something/}
fn={function something(){}} 
date={new Date('6/29/2011 4:52:48 PM UTC')}
reactElement={<div>hi!</div>}
/>

上面是官方文档(?)里的一个例子,当通过表达式等方式而不是变量的方式把 props 传递给子组件的时候,控制台里会有 re-render 提示:

解决办法,只需要把表达式等赋给变量再使用变量传递 props 就行:

const reg = /something/;
const something = function f(){};
const date = new Date('6/29/2011 4:52:48 PM UTC');
const elem = () => {
  return {
    <div>hi!</div>
  }
}
<ClassDemo  
regEx={reg}
fn={something} 
date={date}
reactElement={elem}
/>

不过我从来都是通过创建变量来传递props的,直接把表达式传过去也太low了。

被重赋给相同值的对象 props

这个最常见的例子是在接口请求里,比如查询数据,当参数未改变,再次查询返回的数据未变时,可能会导致数据的渲染组件的re-render,这在ant-design 的 table 组件里很常见。
解决办法:
1、更改state前先判断,有变化才更改state;
2、使用React.memo 或者 shouldComponentUpdate;

变化的事件处理器

hooks组件里,如果事件处理器 F props 里依赖 state,在state 变化时F props 会传入新的事件方法。
在下图的真实场景里,所有的ant-design表单元素value是用的一个 state 对象,事件方法也是同一个,如果不处理,随便一个表单元素的值更改都会导致所有的表单元素 re-render,然后就有了很多个 re-render 提示。
image.png

要让事件处理器不变,有两个解决方式,不过也是大同小异:

// 通用事件处理函数
export function useEventCallback(fn, dependencies) {
  const ref = useRef(() => {
    throw new Error('Cannot call an event handler while rendering.');
  });

  useEffect(() => {
    ref.current = fn;
  }, [fn, ...dependencies]);

  return useCallback((...args) => {
    const fn = ref.current;
    return fn(...args);
  }, [ref]);
}

// 使用
const [state, setState] = useState({
   name: '',
   type: '',
});
// 事件处理器 onChange
const onChange = useEventCallback((value) => {
    // setState or do otherthing
}, [state]);
// 一个简单的ref 自定义 hooks
export function useRefProps(props) {
  const ref = useRef(props);
  // 每次渲染更新props
  useEffect(() => {
    ref.current = props;
  });

  return ref;
}

// 使用
const [state, setState] = useState({
   name: '',
   type: '',
});
const stateRef = useRefProps({
    state,
    [...others]
  });
// 事件处理器 onChange
const onChange = useCallback((value) => {
   const { state, ...others } = stateRef.current;
    // setState or do otherthing
}, []);

两种方式的原理类似,都是把变化数据/函数使用Ref作为中转,使用 useCallback 缓存结果。不过明显第一种易用性更高。
使用这两个方法得到的处理事件处理器即便作为 props 传给子组件也不会变化的。

ant-design 相关

有些 ant-design 的表单组件会触发re-render提示。比如表单里支持 Option 子组件的组件,例如 Select组件,使用 Option 组件就会有 re-render 提示。

解决办法:Option 组件使用 options props 替代,这块ant-design 应该是有优化的。
其他的组件有re-render提示都可先在 ant-design上查找是否有最新的使用方式。

// 会导致 re-render 的使用方式
<Select onChange={handleChange}>
  <Option value="jack">Jack</Option>
  <Option value="lucy">Lucy</Option>
  <Option value="disabled" disabled></Option>
</Select>

// 不会导致 re-render 的使用方式
const options = [
  {
    label: 'Jack',
    value: 'jack',
  },
  {
    label: 'Lucy',
    value: 'lucy',
  }
]
<Select onChange={handleChange} options={options}>
</Select>

引入的第三方库的问题

如果我们的项目没有引入第三方库,那我们是可以优化掉所有的 re-render 提示的。但实际开发中这种情况基本上不会出现的,所以这就导致了一个问题:当第三方组件导致了 re-render 提示时,我们很可能因为无法更改第三方库而导致 re-render 提供无法消除掉。
所以不必执着于消除所有的 re-render 提示,控制 re-render 数量在一个可接受的范围内,比如加载完或交互完后提示在三个内,也不失为一个合理的优化结果

结语

why render 最适合的地方是应用于大型项目,在小型项目、简单页面中的价值并不是很大,毕竟一个页面如果本身就一点简单的内容展示一般也不需要多少内存。而大型项目就不一样的,一个页面可能有几十个组件,这时候每个组件的性能问题都应该重视起来,等到页面崩溃的时候再去找问题那就真是费时又费力,还不一定短时间内能解决。

查看原文

赞 3 收藏 0 评论 0

starkwang 赞了文章 · 2020-06-28

其实我们可以少写点 if else 和 switch

前言

作为搬砖在第一线的底层工人,业务场景从来是没有做不到只有想不到的复杂。
不过他强任他强,if-else全搞定,搬就完了。但是随着业务迭代或者项目交接,自己在看自己或者别人的if代码的时候,心情就不再表述了,各自深有体会。所以我们一起看看if还能怎么写

最基本if-else

假设有这么个场景,不同情况下打印不同值。因为涉及到的条件太多,就不提三目运算之类优化了。

if (a == 1) {
    console.log('a1')
} else if (a == 2) {
    console.log('b2')
} else if (a == 3) {
    console.log('c3')
} else if (a == 4) {
    console.log('d4')
}

现在还算能看,因为逻辑简单,如果逻辑复杂,迭代多个版本之后,你还敢动吗。
每动一下就战战兢兢,谁知道哪里会遗漏。那么换种方式呢

switch-case

这样稍微清晰那么一点,差别好像没什么差别:

switch(a) {

    case 1:console.log('a1');

    break;

    case 40:console.log('a40');

    break;

}

分离配置信息与执行动作

object映射

定义一个object作为配置对象来存放不同状态,通过链表查找

const statusMap = {

    1:()=>{

        console.log('a1')

    },

    2:()=>{

        console.log('b2')

    }  

}

// 执行

let a = 1 

statusMap[a || 1]()

这样比较清晰,将条件配置与具体执行分离。如果要增加其他状态,只修改配置对象即可。

数组映射

当然在某些状态下可以使用数组,来做这个配置对象。

// 它就是个function,内容很复杂


const statusArr = [function(){

    console.log(1)

},

function () {

    console.log(2)

},]

let a = 1

statusArr[a || 1]()

数组的要求更高一点,如果是其他key,例如字符串,那么数组就不能满足需求了

升级版:不同key相同value

这样看起来好一点了,那么需求又有变动了,
前面是每种处理方式都不同,下面有几种情况下处理函数相同的, 例如1-39的时候,调用a,40之后调用b,如果我们继续来用映射的方式来处理。

function f1 (){

    console.log(1)

}

function f2 (){

    console.log(2)

}

const statusMap = {
    1: f1,
    2: f1,
    3: f1,
    4: f1,   
    40: f2
}

let a = 2

statusMap[a]()

这样当然也可以,不过重复写那么多f1,代码看起来不够简洁。

开始重构之前我们先捋一下思路,无非是想把多个key合并起来,对应一个value。
也就是说我们的键值不是字符串而是个数组,object显然只支持字符串, 那么可以将这么多key合并成一个:'1,2,3,4,..,9'。

但是查找的时候有点问题了,我们的参数肯定不能完全匹配。
接着走下去,是不是做个遍历加个判断,包含在子集内的都算匹配,那么代码看起来就是下面这个样子。

const statusMap = {
    '1,2,3,4,5': f1,
    40: f2
}
const keys = Object.keys(statusMap),

len = keys.length
const getVal = (param='') => {
    for (let i = 0; i < len; i++) {
        const key = keys[i],
        val = statusMap[key]
        if (key.includes(param)) {
            return val
        }
    }
}
let a = 2,
handle = getVal(a)
handle() 

但是这样来看,增加了个遍历的过程,而且是拼接字符串,万一哪天传了个逗号进来,会得到了预料之外的结果。

map

es6有个新的数据结构Map,支持任意数据结构作为键值。如果用Map可能更清晰一点。

const map1 = new Map()

const statusArr = [1,2,3,4,5]

map1.set(statusArr,f1)
  
let handle = function(){}

const getVal = (param = '') => {

    for (let value of map1.entries()) {

        console.log(JSON.stringify(value))

        if (value[0].includes(param)){

            console.log(value)
            handle = value[1]

        }

    }

}

const a = 2

getVal(a)

handle()

个人而言虽然这样减少了重复代码,但是又增加了一步匹配值的操作,优劣就见仁见智吧。

双数组

肯定有部分人就是不想做遍历的操作,既然一个数组不能满足,那么两个数组呢。

const keyArr = ['1,2,3,4,5','40']

const valArr = [f1,f2]

const getVal = (param = '') => {
    let index = keyArr.findIndex((it) => {
            return it.includes(param)
        })

    return valArr[index]

}

let a = 2,

handle = getVal(a)
handle()

利用数组提供的下标,将key和value对应起来,进而获取想要的值。
这里一直没有达到我最初的目的,即键里面重复的数组,可以不通过多余操作匹配到,上面不管怎么样都进行了处理,这不是懒人的想要的。

总结

这是在写业务需求的时候做的一点总结,数组和对象的映射可能大家都在用。当遇到了不同key相同value的情况时,从懒出发不像重复罗列,就尝试了下。当然了,因为个人水平问题,肯定有更好的处理方式,欢迎一起讨论,抛砖引玉共同进步。此外现有成熟的库里loadsh也是可以到达目的,不过自己思考过之后再去看大神的作品理解会更深入一点。

作者:潇湘待雨
https://juejin.im/post/5c3607...


THE END

感谢阅读

查看原文

赞 3 收藏 0 评论 0

starkwang 发布了文章 · 2020-06-27

mac 本地配置https 证书,并且通过 Chrome 安全监测

  1. 获取脚本
git clone https://github.com/wsdo/local-https-cert.git
cd local-https-cert
  1. 生成本地的RootCA:
sh createRootCA.sh

20200627134114
20200627134446

1.输入一个秘密(随便输入,但是要记住)
2.输入刚才的秘密(和上面秘密要一致)
  1. 创建根证书
sh createCertificate.sh

20200627134535

  1. 让打开RootCA改成始终信任

点击

20200627133245

点击login 输入上面生成证书的秘密

20200627133233
20200627134735
20200627134805

nginx

# HTTPS server
server {
    listen 443 ssl;
    server_name shudong.wang;

    ssl_certificate ssl/www.server.crt;
    ssl_certificate_key ssl/www.server.key;

    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;

    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    location / {
        # try_files $uri $uri/ /index.html;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://localhost:8000/;
    }
}
查看原文

赞 1 收藏 1 评论 0

starkwang 赞了文章 · 2020-06-26

21 个提升 React 开发效率的工具

作者:jsmanifest
译者:前端小智
来源:medium
点赞再看,养成习惯

本文 GitHubhttps://github.com/qq44924588... 上已经收录,更多往期高赞文章的分类,也整理了很多我的文档,和教程资料。欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。


为了保证的可读性,本文采用意译而非直译。

下列工具中的重要性与排序无关。

1.Webpack Bundle Analyzer

有没有想过你的应用程序的哪些包或哪部分代码所占总大小的多少? Webpack Bundle Analyzer可以帮助咱们分析。

Webpack Bundle Analyzer创建一个实时服务器,并提供依赖包交互式树形图可视化。 通过这个工具包,可以看到所渲染文件的位置,gzip大小,解析大小以及所父子级之间详情。

这个工具的好处是,可以根据你所看到来优化你的React应用。

收下是它生成的一个分析图:

clipboard.png

可以清楚地看到pdf包大小占用应用程序是最多的,同时也是占用分析图片最大比例,这对于咱们来说是所看即所得效果。

然而,生成分析图空间有限,你还可以传递一些有用的选项来更详细地查看它,比如generateStatsFile: true,还可以选择生成一个静态HTML文件,可以将其保存在开发环境之外的某个地方,以供以后使用。

2. React-Proto

React-Proto 是一个面向开发人员和设计人员的原型工具。这是一个桌面软件,所以在使用之前你必须下载并安装这个软件。

以下是使用方式一个简单演示:

clipboard.png

该应用程序允许你声明props及其types,在树中查看组件,导入背景图像,将它们定义为有状态或无状态,定义其父组件将是什么,放大/缩小,以及将原型导出到新的或现有项目。

该应用程序似乎更适合Mac用户,但它仍适用于Windows用户。

完成用户界面后,可以选择导出到现有项目或新项目。 如果你选择导出到现有项目并选择根目录,它会将它们导出到./src/components,如下所示:

clipboard.png

随着React hook的发布,这个应用程序需要更新做更多的工作。当然,开源是这个应用程序的好处,因为它使它有可能成为未来流行的开源存储库列表。

3. Why Did You Render

Why Did You Render 猴子补丁React通知你有关可避免的重新渲染的信息。

猴子补丁: 这个叫法起源于Zope框架,大家在修正Zope的Bug的时候经常在程序后面追加更新部分,这些被称作是“杂牌军补丁(guerilla patch)”,后来guerilla就渐渐的写成了gorllia((猩猩),再后来就写了monkey(猴子),所以猴子补丁的叫法是这么莫名其妙的得来的。

猴子补丁主要有以下几个用处:

  • 在运行时替换方法、属性等
  • 在不修改第三方代码的情况下增加原来不支持的功能
  • 在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加

这非常有用,不仅可以指导咱们修复项目的性能,还可以帮助你理解React是如何工作的。而且,当你更好地理解React的工作原理时,你就会成为更好的React开发人员。

通过声明一个额外的静态属性whyDidYouRender并将其值设置为true,可以将侦听器附加到任何自定义组件

import React from 'react'
import Button from '@material-ui/core/Button'

const Child = (props) => <div {...props} />

const Child2 = ({ children, ...props }) => (
  <div {...props}>
    {children} <Child />
  </div>
)

Child2.whyDidYouRender = true

const App = () => {
  const [state, setState] = React.useState({})

  return (
    <div>
      <Child>{JSON.stringify(state, null, 2)}</Child>
      <div>
        <Button type="button" onClick={() => setState({ hello: 'hi' })}>
          Submit
        </Button>
      </div>
      <Child2>Child #2</Child2>
    </div>
  )
}

export default App

这样做之后,在控制台才会打印令人恼人冗长警告:

clipboard.png

不要认为这是错误的提示,把它当成一件好事。 利用那些烦人的消息,这样你就可以修复那些浪费的重新渲染。

4. Create React App

大家都知道,Create React App是创建 React项目的最快方式(开箱即用)。

还有什么比 npx create-react-app <name>更简单的呢

咱们还有些人可能不知道的是如何使用CRA创建TypeScript项目,这个也很简单,只需要在末尾添加--typescript 即可:

npx create-react-app <name> — typescript

这样可以省去手动将TypeScript添加到CRA创建项目中的麻烦。

5. React Lifecycle Visualizer

React Lifecycle Visualizer是一个npm包,用于跟踪和可视化任意React组件的生命周期方法。

Why Did You Render 工具类似,你可以选择任何组件来启动生命周期可视化工具:

import React from 'react'
import {
  Log,
  VisualizerProvider,
  traceLifecycle,
} from 'react-lifecycle-visualizer'

class TracedComponent extends React.Component {
  state = {
    loaded: false,
  }

  componentDidMount() {
    this.props.onMount()
  }

  render() {
    return <h2>Traced Component</h2>
  }
}

const EnhancedTracedComponent = traceLifecycle(TracedComponent)

const App = () => (
  <VisualizerProvider>
    <EnhancedTracedComponent />
    <Log />
  </VisualizerProvider>
)

运行结果,如下所示:

clipboard.png

但是,其中一个缺点是它目前仅适用于类组件,因此尚不支持 Hook

6. Guppy

GuppyReact的一个友好且免费的应用程序管理器和任务运行器,它在桌面上运行且跨平台的,你可以放心用。

它为开发人员经常面临的许多典型任务(如创建新项目、执行任务和管理依赖项)提供了友好的图形用户界面。

Guppy 启动后的的样子

clipboard.png

7. react-testing-library

react-testing-library 是一个很棒的测试库,编写单元测试时,它会让你感觉很好。这个包提供了React DOM测试实用程序,鼓励良好的测试实践。

此解决方案旨在解决测试实现细节的问题,而不是测试React组件的输入/输出,就像用户会看到它们一样。

这是react-test -library解决的一个问题,因为理想情况下,你只希望您的用户界面能够正常工作,并最终正确地渲染出来。

如何将数据获取到这些组件并不重要,只要它们仍然提供预期的输出即可。

以下是使用此库进行测试的示例代码:

// Hoist helper functions (but not vars) to reuse between test cases
const renderComponent = ({ count }) =>
  render(
    <StateMock state={{ count }}>
      <StatefulCounter />
    </StateMock>,
  )

it('renders initial count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 })

  await waitForElement(() => getByText(/clicked 5 times/i))
})

it('increments

 count', async () => {
  // Render new instance in every test to prevent leaking state
  const { getByText } = renderComponent({ count: 5 })

  fireEvent.click(getByText('+1'))
  await waitForElement(() => getByText(/clicked 6 times/i))
})


8. React Developer Tools

React Developer Tools是一个扩展插件,允许在ChromeFirefox Developer Tools中检查React的组件层次结构。

这是React开发中最常见的扩展插件,并且是React开发人员可以用来调试其应用程序的最有用的工具之一。

9. Bit

通过Bit可以看到数以千计的开源组件,并允许还可以使用它们来构建项目。

图片描述

列表中有很多很多React组件可供咱们使用,包括选项卡,按钮,图表,表格,导航栏,下拉列表,加载微调器,日期选择器,面包屑,图标,布局等。

10. Storybook

Storybook 是一个轻松地构建UI组件的库。该工具启动一个实时开发服务器,支持开箱即用的热重载,你可以在其中独立地实时开发React组件。

这足以作为普通文档页面:

clipboard.png

11. React Sight

你有没有想过你的应用程序在流程图中的样子? React Sight允许你通过展示整个应用程序的实时组件层次结构树来可视化React应用程序。

它还支持react-routerRedux以及React Fiber

使用此工具,您可以将鼠标悬停在节点上,这些节点是指向与树中组件直接相关的组件的链接。

如果在查看结果时遇到问题,可以在地址栏中输入chrome:extensions ,查找“React Sight”框,然后单击“Allow access to file URLs”开关,如下所示:

clipboard.png

12. React Cosmos

React Cosmos是一个用于创建可重用React组件的开发工具。

它扫描项目中的组件,并使你能够:

  • 通过 props,context和state任意组合来渲染组件。
  • 模拟每个外部依赖项(API响应、localStorage等)。
  • 查看应用程序状态在与运行实例交互时的实时演变。

13. CodeSandbox

CodeSandbox一个在线编辑器,可以在上面创建Web应用程序并实行运行。

CodeSandbox 最初只在早期阶段支持React,但它们现在已经扩展到VueAngular等库的其他入门模板。

他们还支持使用常见的静态站点生成器(如GatsbyNext.js)创建项目来启动React Web项目。

clipboard.png

14. React Bits

React Bits是一个React模式、技术、技巧和技巧的集合,所有这些都以类似于在线文档的格式编写,你可以在同一个选项卡上快速访问不同的设计模式和技术、反模式、样式、UX变体以及其他与React相关的有用材料。

GitHub repo,目前有10083颗星星。

clipboard.png

15. folderize

folderize是一个VS Code 扩展。 它允许您将组件文件转换为组件文件夹结构。 React 组件仍然是一个组件,只是转换为一个目录。

例如,假设正在创建一个React组件,该组件将文件作为props来显示有用的信息,如元数据

元数据组件的逻辑占用了大量的行,因此咱们决定将其拆分为单独的文件。 但是,当这样做时,咱们就有两个相互关联的文件。

所以,就有有一个大概如下所示的目录:

clipboard.png

咱们可能想要将FileView.jsfilemetada.js抽象到目录结构中,就像Apple一样,尤其是考虑添加更多与FileScanner.js等文件相关的组件时。

这就是folderize为咱们所做的,这样组件们就可以得到一个类似的结构

clipboard.png

16. React Starter Projects

React starter projects 是一个依赖库列表,可以在上面快速你需要要的依赖库的名称并可以跳转对应的 github 上。

一旦看到一个你喜欢的入门项目,你就可以简单地克隆这个库,并根据你的需要进行修改。

但是,并不是所有的依赖库都是通过克隆使用,因为其中一些库需要通过安装形式,才能成为项目的依赖项。

clipboard.png

17. Highlight Updates

这可能是开发工具包中最重要的工具。 Highlight UpdatesReact DevTools扩展的一个特性,可以查看页面中的哪些组件正在不必要地重新渲染。

图片描述

它可以帮助你在开发页面时是更容易发现一些性能问题,因为它们会使用橙色或红色对严重的重新渲染问题进行着色。

18. React Diff Viewer

React Diff Viewer是一个简单而美观的文本差异对比工具 这支持分割视图,内嵌视图,字符差异,线条突出显示等功能。

clipboard.png

19. JS.coach

JS.coach 是我最常用来与 React 有需要的库的网站。从这个页面可以找到需要的任何东西。

它快速、简单、不断更新,并且总是能给我所有项目所需的结果。最近还添加了React VR,非常棒。

20. Awesome React

Awesome React开源库是一个与React相关的很棒的列表。

我可能会忘记其他网站并单独从这个链接学习React。 因为可以在此找到批量有用的资源,这些资源肯定会帮助我们构建出色的React应用程序!

21. Proton Native

Proton Native为咱们提供了一个React环境来构建跨平台的本机桌面应用程序。

它是Electron的替代产品,具有一些简洁的功能,包括:

  • 与React Native语法相同。
  • 适用于现有的React库,例如 Redux。
  • 兼容所有正常的 Node.js 包。

原文:https://medium.com/better-pro...

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug


交流

干货系列文章汇总如下,觉得不错点个Star,欢迎 加群 互相学习。

https://github.com/qq44924588...

我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!

关注公众号,后台回复福利,即可看到福利,你懂的。

clipboard.png

查看原文

赞 15 收藏 8 评论 0

starkwang 发布了文章 · 2020-05-11

熟悉 Bash 快捷键来提高效率

本文首发:https://shudong.wang/10780.html

Bash快捷键其实是GNU Readline快捷键,
GNU Readline Library是一个来接受用户输入的GNU软件包。
它是包括Bash在内的绝大多数Shell的底层库,
甚至OSX/Windows/Linux下的绝大多数软件都采用与之兼容快捷键。
因此这些快捷键可以在很大程度上支持纯键盘操作,尤其是在Linux/OSX下。

Bash是GNU计划的一部分,是多数Linux发行版提供的默认Shell。
Linux的精髓就在于命令行的高效,而学习命令行的第一步便是学习如何快速地输入Bash命令。

光标移动

快捷键描述
Ctrl + a移动光标到行首
Ctrl + e移动光标到行尾
Alt + b移动光标后退一个单词(词首)
Alt + f移动光标前进一个单词(词首)
Ctrl + f光标前进一个字母
Ctrl + b光标后退一个字母
Ctrl + xx当前位置与行首之间光标切换

剪切粘贴

快捷键描述
Ctrl + k删除从光标到行尾
Ctrl + u删除从光标到行首
Ctrl + w从光标向前删除一个单词
Alt + d从光标向后删除一个单词
Ctrl + d删除光标下一个字母
Ctrl + h删除光标前一个字母
Alt + tswap(当前单词, 上一个单词)
Ctrl + tswap(当前字母, 上一个字母)
Ctrl + y粘贴上一次删除的文本

大小写转换

快捷键描述
Alt + c大写当前字母,并移动光标到单词尾
Alt + u大写从当光标到单词尾
Alt + l小写从当光标到单词尾

历史命令

快捷键描述
Ctrl + r向后搜索历史命令
Ctrl + g退出搜索
Ctrl + p历史中上一个命令
Ctrl + n历史中下一个命令
Alt + .上一个命令的最后一个单词

终端指令

快捷键描述
Ctrl + l清屏
Ctrl + s停止输出(在Zsh中为向前搜索历史命令)
Ctrl + q继续输出
Ctrl + c终止当前命令
Ctrl + z挂起当前命令
Ctrl + d结束输入(产生一个EOF)

纯键盘写邮件?

绝大多数操作系统(OSX,Windows,Linux)中的绝大多数软件(GUI的、命令行的)
在底层都使用GNU Readline兼容的库来读取用户输入。
因此Bash快捷键完全可以胜任纯键盘写邮件

  • 同一行内移动光标:Ctrl-B, Ctrl-F, Ctrl-A, Ctrl-E等。
  • 上下行移动光标:Ctrl-P, Ctrl-N
  • 剪切/粘贴:Ctrl-W, Alt-D等。

相关阅读

查看原文

赞 3 收藏 1 评论 2

认证与成就

  • SegmentFault 讲师
  • 获得 1840 次点赞
  • 获得 42 枚徽章 获得 1 枚金徽章, 获得 8 枚银徽章, 获得 33 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

  • taro-kit

    🏆✌️taro 小程序脚手架。特性: 封装api、redux优雅集成、生成海报,异常日志上报。

注册于 2015-02-01
个人主页被 22k 人浏览