Giter Club home page Giter Club logo

summary's People

Contributors

babycannotsay avatar

Stargazers

 avatar

Watchers

 avatar  avatar

summary's Issues

【Jest】Jest应用踩坑记

  1. SyntaxError: Unexpected token import

    solution:

    1. yarn add --dev babel-jest @babel/core @babel/preset-env

    2.  // babel.config.js
       module.exports = {
         presets: [
           [
             '@babel/preset-env',
             {
               targets: {
                 node: 'current',  //针对当前node版本进行编译,删除该行可能导致`npm start`报错
               },
             },
           ],
         ],
       };
      
  2. 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'
       }
     };
    
  3. 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

  4. Resolve alias in Jest not working

    比如在resolve->alis中把src设置成@,用@去引用文件时,yarn test的时候会提示找不到相应文件。

    solution:

      module.exports = {
       rootDir: 'src',
       moduleNameMapper: {
         '^@(/(shared)/(.*)$)': '<rootDir>$1         // shared为src下的文件夹,具体场景请更改正则表达式
       }
     };
    
  5. 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)
         })
       ])
     );
    
  6. 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");
     	});
     });
    

SyntaxError: Invalid or unexpected token @import

test process.env with Jest

Testing with Jest and Webpack aliases

Jest matching objects in array

Test if object, array or string.

【babel】@babel/plugin-transform-runtime

描述

一个可以重复使用Babel注入的帮助程序代码来节省代码的插件。可以使用Promise,Set,Symbol等内置函数,以及使用所有需要无缝polyfill的Babel功能,而不会造成全局污染

做什么

  • 使用generator/async函数时,自动require('@babel/runtime/regenerator')
  • 如果需要,可以用core-js帮助程序,而不是假设它由用户polyfilled
  • 自动删除内联的Babel帮助程序并使用模块@babel/runtime/helpers

【Git】给git设置代理

前言

可能有同学在用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

【VSC】Snippet不完全指南

前言

大家都是出来写代码的,少不了要写上千万来行代码,其中重复性的代码占比又会很大。那么如何避免一次又一次写重复性的代码呢?除了代码自身的优雅、可复用,Jetbrains系如Intellij IDEA的Live Templates或Visual Studio Code的Snippet等内置工具都能很大程度上帮我们少写很多重复性的代码。下面就vsc的Snippet,结合demo,讲讲它的用法。

创建Snippet

快捷键Cmd + Shift + PF1打开命令窗口,输入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"],则forfof对应同一条代码片段)
  • 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语法

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
变量转换可将变量的值格式化处理后插入预定的位置。 它包括三个部分:

  1. 正则表达式
  2. 格式字符串
  3. 正则表达式匹配选项

正则表达式和正则表达式匹配选项不作解释。

格式字符串在官方文档的Grammar中如下

format      ::= '$' int | '${' int '}'
                | '${' int ':' '/upcase' | '/downcase' | '/capitalize' '}'
                | '${' int ':+' if '}'
                | '${' int ':?' if ':' else '}'
                | '${' int ':-' else '}' | '${' int ':' else '}'

假设某整体片段为${variable/regexp/(format|text)/options},再结合上述语法,
整体片段可变为

  1. ${var_name/regular_expression/$1/options}
  2. ${var_name/regular_expression/${1}/options}
  3. ${var_name/regular_expression/${1:/upcase}/options} // /downcase/capitalize使用方式同/upcase
  4. ${var_name/regular_expression/${1:+if}/options}
  5. ${var_name/regular_expression/${1:?if:else}/options}
  6. ${var_name/regular_expression/${1:-else}/options}
  7. ${var_name/regular_expression/${1:else}/options}
  8. ${var_name/regular_expression/text/options}

上述format$后的数字1表示分组捕获组(正则表达式中()匹配到的数组)的第1项,同理$2表示分组捕获项第2项。分组捕获相关信息详见分组捕获

现有文件名global-js.json,以demo说明上述片段含义。为了精简,输出值直接以body末尾注释表示,另外多个body直接放在一个snippet(实际操作不规范,仅仅为了精简)

注:使用transform末尾必须加/,才能被识别。如${TM_FILENAME_BASE/(global).*/$1/}


其中12意义相同

代码片段
"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
}

上述3、4两个示例匹配失败时,不做转换,即仍输出global.js

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
}

67,表示匹配成功,且分组捕获(正则表达式中()匹配到的项)成功时,不变;

匹配成功,且分组捕获为空时,将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
}

快捷键导入snippet

首先打开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`
  }
}

使用场景

  1. 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}\"}",
      "}"
    ]
  }
  1. 某些固定格式的数组对象

如某个数组长度较大的对象{title:'input',dataIndex:'input'},该数组中对象的每个titledataIndex不尽相同,则可以写个临时snippet,直接生成该结构。

"templates": {
    "prefix": "tem",
    "body": [",{dataIndex:$1,", "title:$2}"],
    "description": ""
}
  1. 某些固定内容的文件或者某些常用的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"
    ]
  },
  1. muji react 下的pages文件
"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说byebye

前言

新手或从其他语言转前端的同学刚接触js时,涉及到的数组循环一般都是for、while,以for居多。

内容

forEachmap

比如输入某个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新增的数组方法forEachmap也可以更优雅的实现

(返回新数组)

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);

someevery

或许有人会说forEach不能中断,达不到for循环中的break的效果

const a = [1,2,3];
for (let index = 0; index < a.length; index ++) {
	if (index === 1) {
	    break;
	}
	// do something
}

forEach确实不能,但是ES5新增的数组方法someevery都可以实现类似的效果。

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);

reducereduceRight

某些场景下可能需要对数组的每一项都进行某种操作。比如获取数组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

结尾

以上例子只是针对一些很简单的场景,复杂的场景就需要同学们举一反三了。希望对刚入坑的同学有所帮助。该文也是我在掘金的第一篇文章,由简入繁,希望在新的一年里自己能多总结多产出多分享。

Array | MDN

【node_modules】doc-scripts(1)

新鲜货(包相关)

  • lint-staged: 提交代码前执行相关'清洁'命令
  • chalk: 终端字符串样式
  • commander: node.js命令行界面的完整解决方案
  • fs-extra: 添加了未包含在原生fs模块中的文件系统方法,并为fs方法添加了promise支持
  • node-notifier: 使用node.js发送通知,可跨平台。
  • cli-spinner: 为node命令行定制的加载器

未知小细节

不知道怎么跑,不想安装包到全局,先放弃。

来源

doc-scripts

【数据结构】Trie树

介绍

Trie树,即字典树,又称单词查找树或键树,是一种树形结构。

核心**

空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的

基本性质

  • 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
  • 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
  • 每个节点的所有子节点包含的字符都不相同。

应用

  1. 字符串检索 Trie.prototype.find
  2. 词频统计 Trie.prototype.findWordCount
  3. 字符串排序 Trie.prototype.sort
  4. 前缀匹配 Trie.prototype.findCommonPrefix

Upgrade Angular 12 to 13 - Compile error in mjs file

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"
}
}

High Vulnerability reported for supports-color-3.2.3

WhiteSourceBolt has generated a report for vulnerability supports-color-3.2.3. They have also mentioned the top fix for this issue as below

image
But we have already given the latest version 0.5.2 for fresh module in express.js

image
Also we are having the latest version of expression 4.17.1

Is vulnerability exists in fresh 0.5.2 itself?

image

【babel】@babel/preset-env

描述

配置@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。

选项

  • looseboolean类型,默认为false

loosetrue时,可生成更简单的es5代码。demo
loosefalse时,转换后的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导入到单个文件。

【npm】package.json详解

前言

今天开始啃库,过程中遇到的package.json属性逐一添加、解释。

属性

  1. name: 发布npm包必需存在name和version两个属性。这两个属性共同组成了npm模块的唯一标志。修改包内容的同时,应该修改version。

    命名规则:

    • name必须小于等于214个字节,包括前缀名称在内(如 xxx/xxxmodule)
    • name不能以._开头
    • 不能含有大写字母
    • 不能包含任何非URL安全字符

    一些技巧:

    • 不要使用与node核心模块相同的名称
    • 不要在name中加上“js”或“node”
    • name尽可能简短且语义化
    • 可以在https://www.npmjs.com/上查询name是否已被占用

    name可以选择以作用域为前缀,例如@myorg/mypackage

  2. version: version必须可以被node-semver模块解析

  3. description: 字符串描述,有助于人们发现你的包

  4. main: main属性指定了程序的主入口文件。意思是,如果你的模块被命名为foo,用户安装了这个模块并通过require("foo")来使用这个模块,那么require返回的内容就是main属性指定的文件中module.exports指向的对象。

    它应该指向模块根目录下的一个文件。对大对数模块而言,只有一个主入口文件才最有意义。

  5. scripts: scripts属性是一个对象,里边指定了项目的生命周期个各个环节需要执行的命令。key是生命周期中的事件,value是要执行的命令。

    详见npm-scripts

  6. 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的情况下启动!

  7. dependencies: 依赖关系在将包名称映射到版本范围的简单对象中指定。 版本范围是一个字符串,其中包含一个或多个以空格分隔的描述符。 也可以使用tarball或git URL识别依赖关系。

    请不要在依赖项对象中放置测试工具或转换器。

    有关指定版本范围的更多详细信息,请参阅semver

    • version 精确匹配版本
    • >version 必须大于某个版本
    • ≥version 大于等于
    • <version 小于
    • <=versionversion 小于
    • ~version "约等于",具体规则详见semver文档
    • ^version "兼容版本"具体规则详见semver文档
    • 1.2.x 1.2.0, 1.2.1, etc., but not 1.3.0
    • http://... 见下方的URLs
    • *匹配任意版本
    • "" 空字符,和*相同
    • version1 - version2 相当于 >=version1 <=version2.
    • range1 || range2 范围1和范围2满足任意一个都行
    • git... 见下方的Git URls
    • user/repo See 见下方的Github URls
    • tag 标记并发布为标记的特定版本,见npm-tag
    • path/path/path 见下方的Local Paths

    例如,这些都是合法的

     { "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"
       }
     }
    

    URLs

    在版本范围的地方可以写一个url指向一个压缩包,模块安装的时候会把这个压缩包下载下来安装到模块本地。

    Git URLs

    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
    

    GitHub URLs

    从版本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"
       }
     }
    

    Local Paths

    从版本2.0.0开始,您可以提供包含包的本地目录的路径。 可以使用以下任何形式使用npm install -Snpm install --save保存本地路径:

     ../foo/bar
     ~/foo/bar
     ./foo/bar
     /foo/bar
    

    package.json 生成的相对路径如下:

     {
       "name": "baz",
       "dependencies": {
         "bar": "file:../foo/bar"
       }
     }
    

    此功能有助于本地脱机开发和创建需要在不想访问外部服务器的情况下进行npm安装的测试,但在将包发布到公共注册表时不应使用此功能。

  8. 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),它也将运行此脚本,以便您可以轻松地进行测试。

  9. people fields:author, contributors

    author是一个people。 contributors是一群people(数组表示)。 people是具有name字段、可选的urlemail的对象,如下所示:

    {“name”:“Barney Rubble”
    ,“email”:“[email protected]”
    ,“url”:“http://barnyrubble.tumblr.com/”
    }
    

    或者您可以将所有内容缩短为单个字符串,npm将为您解析它:

    "Barney Rubble <[email protected]> (http://barnyrubble.tumblr.com/)"
    

    电子邮件和网址都是可选的。

    npm也可以为你的npm用户信息设置顶级maintainers字段。

  10. license: 您应该为您的包指定许可证,以便人们知道如何使用它,以及您对其进行的任何限制。

    如果您不希望授予他人在任何条款下使用私人或未发布的包裹的权利:

    { "license": "UNLICENSED" }
    

    也可以考虑设置private: true防止意外发布。

参考文档

https://docs.npmjs.com/files/package.json
npm package.json属性详解

【node_modules】摘要

概述

后续【node_modules】相关的文章,会记录相关库的核心代码、奇技淫巧以及对我自己而言的新知识点。package.json相关详见【npm】package.json详解,有关babel的详见【babel】。后续也许也会分离出别的知识点作为文章。

【Webpack】ContextReplacementPlugin

介绍

顾名思义,上下文替换插件。允许覆盖查找规则。

主要用于动态导入时,减小导入包的大小。如引入moment时,不做处理的话,默认会打包moment/locale下的所有语言环境。但是大多数情况下,只需要支持特定语言环境就OK了。

以下是限制模块使用的一个小例子:

new webpack.ContextReplacementPlugin(
  /moment[\/\\]locale$/,
  /de|fr|hu/
)

限定查找moment/locale上下文里符合/de|fr|hu/表达式的文件,因此也只会打包这几种本地化内容.

也可以用于重定向请求文件。

引用

ContextReplacementPlugin
Removing unused languages from dynamic import

【JS进阶向】从造数组数据说开去

前言

前后端合作刚开始开发某个项目时,后端api接口基本上是不能一蹴而就的。但是api接口返回的数据接口可以尽快定下来。而前端在制作功能页面时,经常需要数据才能处理的得心应手。而不管是用mock,还是临时变量赋值,都涉及到造数据。一般来说,数据类型以数组居多。接下来,就从造数组数据说开去。

内容

伪数组

数组最基本的特征是有length属性,有length属性的对象(非数组)称作伪数组。伪数组是不能够直接调用数组的方法的。不过以下两种方法可以将伪数组转为数组。

Array.prototype.slice.call();

const obj = {0:'a',1:'b',length:2}; // 伪数组
const arrLike = Array.prototype.slice.call(obj);  
console.log(arrLike);  // ["a","b"]

Array.from()

const obj = {0:'a',1:'b',length:2}; // 伪数组
const arrLike = Array.from(obj);
console.log(arrLike);   // ["a","b"]

生成可循环的长度为length的数组

可以通过以下3种方法生成可循环的长度为3的数组,结果都是在chrome打印的

Array(length).fill(undefined)

const arr = Array(3).fiil(undefined);
console.log(arr);   // [undefined, undefined, undefined]

Array.apply(null, Array(length)) === Array(...Array(length))

const arr = Array.apply(null, Array(3));
console.log(arr);   // [undefined, undefined, undefined]

Array.from({length})

const arr = Array.from({length: 3});
console.log(arr);   // [undefined, undefined, undefined]

empty?

那么有人可能会疑惑为什么不直接用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

还是会输出undefinedempty实际上并不存在,所以Array(...Array(3))输出[undefined, undefined, undefined]没毛病。

Array.from({length : 3})输出[undefined, undefined, undefined],也是以length为基准生成数组的,详见Array.from()

以上都清楚了以后,造数组数据不是信手拈来的事么。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.