babycannotsay / summary Goto Github PK
View Code? Open in Web Editor NEW日常总结
日常总结
SyntaxError: Unexpected token import
solution:
yarn add --dev babel-jest @babel/core @babel/preset-env
// babel.config.js
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current', //针对当前node版本进行编译,删除该行可能导致`npm start`报错
},
},
],
],
};
SyntaxError: Invalid or unexpected token @import
src
下新建__mocks__
文件夹,该文件夹下新建styleMock.js
,
styleMock.js
内容为
module.exports = {};
配置jest.config.js
module.exports = {
rootDir: 'src',
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js'
}
};
process.env.something
自定义环境变量丢失,值为undefined
调用引用自定义环境的函数前,手动重新设置自定义环境变量,如下
// functions.js
const variable = process.env.something;
export function someFunction() {
console.log(variable);
console.log(process.env.something);
}
// functions.test.js
import { someFunction } from './functions.js';
process.env.something = 'something';
await someFunction();
另外functions.test.js
内someFunction的上一级作用域不为functions.js
的上一级作用域。以上代码打印
undefined
'something'
更复杂点的,比如重新设置自定义环境后还要还原,参考test process.env with Jest
Resolve alias in Jest not working
比如在resolve->alis
中把src
设置成@
,用@
去引用文件时,yarn test
的时候会提示找不到相应文件。
solution:
module.exports = {
rootDir: 'src',
moduleNameMapper: {
'^@(/(shared)/(.*)$)': '<rootDir>$1 // shared为src下的文件夹,具体场景请更改正则表达式
}
};
Jest matching objects in array
const data = [{ id: 1, name: 'hello' }, { id: 2, name: 'world' }]
expect(data).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: expect.any(Number),
name: expect.any(String)
})
])
);
jest macth type
expect.extend({
toBeType(received, argument) {
const initialType = typeof received;
const type = initialType === "object" ? Array.isArray(received) ? "array" : initialType : initialType;
return type === argument ? {
message: () => `expected ${received} to be type ${argument}`,
pass: true
} : {
message: () => `expected ${received} to be type ${argument}`,
pass: false
};
}
});
describe("testing extended expect", () => {
it("tests normal types correctly", () => {
expect("").toBeType("string");
expect({}).toBeType("object");
expect(1).toBeType("number");
});
it("tests array types correctly", () => {
expect([]).toBeType("array");
});
it("works with promises", () => {
expect(Promise.resolve([])).resolves.toBeType("array");
});
});
一个可以重复使用Babel注入的帮助程序代码来节省代码的插件。可以使用Promise,Set,Symbol等内置函数,以及使用所有需要无缝polyfill的Babel功能,而不会造成全局污染
generator/async
函数时,自动require('@babel/runtime/regenerator')
core-js
帮助程序,而不是假设它由用户polyfilled
@babel/runtime/helpers
可能有同学在用git命令行或者其他工具推送到github或者从github拉取的时候,会很慢。vpn表示一脸懵逼,我绝壁没偷懒啊,不干我事啊。
以新建的项目为例。以下是命令行
mkdir root
cd root
git init
cd .git
vim config
/*
* config的内容
*/
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
/*
* 需要添加的内容
*/
[http]
proxy = hostname:port
上述hostname和port对应vpn的地址和端口号,在相应vpn上的服务器设置上应该能找到。后续一系列git操作就不赘述了。
如果想全局设置代理(所有项目没有使用公司内部的gitlab之类的),可以直接使用命令行
git config --global http.proxy hostname:port
需要用户名密码的情况,命令行如下
git config --global http.proxy http://proxyUsername:[email protected]:port
大家都是出来写代码的,少不了要写上千万来行代码,其中重复性的代码占比又会很大。那么如何避免一次又一次写重复性的代码呢?除了代码自身的优雅、可复用,Jetbrains系如Intellij IDEA的Live Templates
或Visual Studio Code的Snippet
等内置工具都能很大程度上帮我们少写很多重复性的代码。下面就vsc的Snippet
,结合demo,讲讲它的用法。
快捷键Cmd + Shift + P
或F1
打开命令窗口,输入snippet
,选中配置用户代码片段
,这时候会弹出
可以在现有的代码片段文件上新增snippet,也可以自己新建代码片段文件。
Snippets片段以JSON格式定义,官方提供的例子如下
{
"For_Loop": {
"prefix": "for",
/**
* 在全局代码片段文件新增snippet时,
* 通过该项来指定该snippet使用范围,
* 如下所示,在文件以`.js`或者`.ts`结尾时可使用该snippet
*/
"scope": "javascript,typescript",
"body": [
"for (const ${2:element} of ${1:array}) {",
"\t$0",
"}"
],
"description": "For Loop"
}
}
For_Loop
is the snippet name(后续在指定快捷键绑定的时候会用到).prefix
defines how this snippet is selected from IntelliSense and tab completion. In this case for
.(前缀支持N:1,比如prefix
值为["for","fof"]
,则for
和fof
对应同一条代码片段)body
is the content and either a single string or an array of strings of which each element will be inserted as separate line.description
is the description used in the IntelliSense drop down(非必填).上述英文解释引自官方,怕翻译不到位影响读者理解,就不作翻译了。
下面用一张图展示在使用中各个属性对应的位置
上图左侧框中的为prefix
,右侧圈中的为description
,description
下方的为body
部分内容
Snippet
的语法集中在body
上。
Tabstops
: 即$1
、$2
等。使用$1
、$2
等表示按下键盘tab
后光标将要指向的位置。根据数字大小表示先后顺序。$0
表示光标最后指向的位置。可以存在多个相同的Tabstops
,并会同步更新。
以下是多个相同的Tabstops同步更新的示例
{
"For_Loop": {
"prefix": "for",
"scope": "javascript,typescript",
"body": [
"for (const ${2:element} of ${1:array}) {",
"\tconst item = $1[$2];$0",
"}"
],
"description": "For Loop"
}
}
以下是使用上述snippet的过程
Placeholders
:占位符。用户直接跳过Tabstops
不输入新值时,会使用占位符。它还能内嵌。
以下是占位符内嵌的示例
{
"placeholder": {
"prefix": "ph",
"body": "${1:hello ${2:world}}$0"
}
}
以下是使用上述snippet的过程
Choice
: 可选的占位符
以如下snippet为例
{
"choice": {
"prefix": "ch",
"body": "${1|hello,hi,how are you|}"
}
}
输入ch
按下tab键后,就会显示
注: 在Choice
中,,
、|
、$
、}
、\
可以使用\
转义;其他情况有且仅$
、}
、\
可以使用\
转义,其他字符无法转义, 详见https://code.visualstudio.com/docs/editor/userdefinedsnippets#_grammar
Variables
: 官方定义的变量
TM_SELECTED_TEXT:当前选定的文本或空字符串;
TM_CURRENT_LINE:当前行的内容;
TM_CURRENT_WORD:光标所处单词或空字符串
TM_LINE_INDEX:行号(从零开始);
TM_LINE_NUMBER:行号(从一开始);
TM_FILENAME:当前文档的文件名;
TM_FILENAME_BASE:当前文档的文件名(不含后缀名);
TM_DIRECTORY:当前文档所在目录;
TM_FILEPATH:当前文档的完整文件路径;
CLIPBOARD:当前剪贴板中内容。
时间相关
CURRENT_YEAR: 当前年份;
CURRENT_YEAR_SHORT: 当前年份的后两位;
CURRENT_MONTH: 格式化为两位数字的当前月份,如 02;
CURRENT_MONTH_NAME: 当前月份的全称,如 July;
CURRENT_MONTH_NAME_SHORT: 当前月份的简称,如 Jul;
CURRENT_DATE: 当天月份第几天;
CURRENT_DAY_NAME: 当天周几,如 Monday;
CURRENT_DAY_NAME_SHORT: 当天周几的简称,如 Mon;
CURRENT_HOUR: 当前小时(24 小时制);
CURRENT_MINUTE: 当前分钟;
CURRENT_SECOND: 当前秒数。
注释相关
BLOCK_COMMENT_START: 在PHP中输出 /* ,在HTML中输出 <!--
BLOCK_COMMENT_END: 在PHP中输出 */ ,在HTML中输出 -->
LINE_COMMENT: 在PHP中输出 // ,在HTML中输出 <!-- -->
Variable transforms
变量转换可将变量的值格式化处理后插入预定的位置。 它包括三个部分:
正则表达式和正则表达式匹配选项不作解释。
格式字符串在官方文档的Grammar
中如下
format ::= '$' int | '${' int '}'
| '${' int ':' '/upcase' | '/downcase' | '/capitalize' '}'
| '${' int ':+' if '}'
| '${' int ':?' if ':' else '}'
| '${' int ':-' else '}' | '${' int ':' else '}'
假设某整体片段为${variable/regexp/(format|text)/options}
,再结合上述语法,
整体片段可变为
${var_name/regular_expression/$1/options}
${var_name/regular_expression/${1}/options}
${var_name/regular_expression/${1:/upcase}/options}
// /downcase
和/capitalize
使用方式同/upcase
${var_name/regular_expression/${1:+if}/options}
${var_name/regular_expression/${1:?if:else}/options}
${var_name/regular_expression/${1:-else}/options}
${var_name/regular_expression/${1:else}/options}
${var_name/regular_expression/text/options}
上述format
中$
后的数字1表示分组捕获组(正则表达式中()
匹配到的数组)的第1项,同理$2表示分组捕获项第2项。分组捕获相关信息详见分组捕获
现有文件名global-js.json
,以demo说明上述片段含义。为了精简,输出值直接以body末尾注释表示,另外多个body直接放在一个snippet(实际操作不规范,仅仅为了精简)
注:使用transform末尾必须加/
,才能被识别。如${TM_FILENAME_BASE/(global).*/$1/
}
其中1
、2
意义相同
代码片段
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global).*/$1/}" // 输出: global
}
// 待匹配字符串 global-js
// 正则表达式 (global).*
// 全部匹配项 global-js
// 分组捕获组 ['global'],即$1=global
// $1替换global-js,即输出 global
3
表示对匹配到的相应分组捕获组转化成大写,或小写,或首字母大写,以替换正则表达式匹配到的全部字符串
代码片段(该片段仅展示转化成大写)
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global).*/${1:/upcase}/}" // 输出: GLOBAL
}
// 待匹配字符串 global-js
// 正则表达式 (global).*
// 全部匹配项 global-js
// 分组捕获组 ['global'],即$1=global
// 经${1:/upcase}转换后,为GLOABl
// ${1:/upcase}替换global-js,即输出GLOABl
4
表示匹配成功时,将if
所述语句完全替换正则表达式匹配项。
代码片段
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global)/${1:+if}/}", //输出: if-js
// 待匹配字符串 global-js
// 正则表达式 (global)
// 全部匹配项 global
// 分组捕获组 ['global'],即$1=global
// $1匹配成功, if替换global,即输出if-js
"body": "${TM_FILENAME_BASE/(global).*/${1:+if}/}" //输出: if
// 待匹配字符串 global-js
// 正则表达式 (global).*
// 全部匹配项 global-js
// 分组捕获组 ['global'],即$1=global
// $1匹配成功, if替换global-js,即输出if
}
5
表示匹配成功,且相应的分组捕获成功时,将if
所述语句完全替换正则表达式匹配项;
匹配成功,且相应的分组捕获为空时,将else
所述语句完全替换正则表达式匹配项;
匹配失败时,else
所述语句即为处理后的变量
代码片段
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global)/${1:?if:else}/}", //输出: if-js
// 待匹配字符串 global-js
// 正则表达式 (global)
// 全部匹配项 global
// 分组捕获组 ['global'],即$1=global
// $1匹配成功, if替换global,即输出if-js
"body": "${TM_FILENAME_BASE/global/${1:?if:else}/}", //输出: else-js
// 待匹配字符串 global-js
// 正则表达式 global
// 全部匹配项 global
// 分组捕获组 [],$1对应的分组捕获为空
// else替换global,即输出else-js
"body": "${TM_FILENAME_BASE/(globald)/${1:?if:else}/}", //输出: else
// 待匹配字符串 global-js
// 正则表达式 (globald),匹配失败
// 全部匹配项 null
// 分组捕获组 无
// 输出 else
}
6
同7
,表示匹配成功,且分组捕获(正则表达式中()
匹配到的项)成功时,不变;
匹配成功,且分组捕获为空时,将else
所述语句完全替换正则表达式匹配项;
匹配失败时,else
所述语句即为处理后的变量
代码片段
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global)/${1:else}/}", //输出: global-js
// 待匹配字符串 global-js
// 正则表达式 (global)
// 全部匹配项 global
// 分组捕获组 ['global'],即$1=global
// 不变,输出global-js
"body": "${TM_FILENAME_BASE/global/${1:else}/}", //输出: else-js
// 待匹配字符串 global-js
// 正则表达式 global
// 全部匹配项 global
// 分组捕获组 [],$1对应的分组捕获为空
// else替换global,输出else-js
"body": "${TM_FILENAME_BASE/(globald)/${1:else}/}", //输出: else
// 待匹配字符串 global-js
// 正则表达式 (globald),匹配失败
// 全部匹配项 null
// 分组捕获组 无
// 输出 else
}
8
表示匹配成功时,将text
完全替换正则表达式匹配项;
匹配失败时,不变
代码片段
"transform": {
"prefix": "tr",
"body": "${TM_FILENAME_BASE/(global)/text/}", //输出: text-js
}
Placeholder Transform
本质与Variable Transform
的第8条一致,只是正则表达式变为占位符常量
代码片段
"transform": {
"prefix": "tr",
"body": "$1 -> ${1/placeholder/text/}", //输入: placeholder 输出: placeholder -> text
}
首先打开keybindings.json
然后可以添加如下
{
"key": "cmd+k 1",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"snippet": "console.log($1)$0"
}
}
亦或者导入已有的snippet
{
"key": "cmd+k 1",
"command": "editor.action.insertSnippet",
"when": "editorTextFocus",
"args": {
"langId": "csharp", // 语言包,如javascript,typescript
"name": "myFavSnippet" // 对应最开始提过的name,如下面使用场景的`import snippet`
}
}
snippet
写snippet "import snipppet": {
"prefix": "sni",
"body": ["\"$1\": {", "\t\"prefix\": \"$2\",", "\t\"body\": [\"$3\"]", "}"]
},
加个可选的description
"snipppet": {
"prefix": "sni",
"body": [
"\"$1\": {",
"\t\"prefix\": \"$2\",",
"\t\"body\": [\"$3\"]${4:,\n\t\"description\":\"${5}\"}",
"}"
]
}
如某个数组长度较大的对象{title:'input',dataIndex:'input'}
,该数组中对象的每个title
或dataIndex
不尽相同,则可以写个临时snippet,直接生成该结构。
"templates": {
"prefix": "tem",
"body": [",{dataIndex:$1,", "title:$2}"],
"description": ""
}
import
组合"muji store file": {
"prefix": "store",
"body": [
"import { createStore } from '@souche-f2e/muji'",
"",
"type IState = {",
"",
"}",
"const state: IState = {",
"",
"}",
"const store = createStore({",
" state,",
" reducers: {",
" ",
" },",
" effects: {",
" ",
" },",
"})",
"export default store"
]
},
"index.tsx under pages": {
"prefix": "ind",
"scope": "typescriptreact",
"body": [
"import React, { Component } from 'react'",
"import { dispatch, IRootState } from '@@/store'",
"import { connect } from '@souche-f2e/muji'",
"const mapStateToProps = (state: IRootState) => state.${1/(.*)/${1:/downcase}/}",
"",
"interface I$1Props extends ReturnType<typeof mapStateToProps> {",
" ",
"}",
"interface I${1}State {",
"",
"}",
"class $1 extends Component<I${1}Props, I${1}State> {",
" render() {",
" return ${3:null}",
" }",
"}",
"export default connect(mapStateToProps)($1)"
]
}
只需要输入组件名,就可以一次性生成必备的格式。
安利一下prettier,配合snippet使用,美滋滋
新手或从其他语言转前端的同学刚接触js时,涉及到的数组循环一般都是for、while,以for居多。
forEach
和map
比如输入某个const a = [1,2,3]
,要输出数组[2,3,4]
。for操作会像下面这样(返回新数组)
const a = [1,2,3];
const b = [];
for (let i = 0; i < a.length; i++) {
b[i] = a[i] + 1;
}
console.log(b); // [2,3,4]
或(修改原数组)
const a = [1,2,3];
for (let i = 0; i < a.length; i++) {
a[i] += 1;
}
console.log(a); // [2,3,4]
而ES5新增的数组方法forEach
与map
也可以更优雅的实现
(返回新数组)
const a = [1,2,3];
const b = a.map(value => value + 1);
或(修改原数组)
const a = [1,2,3];
a.forEach((value,index) => a[index] = value + 1);
some
和every
或许有人会说forEach
不能中断,达不到for循环中的break
的效果
即
const a = [1,2,3];
for (let index = 0; index < a.length; index ++) {
if (index === 1) {
break;
}
// do something
}
forEach
确实不能,但是ES5新增的数组方法some
和every
都可以实现类似的效果。
some
方法的作用为:如果数组中至少有一个元素满足测试函数,则返回 true
,并且退出循环。
every
方法的作用为: 如果数组中的每个元素都满足测试函数,则返回 true
;否则返回 false
, 并退出循环。
const a = [1,2,3];
a.some((value, index) => {
if (index === 1) {
return true; // 此处达到break的效果
}
// do something
return false;
})
const a = [1,2,3];
a.every((value, index) => {
if (index === 1) {
return false; // 此处达到break的效果
}
// do something
return true;
})
至于for中的continue
,用forEach
实现就好了
const a = [1,2,3];
a.forEach(value => {
if (value === 3) return; // 此处达到continue的效果
// dosomething
})
filter
过滤a中的偶数,for的实现方式(返回新数组)
const a = [1,2,3];
const b = [];
for(let index = 0; index < a.length; index++) {
if (a[index] % 2 === 0) {
b.push(a[index]);
}
}
ES5新增的数组方法filter
也可以更优雅的做到
const a = [1,2,3];
const b = a.filter(value => value % 2 === 0);
reduce
和reduceRight
某些场景下可能需要对数组的每一项都进行某种操作。比如获取数组a
中元素的和。
for的实现方式
const a = [1,2,3];
let sum = 0;
for(let index = 0; index < a.length; index++) {
sum += a[i];
}
ES5新增的数组方法reduce
也可以实现,
其作用为: 从左到右为每个数组元素执行一次回调函数,并把上次回调函数的返回值放在一个暂存器中传给下次回调函数,并返回最后一次回调函数的返回值。
const a = [1,2,3];
const sum = a.reduce((prev, next) => prev + next, 0)
数组方法还有个reduceRight
,作用跟reduce
近似,不过是从右往左执行回调函数
findIndex
for循环获取第一个偶数的index
const a = [1,2,3];
let i = -1;
for(let index = 0; index < a.length; index++) {
if (a[index] % 2 === 0) {
i = index;
break;
}
}
ES6数组方法findIndex
实现
const a = [1,2,3];
const i = a.findIndex(value => value % 2 === 0);
find
for循环获取第一个偶数
const a = [1,2,3];
let i;
for(let index = 0; index < a.length; index++) {
if (a[index] % 2 === 0) {
i = a[index];
break;
}
}
ES6数组方法find
实现
const a = [1,2,3];
const i = a.find(value => value % 2 === 0);
find
未找到偶数时,会返回undefined
以上例子只是针对一些很简单的场景,复杂的场景就需要同学们举一反三了。希望对刚入坑的同学有所帮助。该文也是我在掘金的第一篇文章,由简入繁,希望在新的一年里自己能多总结多产出多分享。
await
报错,会退出try,进入catch。详见https://codepen.io/giggle/pen/KbeGjv?editors=1111Array.prototype.filter(Boolean)
过滤值为true的元素。如[true, false, 0].filter(Boolean)
返回[true]
不知道怎么跑,不想安装包到全局,先放弃。
Trie树,即字典树,又称单词查找树或键树,是一种树形结构。
空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的
Escape RegExp special characters
$&
: 最后匹配的字符.$'
: 最后匹配到的字符之后的字符.'--1++'.replace( /1/, '$`' ); // ----++
'--1++'.replace( /1/, '$\''); // --++++
'-1+'.replace( /1/, '$&'); // -1+
一个使用最小辅助函数将包含await表达式的异步函数转换为等效的Promise调用链的Babel插件。
We are trying to upgrade our angular from 12 to 13 with node 14.15.0 and facing the below error while giving npm start
ERROR in ./node_modules/@angular/platform-browser-dynamic/fesm2015/platform-browser-dynamic.mjs
Module not found: Error: Can't resolve '@angular/common' in '..@angular\platform-browser-dynamic\fesm2015'
ERROR in ./node_modules/@angular/platform-browser/fesm2015/platform-browser.mjs
Module not found: Error: Can't resolve '@angular/common' in '..@angular\platform-browser\fesm2015'
ERROR in ./node_modules/@angular/router/fesm2015/router.mjs
Module not found: Error: Can't resolve '@angular/common' in '..@angular\router\fesm2015'
ERROR in ./node_modules/@angular/platform-browser-dynamic/fesm2015/platform-browser-dynamic.mjs
Module not found: Error: Can't resolve '@angular/compiler' in '..@angular\platform-browser-dynamic\fesm2015'
ERROR in ./node_modules/@angular/common/fesm2015/common.mjs
Module not found: Error: Can't resolve '@angular/core' in '..@angular\common\fesm2015'
ERROR in ./node_modules/@angular/platform-browser-dynamic/fesm2015/platform-browser-dynamic.mjs
Module not found: Error: Can't resolve '@angular/core' in '..@angular\platform-browser-dynamic\fesm2015'
ERROR in ./node_modules/@angular/platform-browser/fesm2015/platform-browser.mjs
Module not found: Error: Can't resolve '@angular/core' in '..@angular\platform-browser\fesm2015'
ERROR in ./node_modules/@angular/router/fesm2015/router.mjs
Module not found: Error: Can't resolve '@angular/core' in '..@angular\router\fesm2015'
ERROR in ./node_modules/@angular/platform-browser-dynamic/fesm2015/platform-browser-dynamic.mjs
Module not found: Error: Can't resolve '@angular/platform-browser' in '..@angular\platform-browser-dynamic\fesm2015'
i 「wdm」: Failed to compile.
Below is our package.json
"dependencies": {
"@angular/animations": "^13.2.3",
"@angular/cdk": "^13.2.3",
"@angular/common": "^13.2.3",
"@angular/compiler": "^13.2.3",
"@angular/core": "^13.2.3",
"@angular/forms": "^13.2.3",
"@angular/http": "^7.2.15",
"@angular/material": "^13.2.3",
"@angular/platform-browser": "^13.2.3",
"@angular/platform-browser-dynamic": "^13.2.3",
"@angular/platform-server": "^13.2.3",
"@angular/router": "^13.2.3",
"@aspnet/signalr": "^1.1.4",
"@juggle/resize-observer": "^3.2.0",
"@ng-bootstrap/ng-bootstrap": "^10.0.0",
"@progress/kendo-angular-buttons": "^5.0.1",
"@progress/kendo-angular-charts": "^4.1.2",
"@progress/kendo-angular-common": "^1.2.1",
"@progress/kendo-angular-dateinputs": "^4.2.0",
"@progress/kendo-angular-dropdowns": "^4.2.3",
"@progress/kendo-angular-excel-export": "^3.0.1",
"@progress/kendo-angular-grid": "^4.5.0",
"@progress/kendo-angular-inputs": "^6.3.1",
"@progress/kendo-angular-l10n": "^2.0.0",
"@progress/kendo-angular-pdf-export": "^2.0.0",
"@progress/kendo-angular-popup": "^3.0.4",
"@progress/kendo-drawing": "^1.6.0",
"@progress/kendo-file-saver": "^1.0.7",
"@progress/kendo-theme-default": "^4.9.0",
"applicationinsights-js": "^1.0.20",
"bootstrap": "^5.1.2",
"core-js": "^3.21.1",
"expose-loader": "^0.7.5",
"hammerjs": "^2.0.8",
"jquery": "^3.6.0",
"mat-currency-format": "0.0.7",
"moment": "^2.24.0",
"moment-timezone": "^0.5.27",
"ngx-bootstrap": "^5.6.2",
"ngx-perfect-scrollbar": "^8.0.0",
"ngx-restangular": "^5.0.0",
"ngx-swiper-wrapper": "^8.0.2",
"regenerator-runtime": "^0.13.3",
"rxjs": "^7.5.4",
"rxjs-compat": "^6.5.3",
"sass": "^1.45.2",
"zone.js": "^0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^13.2.4",
"@angular/cli": "^13.2.4",
"@angular/compiler-cli": "^13.2.3",
"@angular/language-service": "^13.2.3",
"@ngtools/webpack": "^8.3.20",
"@progress/kendo-angular-intl": "^2.0.0",
"@progress/kendo-data-query": "^1.5.2",
"@types/angular": "^1.6.57",
"@types/angular-animate": "^1.5.10",
"@types/angular-mocks": "^1.7.0",
"@types/angular-resource": "^1.5.15",
"@types/angular-route": "^1.7.0",
"@types/angular-sanitize": "^1.7.0",
"@types/applicationinsights-js": "^1.0.9",
"@types/google.analytics": "^0.0.40",
"@types/jasmine": "^3.10.3",
"@types/jquery": "^3.3.31",
"@types/lodash": "^4.14.149",
"@types/moment": "^2.13.0",
"@types/moment-timezone": "^0.5.12",
"@types/node": "^17.0.18",
"@types/webpack-env": "^1.14.1",
"angular-router-loader": "^0.8.5",
"angular2-template-loader": "^0.6.2",
"canonical-path": "^1.0.0",
"codelyzer": "^6.0.2",
"concurrently": "^5.0.1",
"copy-webpack-plugin": "^5.1.0",
"css-loader": "^3.3.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^5.0.2",
"file-saver": "^2.0.2",
"gsap": "^3.7.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"http-server": "^0.12.0",
"install": "^0.13.0",
"jasmine-core": "^4.0.0",
"jasmine-spec-reporter": "^7.0.0",
"karma": "^6.3.16",
"karma-chrome-launcher": "^3.1.0",
"karma-cli": "^2.0.0",
"karma-jasmine": "^4.0.1",
"karma-jasmine-html-reporter": "^1.7.0",
"lodash": "^4.17.21",
"ng2-odometer": "^1.1.3",
"ngx-countdown": "^8.0.3",
"ngx-modialog": "^5.0.1",
"null-loader": "^3.0.0",
"protractor": "^7.0.0",
"raw-loader": "^4.0.0",
"rimraf": "^3.0.0",
"rollup": "^1.27.11",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-uglify": "^6.0.4",
"rxjs-tslint": "^0.1.8",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.1",
"terser-webpack-plugin": "^2.3.0",
"to-string-loader": "^1.1.6",
"ts-loader": "^6.2.1",
"ts-node": "~8.5.4",
"tslint": "^6.1.3",
"typescript": "^4.4",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0",
"webpack-merge": "^4.2.2",
"xlsx": "^0.17.2"
}
}
WhiteSourceBolt has generated a report for vulnerability supports-color-3.2.3. They have also mentioned the top fix for this issue as below
But we have already given the latest version 0.5.2 for fresh module in express.js
Also we are having the latest version of expression 4.17.1
Is vulnerability exists in fresh 0.5.2 itself?
配置@babel/preset-env
后,允许你使用最新的javascript,而无需关注代码转译和相关的浏览器polyfill。它能使你打包后的javascript块更小。
如果没有很多很棒的开源项目,比如browserslist
, compat-table
,electron-chromium
,@babel/preset-env
是不会存在的。
我们利用这些数据源来维护我们支持的目标环境的哪个版本获得JavaScript语法或浏览器功能的支持的映射,以及这些语法和功能到Babel转换插件和core-js polyfill
的映射。(存疑)
注意:@babel/preset-env
不支持stage-x
插件
@babel/preset-env
接受您指定的任何目标环境,并根据@babel/preset-env
的映射检查目标环境,得以编译插件列表并将其传递给Babel。
boolean
类型,默认为false
。loose
为true
时,可生成更简单的es5代码。demo
loose
为false
时,转换后的es5代码会尽可能的遵循ECMAScript6的语义。demo
targets: 描述你为项目支持/定位的环境, 默认为{}
modules: 启用将ES6模块语法转换为另一种模块类型。将此设置为false将不会转换模块。默认为auto
useBuiltIns: 该属性配置了@babel/prese-env
怎么处理polyfills, 默认为false。
entry: 用特定的导入替代import "@babel/polyfill"
或者`require("@babel/polyfill"), 导入到单个文件,比如
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
usage: 引用,如const a = new Promise();
时,如环境支持,则不添加导入。环境不支持,则在相应文件中添加特定的导入,如import "core-js/modules/es.promise";
,为每个文件自动添加polyfill。
false: 不为每个文件自动添加polyfill,也不将@babel/polyfill
导入到单个文件。
今天开始啃库,过程中遇到的package.json属性逐一添加、解释。
name: 发布npm包必需存在name和version两个属性。这两个属性共同组成了npm模块的唯一标志。修改包内容的同时,应该修改version。
.
或_
开头name可以选择以作用域为前缀,例如@myorg/mypackage
version: version必须可以被node-semver模块解析
description: 字符串描述,有助于人们发现你的包
main: main属性指定了程序的主入口文件。意思是,如果你的模块被命名为foo,用户安装了这个模块并通过require("foo")来使用这个模块,那么require返回的内容就是main属性指定的文件中module.exports指向的对象。
它应该指向模块根目录下的一个文件。对大对数模块而言,只有一个主入口文件才最有意义。
scripts: scripts属性是一个对象,里边指定了项目的生命周期个各个环节需要执行的命令。key是生命周期中的事件,value是要执行的命令。
bin: 很多模块有一个或多个需要配置到PATH路径下的可执行文件,npm让这个工作变得十分简单(事实上,它使用此功能来安装“npm”可执行文件。)
要使用这个属性,请在package.json中配置bin字段,该字段是命令名到本地文件名的映射。 在安装时,npm会将该文件符号链接到用于全局安装的prefix/ bin
,或者用于本地安装的./node_modules/.bin/
。
例如,myapp可以这样:
{"bin": {"myapp":"./cli.js"}}
因此,当你安装myapp时,它会创建一个从cli.js脚本到usr/local/bin/myapp
的符号链接。
如果您有一个可执行文件,并且其名称应该是包的名称,那么您可以将其作为字符串提供。 例如:
{ "name": "my-program"
, "version": "1.2.5"
, "bin": "./path/to/program" }
等价于
{ "name": "my-program"
, "version": "1.2.5"
, "bin" : { "my-program" : "./path/to/program" } }
请确保bin中引用的文件以#!/usr/bin/env node
节点开头,否则脚本将在没有可执行node的情况下启动!
dependencies: 依赖关系在将包名称映射到版本范围的简单对象中指定。 版本范围是一个字符串,其中包含一个或多个以空格分隔的描述符。 也可以使用tarball或git URL识别依赖关系。
请不要在依赖项对象中放置测试工具或转换器。
有关指定版本范围的更多详细信息,请参阅semver。
URLs
Git URls
Github URls
例如,这些都是合法的
{ "dependencies" :
{ "foo" : "1.0.0 - 2.9999.9999"
, "bar" : ">=1.0.2 <2.1.2"
, "baz" : ">1.0.2 <=2.3.4"
, "boo" : "2.0.1"
, "qux" : "<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0"
, "asd" : "http://asdf.com/asdf.tar.gz"
, "til" : "~1.2"
, "elf" : "~1.2.3"
, "two" : "2.x"
, "thr" : "3.3.x"
, "lat" : "latest"
, "dyl" : "file:../dyl"
}
}
在版本范围的地方可以写一个url指向一个压缩包,模块安装的时候会把这个压缩包下载下来安装到模块本地。
Git urls组成
<protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]
<protocol>
是git
, git+ssh
, git+http
, git+https
, git+file
其中的一个.
commit-ish 默认是master分支。
Git url可以像下面一样:
git+ssh://[email protected]:npm/cli.git#v1.0.27
git+ssh://[email protected]:npm/cli#semver:^5.0
git+https://[email protected]/npm/cli.git
git://github.com/npm/cli.git#v1.0.27
从版本1.1.65开始,你可以参考GitHub urls, 如"foo": "user/foo-project"
。 与git URL一样,可以包含commit-ish后缀。 例如:
{
"name": "foo",
"version": "0.0.0",
"dependencies": {
"express": "expressjs/express",
"mocha": "mochajs/mocha#4727d357ea",
"module": "user/repo#feature\/branch"
}
}
从版本2.0.0开始,您可以提供包含包的本地目录的路径。 可以使用以下任何形式使用npm install -S
或npm install --save
保存本地路径:
../foo/bar
~/foo/bar
./foo/bar
/foo/bar
package.json 生成的相对路径如下:
{
"name": "baz",
"dependencies": {
"bar": "file:../foo/bar"
}
}
此功能有助于本地脱机开发和创建需要在不想访问外部服务器的情况下进行npm安装的测试,但在将包发布到公共注册表时不应使用此功能。
devDependencies: 如果有人计划在他们的程序中下载和使用您的模块,那么他们可能不希望或不需要下载和构建您使用的外部测试或文档框架。
在这种情况下,最好将这些附加项映射到devDependencies对象中。
这些东西将在从包的根目录执行npm链接或npm安装时安装,并且可以像任何其他npm配置参数一样进行管理。 更多信息,请参阅npm-config。
对于非特定于平台的构建步骤,例如将CoffeeScript或其他语言编译为JavaScript,请使用prepare
脚本执行此操作,并使所需的包成为devDependency。
如
{ "name": "ethopia-waza",
"description": "a delightfully fruity coffee varietal",
"version": "1.2.3",
"devDependencies": {
"coffee-script": "~1.6.3"
},
"scripts": {
"prepare": "coffee -o lib/ -c src/waza.coffee"
},
"main": "lib/waza.js"
}
prepare
脚本将在发布之前运行,以便用户可以使用该功能而无需他们自己编译。在开发模式下(即本地运行npm install),它也将运行此脚本,以便您可以轻松地进行测试。
people fields:author, contributors
author是一个people
。 contributors是一群people
(数组表示)。 people
是具有name
字段、可选的url
和email
的对象,如下所示:
{“name”:“Barney Rubble”
,“email”:“[email protected]”
,“url”:“http://barnyrubble.tumblr.com/”
}
或者您可以将所有内容缩短为单个字符串,npm将为您解析它:
"Barney Rubble <[email protected]> (http://barnyrubble.tumblr.com/)"
电子邮件和网址都是可选的。
npm也可以为你的npm用户信息设置顶级maintainers
字段。
license: 您应该为您的包指定许可证,以便人们知道如何使用它,以及您对其进行的任何限制。
如果您不希望授予他人在任何条款下使用私人或未发布的包裹的权利:
{ "license": "UNLICENSED" }
也可以考虑设置private: true
防止意外发布。
https://docs.npmjs.com/files/package.json
npm package.json属性详解
Detect whether a terminal supports color
process.stdout: 存疑
process.stderr: 存疑
process.platform: process.platform属性返回字符串,标识Node.js进程运行其上的操作系统平台。
process.versions: process.versions属性返回一个对象,此对象列出了Node.js和其依赖的版本信息。
os.release(): 返回一个字符串, 指定操作系统的发行版.
Check if process.argv has a specific flag
process.argv: 返回进程启动时的命令行参数
String.prototype.startsWith(): startsWith()方法用来判断当前字符串是否是以另外一个给定的子字符串“开头”的
后续【node_modules】相关的文章,会记录相关库的核心代码、奇技淫巧以及对我自己而言的新知识点。package.json相关详见【npm】package.json详解,有关babel的详见【babel】。后续也许也会分离出别的知识点作为文章。
引用模块路径时对大小写敏感
顾名思义,上下文替换插件。允许覆盖查找规则。
主要用于动态导入时,减小导入包的大小。如引入moment
时,不做处理的话,默认会打包moment/locale下的所有语言环境。但是大多数情况下,只需要支持特定语言环境就OK了。
以下是限制模块使用的一个小例子:
new webpack.ContextReplacementPlugin(
/moment[\/\\]locale$/,
/de|fr|hu/
)
限定查找moment/locale
上下文里符合/de|fr|hu/
表达式的文件,因此也只会打包这几种本地化内容.
也可以用于重定向请求文件。
ContextReplacementPlugin
Removing unused languages from dynamic import
进度条插件
前后端合作刚开始开发某个项目时,后端api接口基本上是不能一蹴而就的。但是api接口返回的数据接口可以尽快定下来。而前端在制作功能页面时,经常需要数据才能处理的得心应手。而不管是用mock,还是临时变量赋值,都涉及到造数据。一般来说,数据类型以数组居多。接下来,就从造数组数据说开去。
数组最基本的特征是有length
属性,有length
属性的对象(非数组)称作伪数组。伪数组是不能够直接调用数组的方法的。不过以下两种方法可以将伪数组转为数组。
const obj = {0:'a',1:'b',length:2}; // 伪数组
const arrLike = Array.prototype.slice.call(obj);
console.log(arrLike); // ["a","b"]
const obj = {0:'a',1:'b',length:2}; // 伪数组
const arrLike = Array.from(obj);
console.log(arrLike); // ["a","b"]
可以通过以下3种方法生成可循环的长度为3的数组,结果都是在chrome打印的
const arr = Array(3).fiil(undefined);
console.log(arr); // [undefined, undefined, undefined]
const arr = Array.apply(null, Array(3));
console.log(arr); // [undefined, undefined, undefined]
const arr = Array.from({length: 3});
console.log(arr); // [undefined, undefined, undefined]
那么有人可能会疑惑为什么不直接用Array(3)呢?我们先打印Array(3)在chrome下输出什么,以及,它是否可循环3次。
const arr = Array(3);
console.log(arr); // [empty × 3]
arr.forEach(item => console.log(item)); // 回调函数未执行,循环0次。
那么这个chrome下的empty
究竟是什么东西呢。我们先来看看还有什么情况会出现这个empty
const arr = [1,2,3];
delete arr[1];
console.log(arr); // [1, empty, 3];
arr.forEach(item => console.log(item)); // 1,3 实际循环了2次。
arr.length = 5;
console.log(arr); // [1, empty, 3, empty × 2]
arr[6] = 7;
console.log(arr); // [1, empty, 3, empty × 3, 7]
由上述forEach可知,数组的循环次数不一定等于数组的长度。而是等于数组的长度减去empty的个数。
我们知道数组本质上也是对象。那么我们就把数组当成对象,以对象看待试试。
const arr = [1,2,3];
delete arr[1]; // output: [1, empty, 3]
console.log(Object.getOwnPropertyDescriptors(arr));
Object.getOwnPropertyDescriptors()
方法用来获取一个对象的所有自身属性的描述符。输出如下
delete
操作符用于删除对象的某个属性,数组也是对象,删掉之后输出上面的结果不是很正常吗。但是,等等。
也就是说数组中打印出来的empty
等于对象中不存在的属性。即empty
在打印结果中的作用就是占位用的,其意义是,举个例子,[1, empty, 3]
这个对象的自身属性1
,已经不存在了。用对象表示的话,就是{ 0: 1, 2: 3, length: 3 }
。另外数组的for循环或者循环方法应该是对象的for...in
的数组展示。那么元素为empty
的不执行回调函数,也可以理解了。
回到Array(3).fill(undefined)
,既然Array(3)
输出[empty × 3]
,那么fill
之后为何会输出[undefined, undefined, undefined]
呢,不是说好的回调函数不执行了吗。咳咳,详情可以看fill
的polyfill。可以看到fill
的根据是数组的length属性。毫无疑问,Array(3)的length就是3。
我们知道Array(1,2,undefined)
会生成[1, 2, undefined]
,所以Array(...Array(3))
按chrome的empty
填充的话,其实就是Array(empty, empty, empty)
。其实相当于{0: empty, 1: empty, 2, empty, length: 3}
。而对象中不存在的属性,比如
const a = {};
console.log(a.b); // undefined
还是会输出undefined
,empty
实际上并不存在,所以Array(...Array(3))
输出[undefined, undefined, undefined]
没毛病。
而Array.from({length : 3})
输出[undefined, undefined, undefined]
,也是以length为基准生成数组的,详见Array.from()
以上都清楚了以后,造数组数据不是信手拈来的事么。
用来描述如何持续构建,支持各种语言,各种系统环境
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.