总结一些好用的库及使用方法
ip2region——查询ip属地
import ip2regin from 'node-ip2region';
const searcher = ip2regin.create();
let result = searcher.memorySearchSync('106.33.230.74');
result=searcher.btreeSearch('106.33.230.74',(err,data)=>{
if(err){
console.log(err);
}else{
console.log(data);
}
});
sharp——图片处理及压缩工具
const sharp = require('sharp');
(async () => {
const semiTransparentRedPng = await sharp('input.jpg')
.resize(300, 300)
.jpeg({quality: 70})//png webp...
.toFile('output.jpeg');
})();
puppeteer——chrome自动化测试工具
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: true,
});
const page = await browser.newPage();
await page.goto('https://www.bilibili.com/', {
waitUntil: 'load'
});
await page.setViewport({
width: 1280,
height: 800
});
await page.evaluate(async function () {
let scroll = 0;
await new Promise((res, rej) => {
const interval = setInterval(() => {
if (window.document.documentElement.scrollHeight - window.document.documentElement.scrollTop - window.document.documentElement.clientHeight <= 0) {
clearInterval(interval);
res();
} else {
window.scrollTo(0, scroll);
scroll += 4;
}
}, 1);
});
const images = document.querySelectorAll('img');
await new Promise((res, rej) => {
setInterval(() => {
if (images[images.length - 1].complete) {
res();
}
}, 500);
});
});
await page.screenshot({path: 'example.png', fullPage: true});
await page.pdf({path: '都是对的.pdf', format: 'a4'});
await browser.close();
})();
webp-converter——webp图片处理工具
developers.google.com/speed/webp/…
webp.cwebp(originName,gzipName,`-q ${quantity} -m 6 -resize 0 ${height} -mt -low_memory`,)
.then(() => { res();});
zx——命令行脚本工具
let result = await $`dir`;
console.log(result.stdout);
dotenv——加载.env环境变量
import dotenv from 'dotenv';
dotenv.config();
console.log(process.env.MY_ENV);
node-media-server——流媒体推流工具
const nodeMediaServer = require('node-media-server');
const config = {
rtmp: {
port: 3001,
chunk_size: 6000,
gop_cache: true,
ping: 30,
ping_timeout: 60
},
http: {
port: 3002,
allow_origin: '*'
}
};
const nms = new nodeMediaServer(config);
nms.run();
resso——极简react状态管理工具
import resso from 'resso';
const store = resso({
count: 0,
text: 'hello',
inc: () => store.count++,
});
function App() {
const { count,inc } = store; // destructure first, then use
return (
<>
{count}
<button onClick={inc}>+</button>
</>
);
}
react-syntax-highlighter+react-markdown+remark-gfm——markdown组件
import {PrismLight as SyntaxHighlighter} from 'react-syntax-highlighter';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import js from 'react-syntax-highlighter/dist/esm/languages/prism/javascript';
import jsx from 'react-syntax-highlighter/dist/esm/languages/prism/jsx';
import atomOneDark from 'react-syntax-highlighter/dist/esm/styles/prism/one-dark';
SyntaxHighlighter.registerLanguage('jsx', jsx);
SyntaxHighlighter.registerLanguage('javascript', js);
const components = {
code({node, inline, className, children, ...props}) {
const match = /language-(\w+)/.exec(className || 'language-jsx');
return (
<SyntaxHighlighter
style={atomOneDark}
customStyle={{}}
showLineNumbers={true}
language={match[1]}
PreTag="div"
children={children}
{...props}
/>
);
},
td({children}) {
return <td style={{borderLeft: '1px solid black', borderRight: '1px solid black'}}>{children}</td>;
},
tr({children, ...props}) {
return <tr style={{borderTop: '1px solid black', borderBottom: '1px solid black'}}>{children}</tr>;
},
th({children, style, ...props}) {
return <th style={{borderLeft: '1px solid black', borderRight: '1px solid black', ...style}}>{children}</th>;
},
img({...props}) {
let splits = props.src.split('/');
splits[splits.length - 1] = `gzip_${splits[splits.length - 1]}.webp`;
let all = splits.join('/');
return (
<div style={{textAlign: 'center'}}>
<div style={{
display: 'inline-block',
height: props.alt,
width: props.alt,
}}>
<Image src={all} alt={props.alt} preview={{src: props.src}}/>
</div>
</div>
);
},
h1({...props}) {
return <h1 style={{fontWeight: 700}}>{props.children}</h1>;
},
li({...props}) {
return <li children={props.children} style={{listStyle: 'initial', marginLeft: '16px'}}/>;
},
};
export default memo(function Blog({content, lastModified}) {
return (
<div className={'blog-content'}>
<ReactMarkdown children={content} components={components} remarkPlugins={[remarkGfm]}/>
<div className={'blog-content-lastModified'}>
<FieldTimeOutlined/> 最后编辑于:{parseTime(lastModified)}
</div>
</div>
);
});
rc-footer——页脚组件
import Footer from "rc-footer";
<Footer theme={"light"} columns={result} bottom={`Made by Pikachu - Powered by React`} />
result=
[
{
"title": "联系方式",
"items": [
{
"title": "QQ",
"url": "tencent://message/?uin=530394623&Menu=yes",
"description": "530394623",
"openExternal": true
},
{
"title": "邮箱",
"url": "http://mail.qq.com/cgi-bin/qm_share?t=qm_mailme&email=530394623@qq.com",
"description": "530394623@qq.com",
"openExternal": true
},
{
"title": "微信",
"url": null,
"description": "gangganghao6"
},
{
"title": "Github",
"url": "https://github.com/gangganghao6",
"description": "gangganghao6"
}
]
},
{
"title": "Github项目展示",
"items": [
{
"title": "Blog-前台",
"url": "https://github.com/gangganghao6/react-blog",
"description": "已基于nestjs版后端重构",
"openExternal": true
},
{
"title": "Blog-后台",
"url": "https://github.com/gangganghao6/react-blog-backstage",
"description": "已基于nestjs版后端重构",
"openExternal": true
},
{
"title": "Blog-后端(nestjs+MySQL重构版)",
"url": null,
"description": "最新重构版后端",
"openExternal": true
},
{
"title": "Blog-后端(Express+JSONServer版)",
"url": "https://github.com/gangganghao6/react-blog-server",
"description": "因API变化过大,已废弃",
"openExternal": true
}
]
}
]
immer+use-immer——immutable数据
import React from "react";
import { useImmer,useImmerReducer } from "use-immer";
function App() {
const [person, updatePerson] = useImmer({
name: "Michel",
age: 33
});
function updateName(name) {
updatePerson(draft => {
draft.name = name;
});
}
return (
<div className="App">
<h1>
Hello {person.name} ({person.age})
</h1>
<input
onChange={e => {
updateName(e.target.value);
}}
value={person.name}
/>
</div>
);
}