首页
Search
1
解决visual studio code (vscode)安装时没有选择安装路径问题
322 阅读
2
如何在 Clash for Windows 上配置服务
217 阅读
3
Linux 下 Bash 脚本 bad interpreter 报错的解决方法
150 阅读
4
Arch Linux 下解决 KDE Plasma Discover 的 Unable to load applications 错误
149 阅读
5
uniapp打包app提示通讯录权限问题,如何取消通讯录权限
113 阅读
clash
服务器
javascript
全部
游戏资讯
登录
Search
加速器之家
累计撰写
1,228
篇文章
累计收到
0
条评论
首页
栏目
clash
服务器
javascript
全部
游戏资讯
页面
搜索到
1228
篇与
的结果
2024-10-20
NextJs 如何按服务端或浏览器端的类型分别打包
NextJs 是一款优秀的 react 同构直出框架,写一次代码,能够同时在服务端和浏览器端。这是因为 NextJs 会在服务端和浏览器分别打包一份,然后通过数据进行互通。可是若一些模块只能在浏览器端使用,或只能在服务端使用,该怎么办呢? 1. 只在浏览器端使用的模块 # 例如@fingerprintjs/fingerprintjs组件,在 3.0.3 版本及之前,若在 NextJs 中引用时,会直接报错。这是我之前提的 issue:https://github.com/fingerprintjs/fingerprintjs/issues/602。例如:import FingerprintJS from '@fingerprintjs/fingerprintjs'; useEffect(() => { FingerprintJS.load(); }, []); 会提示 window 变量不存在的错误: ReferenceError: window is not defined 这是因为,在 FingerprintJS 模块中,直接调用了 window 变量,而 window 变量只有在浏览器端才有。因此,引用模块后,啥也没干,就已经报错了。解决方案,就是使用 import 异步引入:useEffect(() => { // 这里是浏览器的环境 import('@fingerprintjs/fingerprintjs') .then((FingerprintJS) => FingerprintJS.load()) .then((fp) => fp.get()) .then((result) => console.log(result.visitorId)); }, []); 这里也仅仅是用 FingerprintJS 模块来举个例子,不过该模块已经从 3.0.6 版本开始解决这个问题了。它会在调用 load 方法时,才会去引用 window 变量。 2. 只在服务端使用的模块 # 某组件 A 引用了 net 模块、stream 模块等只有在服务端才有的模块,这些模块就只能在服务端使用。若直接 import 的话,NextJs 也会在浏览器端打包一份,但这个组件在浏览器端又无法使用。我们公司一个很有名的名字服务-北极星模块,一个只在服务端使用的模块。开发的过程中,是没有感觉的,但打包时就会提示找不到模块:有两种解决方案。 2.1 只在 server 端引用 # NextJs 可以自定义 sever 文件,自定义 server 的文档:https://nextjs.org/docs/advanced-features/custom-server。如果可以的话,我们把代码逻辑引导 sever 文件中。// server.js const { createServer } = require('http'); const { parse } = require('url'); const next = require('next'); const Polaris = require('@tencent/polaris'); // 服务模块在这里引用,就可以了 const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); const handle = app.getRequestHandler(); app.prepare().then(() => { createServer((req, res) => { // Be sure to pass `true` as the second argument to `url.parse`. // This tells it to parse the query portion of the URL. const parsedUrl = parse(req.url, true); const { pathname, query } = parsedUrl; if (pathname === '/a') { console.log(Polaris); app.render(req, res, '/a', query); } else if (pathname === '/b') { app.render(req, res, '/b', query); } else { handle(req, res, parsedUrl); } }).listen(3000, (err) => { if (err) throw err; console.log('> Ready on http://localhost:3000'); }); }); server.js 本身就是服务端的文件,它不会通过 NextJs 的打包系统引入到浏览器端。 2.2 在服务侧按需引入 # 若不方便将代码执行路径引导到服务端的文件。我们可以在服务侧按需引入,然后在 next.config.js 中配置不要打包到浏览器端。export default function App { }; export async function getStaticProps() { const Polaris = require('@tencent/polaris'); console.log(Polaris); return {}; } getStaticProps()方法在 NextJs 中,就是服务端运行的方法。我们在这里面使用require()来按需引入。接着在 next.config.js 中:const withAntdLess = require('next-plugin-antd-less'); module.exports = (phase) => withAntdLess({ webpack: (cfg, { isServer, webpack }) => { const config = cfg; if (!isServer) { // 在浏览器端,忽略这些模块的打包 const ignoreList = ['@tencent\\/polaris', 'dns', 'dotenv']; ignoreList.forEach((n) => { config.plugins.push(new webpack.IgnorePlugin({ resourceRegExp: new RegExp(n) })); }); } return config; }, }); 在浏览器端,忽略这些模块的打包。 3. 总结 # NextJs 是一个在服务端和浏览器都可以运行的 react 框架,我们在使用的使用要特别注意有哪些是只能在客户端使用,哪些是只能在服务端使用。
2024年10月20日
15 阅读
0 评论
0 点赞
2024-10-20
leetcode1337 矩阵中战斗力最弱的 K 行的一种新颖解法
这是一道难度为“简单”的题目,我们先来看下题干https://leetcode-cn.com/problems/the-k-weakest-rows-in-a-matrix:给你一个大小为?m?* n?的矩阵?mat,矩阵由若干军人和平民组成,分别用 1 和 0 表示。 请你返回矩阵中战斗力最弱的?k?行的索引,按从最弱到最强排序。 如果第?i?行的军人数量少于第?j?行,或者两行军人数量相同但 i 小于 j,那么我们认为第 i 行的战斗力比第 j 行弱。 军人 总是 排在一行中的靠前位置,也就是说 1 总是出现在 0 之前。 这里有个矩阵:const mat = [ [1, 1, 0, 0, 0], [1, 1, 1, 1, 0], [1, 0, 0, 0, 0], [1, 1, 0, 0, 0], [1, 1, 1, 1, 1], ]; 因为军人总是在最前面,很多人最直观的算法就是,按照列,从上往下找,碰到第一个 0 的那一行就是最小的,遍历个遍,就能把找出最弱的前 K 行了。 1. 一个新颖的思路 # 但这里我提供了另一种思路:通过一个公式,计算出每行的战斗值: 该行的军人数量 * 100 + 行号。 按照这个公式,我们来实现一个算法: 每行:该行的军人数量 * 100 + 行号,得到该行的战斗值; 然后按照算出的战斗值进行从小到达的排序; 取前 k 个数据,然后进行取余,即得到结果; 我们用 C 语言来实现一下:// 升序 int cmp(const void *a, const void *b){ return *(int *) a - *(int *) b; } int *kWeakestRows(int **mat, int matSize, int *matColSize, int k, int *returnSize){ static int result[110]; int i, j, num, weighting; weighting = 100; for (i = 0; i < matSize; i++) { num = 0; for (j = 0; j < *matColSize; j++) { if (mat[i][j] == 0) { break; } num += mat[i][j]; } result[i] = num * weighting + i; // 军人数量 * 100 + 行号 } qsort(result, matSize, sizeof(result[0]), cmp); // 排序 *returnSize = k; for (i = 0; i < k; i++) { result[i] = result[i] % weighting; // 取余 } return result; } 这思路是不是很新颖?可是为什么这么计算,也是正确的呢? 2. 思路的剖析 # 这里我们要注意题目中给出的两个判断条件: 优先判断军人数量,军人数量少的则战斗力弱; 军人数量相同的,则行号小的战斗力弱; 而最后又需要的是最弱的行号。因此,我们把军人数量按照一定的权重进行放大后,其实大小关系是没有的,该相等的还是相等,该小的还是小。最后再加上行号,则可以把军人数量和行号两个维度结合算出一个战斗值来。这个算出来的战斗值就会满足上面的两个判断条件。 2.1 权重值的选择 # 为什么权重是 100 呢?我们先说下为什么不能小于 100 。假如我们设定权重是 90,上面的算法就会存在一个漏洞:行号的加持超过军人数量。举个例子,比如第 0 行有 1 个军人,第 99 行有 0 个军人;按照上面的算法,得到第 0 行的战斗值是 90(军人数量 1 * 90 + 行号 0),第 99 行的战斗值是 99(军人数量 0 * 99 + 行号 99),则第 0 行小于第 99 行;但实际上,是第 0 行的战斗力更强(因为军人数量更多)。题目要求整个战斗矩阵最大只有 100 行,当我们把权重设置成 100 时,则行号再大,也追不上军人数量的加持。实际上,权重 weighting >= 100 都是没问题的,只不过我们这里取了一个最小的临界值而已。 2.2 最后的那一步取余 # 取余这个操作,就是为了得到我们的行号。我们选择加持的权重的值大于最大行的行号(从 0 开始计数),对权重再进行取余后,得到的一定是行号。听懂掌声!
2024年10月20日
6 阅读
0 评论
0 点赞
2024-10-20
nodejs 中如何校验请求中的 referer
我们在写 nodejs 服务时,经常需要校验请求中的 referer 字段。有些只需要校验 referer 中的 hostname 是否合法即可,有些则要校验 referer 中的协议或者端口。同时,接收到的 referer 字段最后还有个斜杠/,若我们使用完全相等判断法,可能会造成前后端联调不太方便。那么该如何更方便的校验 referer 呢?这就要用到我们在上一篇文章如何在 nodejs 的原生 http 服务中获取请求参数中讲到的URL构造函数,这个函数可以把 url 拆分成几部分,然后我们可以分别进行判断。如,我们设置几个 referer 白名单,同时不限制端口:// 从headers中获取到referer const { referer, origin, host } = req.headers; const selfOrigin = referer || origin || `//${host}`; // 只匹配中间的域名,协议和端口均忽略 const { hostname } = new URL(selfOrigin, 'http://localhost/'); // 设置访问白名单 const ALLOW_HOSTS = ['joke.qq.com', 'news.qq.com']; // 当不在白名单中时,则返回403 if (!ALLOW_HOSTS.includes(hostname)) { res.status(403).end('403 forbidden'); next('403 forbidden'); } 若需要校验端口时,可以再加上端口的判断,如端口只能是空、80和443等。
2024年10月20日
14 阅读
0 评论
0 点赞
2024-10-20
nextjs 如何不显示next_data的数据
nextjs 提供了 getServerSideProps 方法(之前叫 getInitialProps 方法),用于在渲染页面之前请求数据,但 nextjs 框架为了能够前后端保持同步,会将请求到的数据,通过一个 script 标签传给前端: 但有时候,我们并不想把一些原始数据暴露到前端页面中,如一些博客网站、新闻网站等,基本以展示数据为主,没有同构的需要。所以,如何隐藏掉__NEXT_DATA__中的数据,只展示构建好的 html 呢? 1. 使用方式 # 在 nextjs 的 GitHub 上,有一个 pull request: Allow disabling runtime JS in production for certain pages (experimental) #11949,讨论了这个功能。从nextjs@9.4.0版本开始,为 pages 目录中的组件提供了一个unstable_runtimeJS的配置,当设置该参数为 false 后,则不会再展示__next_data__中的数据。 注意该设置只在process.env.NODE_ENV==='production'时生效。 不过,它带来的副作用也很大,它会导致整个页面实现的前端功能(如点击事件等)全部失效,包括该组件引用的子组件。// pages/home.tsx const Home = ({ nick, age }) => { const handleClick = () => { console.log('home click'); }; return ( home {nick} {age} ); }; // 移除__next_data__,移除所有前端的js export const config = { unstable_runtimeJS: false, }; // https://www.nextjs.cn/docs/basic-features/pages#%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E6%B8%B2%E6%9F%93 export const getServerSideProps = async (context: any) => { const { nick, age } = await fetch('api'); return { props: { nick, age } }; }; 最终渲染出来的 html 结构: 2. 副作用 # 从上图中可以看到,unstable_runtimeJS副作用很少很大的,虽不再展示 getServerSideProps 方法中返回的数据,但整个页面所有的 script 标签也都没了。这就造成该组件和它所有的子组件,均没有了前端功能。 3. 解决方案 # 若真的想在前端加载 js,也是有办法的。那就是使用 script 标签,自己加载 js 链接或者内容。 3.1 外链的方式 # 假如我们把要加载的前端 js 放在了https://cdn.bootcdn.net/ajax/libs/axios/0.26.0/axios.js链接中,直接通过 script 标签的 src 引入即可:const Home = ({ nick, age }) => { return ( home {nick} {age} ); }; 3.2 内敛的方式 # 都是同一个项目的代码,单独把某一部分拿出去再构建,实在是不方便。这里可以把 js 代码转成字符串,写到 script 标签中。 3.2.1 dangerouslySetInnerHTML 属性 # 使用 script 标签的 dangerouslySetInnerHTML 属性: console.log(Date.now()));`, }} > 3.2.2 script 标签的内容区 # {`document.querySelector('h1')?.addEventListener('click', () => console.log(Date.now()));`} 3.2.3 利用 function 的 toString() # 方法名调用 toString()会该方法的函数体,这里我们封装成一个立即执行函数的形式:const Home = ({ nick, age }: any) => { // 所有前端要执行的js,放在这里面 const bootstrap = () => { if (typeof document === 'undefined') { return; } document.querySelector('h1')?.addEventListener('click', () => console.log(Date.now())); }; return ( home {nick} {age} ); }; 最终编译后的效果: 4. 总结 # 从上面的分析也能看到,不是特别必要的时候,最好还是不要用unstable_runtimeJS禁用 js,否则为了实现相同的功能,就要用很多的奇技淫巧来弥补。
2024年10月20日
39 阅读
0 评论
0 点赞
2024-10-20
前端中对 url 的一些常用操作
我们平时操作 url 也比较多,如获取 url 中的参数,拼接 url 等,这里我们简单汇总下对 url 的常用操作。 1. 获取 url 中的参数 # 现在浏览器已经支持URLSearchParams对象了,我们可以直接用该方法获取参数。而且该方法的浏览器兼容性也非常好:// 获取当前url中的参数 const getQueryString = (name) => { const searchParams = new URLSearchParams(location.search); return searchParams.get(name); }; 若您的项目要兼容的范围更广,可以参考这篇文章中的方法:javascript 获取 URL 链接和 js 链接中的参数。 2. 获取 url 的域名、路径、referer 等 # 以前我们要获取一个 url 其中的某一部分,还得创建一个a标签来进行解析,如使用 DOM 中的 a 标签解析 url这篇文章中讲解到的。不过现在浏览器也提供了URL对象,获取 url 的某一部分也更简便了。 若只给 URL 传入一个参数,这个 url 必须是绝对地址,即需要携带协议,如 http://, https://, file://等;若不确定第一个参数中是否携带协议和主机信息,我们可以使用第二个参数进行补充。 若我们不确定要解析的参数是不是绝对地址,那就传第 2 个参数进行备用,如:const param = '/post/nodejs/nodejs-http-getquery-qwurz4.html?nick=wenzi'; // 若param是绝对地址,则直接使用,否则用第2个参数进行拼接 // 若拼接后依然不是绝对地址,则抛出TypeError异常 const uu = new URL(param, 'http://localhost'); console.log(uu); 执行后的结果(host 与 hostname 字段的区别:若链接中有端口时,host 字段会拼接上端口;如端口为 8080 时,则 host 字段为localhost:8080,hostname 为localhost):解析后,获取 hostname, path 等就非常方便了,不受其他字段的干扰。具体使用,也可以参考文章如何在 nodejs 的原生 http 服务中获取请求参数。 3. 修改 URL 的某一部分 # 对于一个完整的 URL,有时候我们只想修改其中的某一部分,而不影响其他部分,这个怎么处理呢?比如我们要把链接路径(pathname)中所有的字符a改为字符b,若使用正则的话,则可能把参数和 hash 路由中的字符也给替换掉。或者把当前链接中所有的参数,然后跳转到下一个链接。先把 url 拆分,再进行拼装,其实也可以,但并不是最好的方案。这里用URL的实例化对象,直接更新某一部分,然后最后返回.href属性即可。const replaceUrlPath = (url: string) => { const uu = new URL(url, 'http://localhost'); uu.pathname = uu.pathname.replace(/a/g, 'b'); // 对url的某一部分进行处理 return uu.href; }; replaceUrlPath('https://www.xiabingbao.com/post/javascript/url-handler-r7scei.html?a=b#main?c=123'); // https://www.xiabingbao.com/post/jbvbscript/url-hbndler-r7scei.html?a=b#main?c=123 4. 判断 url 地址是否为绝对地址 # 我们在这里简单地认为只要 url 有协议,它就是绝对地址,无论是什么协议(双斜杠//也算作绝对地址):const isAbsolute = (url) => /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url); 运行的结果:isAbsolute('http://localhost'); // true isAbsolute('https://localhost'); // true isAbsolute('file://localhost'); // true isAbsolute('qqnews://localhost'); // true isAbsolute('//localhost'); // true isAbsolute('/api/list'); // false 5. 拼接 URL # 拼接 url 时,尤其要注意前后的斜杠/:/** * Creates a new URL by combining the specified URLs * * @param {string} baseURL The base URL * @param {string} relativeURL The relative URL * @returns {string} The combined URL */ const combineURLs = (baseURL, relativeURL) => { // 将baseURL最后的斜杠和relativeURL最前面的斜杠去掉 return relativeURL ? `${baseURL.replace(/\/+$/, '')}/${relativeURL.replace(/^\/+/, '')}` : baseURL; }; 使用:combineURLs('https://www.xiabingbao.com/post/', '/request/axios-some-utils.html'); // 得到: https://www.xiabingbao.com/post/request/axios-some-utils.html 我们在这里仅仅是进行简单的拼接,并不保证拼接后的 url 的合法性。 6. http 协议转成 https # 这里用正则判断下就可以,若是以http://开头的,则替换成https://:/** * 将http链接转换为https链接 * @param url 要转换的http链接 */ const http2https = (url: string): string => { // 若不是以 http:// 开头,则原样返回 return url.replace(/^http:\/\//, 'https://'); }; 7. encodeURI 和 encodeURIComponent 的区别 # encodeURI 和 encodeURIComponent 的区别在于前者被设计来用于对完整 URL 进行 URL Encode,于是 URL 中的功能字符,比如&, ?, /, =等等这些并不会被转义;而后者被设计来对一个 URL 中的值进行转义,会把这些功能字符也进行转义。 escape 和 unescape 两个方法已被废弃,应当避免使用。 我们看着例子:const url = 'https://www.xiabingbao.com/post/react/nextjs-server-client-build-qxpzwi.html#1. 只在浏览器端使用的模块'; encodeURI(url); // https://www.xiabingbao.com/post/react/nextjs-server-client-build-qxpzwi.html#1.%20%E5%8F%AA%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E7%AB%AF%E4%BD%BF%E7%94%A8%E7%9A%84%E6%A8%A1%E5%9D%97 encodeURIComponent(url); // https%3A%2F%2Fwww.xiabingbao.com%2Fpost%2Freact%2Fnextjs-server-client-build-qxpzwi.html%231.%20%E5%8F%AA%E5%9C%A8%E6%B5%8F%E8%A7%88%E5%99%A8%E7%AB%AF%E4%BD%BF%E7%94%A8%E7%9A%84%E6%A8%A1%E5%9D%97 encodeURI 编译后的 url 可以正常访问,而 encodeURIComponent 编译后的字符串大部分都是作为参数。
2024年10月20日
36 阅读
0 评论
0 点赞
1
...
80
81
82
...
246