Skip to content

JS库

链接: https://cloud.seatable.cn/dtable/external-links/59b453a8639945478de2/

husky

在 git commit 提交前,增加一个 pre-commit 的钩子,进行格式检测和单元测试

https://typicode.github.io/husky/get-started.html

npm install --save-dev husky

npx husky init

@babel/cli

babel 执行的命令行的 CLI

@babel/plugin-proposal-class-properties

Below is a class with four class properties which will be transformed. This https://babeljs.io/docs/en/babel-plugin-proposal-class-properties

@babel/plugin-proposal-export-default-from

Compile export default to ES2015 https://babeljs.io/docs/en/babel-plugin-proposal-export-default-from

@babel/plugin-proposal-export-namespace-from

Compile export namespace to ES2015 https://babeljs.io/docs/en/babel-plugin-proposal-export-namespace-from

@babel/plugin-proposal-object-rest-spread

Compile object rest and spread to ES5 https://babeljs.io/docs/en/babel-plugin-proposal-object-rest-spread

@babel/plugin-transform-member-expression-literals

Ensure that reserved words are quoted in property accesses https://babeljs.io/docs/en/babel-plugin-transform-member-expression-literals

@babel/plugin-transform-property-literals

Ensure that reserved words are quoted in object property keys https://babeljs.io/docs/en/babel-plugin-transform-property-literals

@babel/plugin-transform-runtime

Externalise references to helpers and builtins, automatically polyfilling your code without polluting globals https://babeljs.io/docs/en/babel-plugin-transform-runtime

@babel/preset-env

babel 预设编译后的JS代码的环境

@babel/preset-react

babel 编译 react 预设的库

@svgr/webpack

svg 文件loader https://www.npmjs.com/package/@svgr/webpack

@babel/core

babel 核心代码(编译es6) https://babeljs.io/docs/en/babel-core

@babel/node

babel-node 是一个 CLI,其工作方式与 Node.js CLI 完全相同,它的额外好处是在运行之前使用 Babel 预设和插件进行编译。 https://babeljs.io/docs/en/babel-node

@babel/plugin-transform-modules-commonjs

This plugin transforms ES2015 modules to CommonJS https://babeljs.io/docs/en/babel-plugin-transform-modules-commonjs

@babel/register

babel require hook https://www.npmjs.com/package/@babel/register

@babel/runtime

contains Babel modular runtime helpers and a version of regenerator-runtime https://babeljs.io/docs/en/babel-runtime

webpack-node-externals

babel-eslint

babel 代码规范检查 https://www.npmjs.com/package/eslint-plugin-babel

babel-jest

Babel jest plugin https://www.npmjs.com/package/babel-jest

babel-loader

This package allows transpiling JavaScript files using Babel and webpack. https://www.npmjs.com/package/babel-loader

babel-plugin-named-asset-import

babel 插件

babel-preset-react-app

This package includes the Babel preset used by Create React App. https://www.npmjs.com/package/babel-preset-react-app

case-sensitive-paths-webpack-plugin

这个 Webpack 插件强制所有必需模块的整个路径与磁盘上实际路径的确切大小写匹配。 使用此插件有助于缓解在 OSX 上工作的开发人员(不遵循严格的路径区分大小写)与其他开发人员或运行其他需要正确大小写路径的操作系统的构建框发生冲突的情况。 https://www.npmjs.com/package/case-sensitive-paths-webpack-plugin

css-loader

css 加载器

enzyme

Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components' output.

enzyme-adapter-react-

对 react 功能组件测试

Enzyme is a JavaScript Testing utility for React that makes it easier to test your React Components' output. You can also manipulate, traverse, and in some ways simulate runtime given the output.

eslint

代码格式检查

eslint-config-react-app

eslint 针对 react 的插件

eslint-loader

eslint 加载器

eslint-plugin-flowtype

ESLint 的流类型 linting 规则。

eslint-plugin-import

该插件旨在支持 ES6+ 导入/导出语法的 linting,并防止文件路径和导入名称拼写错误的问题

eslint-plugin-jsx-ay

用于 JSX 元素可访问性规则的静态 AST 检查器

eslint-plugin-react-hooks

This ESLint plugin enforces the Rules of Hooks. https://www.npmjs.com/package/eslint-plugin-react-hooks

html-webpack-plugin-beta

简化创建 HTML 文件以服务于打包的插件 https://www.npmjs.com/package/html-webpack-plugin

identity-obj-proxy

使用 ES6 代理的身份对象。 用于测试简单的 webpack 导入。 例如,您可以告诉 Jest 将此对象模拟为导入的 CSS 模块; 那么您在导入的样式对象上的所有 className 查找都将按原样返回。

jest-environment-jsdom-fourteen

jest 插件,可以在观察模式下,选择特定的单元测试执行,已经部署到个人项目中

jest-resolve

说明文档和 jest 在一个界面上

jest-watch-typeahead

Filter your tests by file name or test name

less

less 样式 The dynamic stylesheet language.

less-loader

less 加载器

mini-css-extract-plugin

css 按需加载(把CSS提取到不同的JS文件中)

optimize-css-assets-webpack-plugin

A Webpack plugin to optimize minimize CSS assets.

pnp-webpack-plugin

Webpack 的即插即用解析器

postcss-flexbugs-fixes

PostCSS plugin This project tries to fix all of flexbug's issues.

postcss-loader

postcss 加载器

postcss-normalize

PostCSS Normalize lets you use the parts of normalize.css or sanitize.css that you need from your browsers list.

postcss-preset-env

CSS 兼容不用版本早期的浏览器。

PostCSS Preset Env lets you convert modern CSS into something most browsers can understand, determining the polyfills you need based on your targeted browsers or runtime environments.

postcss-safe-parser

PostCSS 的容错 CSS 解析器,它将发现和修复语法错误,能够解析任何输入。

sass-loader

sass 加载器

style-loader

样式加载器

terser-webpack-plugin

This plugin uses terser to minify your JavaScript. 压缩JS https://www.npmjs.com/package/terser-webpack-plugin

webpack

webpack 打包工具

webpack-cli

webpack 命令行工具

webpack-dev-server

webpack 开发环境打包服务器

webpack-manifest-plugin

生成资源清单

module.exports = {
  plugins: [
    new ManifestPlugin()
  ]
}

workbox-webpack-plugin

https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin

eslint-plugin-react

React specific linting rules for ESLint

file-loader

The file-loader resolves import/require() on a file into a url and emits the file into the output directory.

resolve-url-loader

这个 webpack 加载器允许你拥有一个分布式的 SCSS 文件集,以及与这些 SCSS 文件共存的资源。

webpack-bundle-tracker

将有关 webpack 编译过程的一些统计信息,记录到文件中。(tracker 追踪者)

和 webpack nodejs 存在兼容性问题。

This project is compatible with NodeJS versions 16 and up.

⚠️ Starting on version 17, NodeJS uses OpenSSL v3 which has compatibility issues with Webpack\@4.

This isn't an issue for Webpack\@5

however if you're using Node >= 17 and Webpack\@4, to properly use this package you must ensure to set the NODE_OPTIONS=--openssl-legacy-provider environment variable.

官方案例

var path = require('path');
var BundleTracker = require('webpack-bundle-tracker');

module.exports = {
  context: __dirname,
  entry: {
    app: ['./app'],
  },
  output: {
    path: path.resolve('./assets/bundles/'),
    filename: '[name]-[hash].js',
    publicPath: 'http://localhost:3000/assets/bundles/',
  },

  // 设置统计文件的存储路径和文件名
  plugins: [
    new BundleTracker({
      path: path.join(__dirname, 'assets'),
      filename: 'webpack-stats.json',
    }),
  ],
};

实际项目使用,根据不同环境配置了不同的统计文件

  new webpackBundleTracker({
    filename: isEnvProduction ? './webpack-stats.pro.json' : './webpack-stats.dev.json',
    publicPath: isEnvProduction ? '' : paths.publicUrlOrPath
  }),

统计文件:webpack-stats.pro.json 提供了每一个资源文件的名称和路径,每一个 chunks 引用的资源(通常是 common + others)

{
  "status": "done",
  "assets": {
    "static/css/app.58d2e6dd.css": {
      "name": "static/css/app.58d2e6dd.css",
      "path": "/build/frontend/static/css/app.58d2e6dd.css"
    },
    "static/css/commons.d6c420b4.css": {
      "name": "static/css/commons.d6c420b4.css",
      "path": "/build/frontend/static/css/commons.d6c420b4.css"
    },
    "static/css/draft.299cd106.css": {
      "name": "static/css/draft.299cd106.css",
      "path": "/build/frontend/static/css/draft.299cd106.css"
    }
  },
  "chunks": {
    "app": [
      "static/js/runtime.e32c54a5.js",
      "static/css/commons.d6c420b4.css",
      "static/js/commons.e891325f.js",
      "static/css/app.58d2e6dd.css",
      "static/js/app.011a7734.js"
    ],
    "draft": [
      "static/js/runtime.e32c54a5.js",
      "static/css/commons.d6c420b4.css",
      "static/js/commons.e891325f.js",
      "static/css/draft.299cd106.css",
      "static/js/draft.e9f03bdc.js"
    ],
    "wiki": [
      "static/js/runtime.e32c54a5.js",
      "static/css/commons.d6c420b4.css",
      "static/js/commons.e891325f.js",
      "static/css/wiki.30e6b692.css",
      "static/js/wiki.41704f71.js"
    ],
    "wiki2": [
      "static/js/runtime.e32c54a5.js",
      "static/css/commons.d6c420b4.css",
      "static/js/commons.e891325f.js",
      "static/css/wiki2.89e72cc3.css",
      "static/js/wiki2.1aa50e13.js"
    ]
  }
}

babel-register

The require hook will bind itself to node's require and automatically compile files on the fly.

clean-webpack-plugin

A webpack plugin to remove/clean your build folder(s).

webpack-merge

webpack-merge - Merge designed for Webpack

grunt

https://github.com/gruntjs/grunt

grunt 是 js 的任务运行器,可以自动化执行压缩,打包,测试等。实际项目使用不多,了解即可。

Why use a task runner? In one word: automation. The less work you have to do when performing repetitive tasks like minification, compilation, unit testing, linting, etc, the easier your job becomes. After you've configured it through a Gruntfile, a task runner can do most of that mundane work for you—and your team—with basically zero effort.

类似 webpack,这里需要配置一个 Gruntfile.js 文件,然后运行进行编译打包

module.exports = function(grunt) {
  // 初始化配置
  grunt.initConfig({
    jshint: {
      files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
      options: {
        globals: {
          jQuery: true
        }
      }
    },
    watch: {
      files: ['<%= jshint.files %>'],
      tasks: ['jshint']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.registerTask('default', ['jshint']);
};

gulp

gulp 是一个前端构建工具,支持自动化和工作流

A toolkit to automate & enhance your workflow

Leverage gulp and the flexibility of JavaScript to automate slow, repetitive workflows and compose them into efficient build pipelines.

配置文件:gulpfile.js

const { series } = require('gulp');

// The `clean` function is not exported so it can be considered a private task.
// It can still be used within the `series()` composition.
function clean(cb) {
  // body omitted
  cb();
}

// The `build` function is exported so it is public and can be run with the `gulp` command.
// It can also be used within the `series()` composition.
function build(cb) {
  // body omitted
  cb();
}

exports.build = build;
exports.default = series(clean, build);

video.js

视频播放器

这个库比较大,打包压缩后也有 1mb

watermark-dom

https://www.npmjs.com/package/watermark-dom

watermark.js是一个给B/S网站系统加水印的插件,确保系统保密性,安全性,降低数据泄密风险。

@typescript-eslint/eslint-plugin

An ESLint plugin which provides lint rules for TypeScript codebases. https://www.npmjs.com/package/@typescript-eslint/eslint-plugin

@typescript-eslint/parser

An ESLint parser which leverages TypeScript ESTree to allow for ESLint to lint TypeScript source code. https://www.npmjs.com/package/@typescript-eslint/parser

connect-multiparty

上传文件的中间件

csv

nodeJS 中数据类型和 csv 转换器

CSV for Node.js and the web

version

6.3.9 

downloads

1,330,572

repository

github.com/adaltas/node-csv

homepage

csv.js.org

The csv project provides CSV generation, parsing, transformation and serialization for Node.js.

It has been tested and used by a large community over the years and should be considered reliable. It provides every option you would expect from an advanced CSV parser and stringifier.

This package exposes 4 packages:

  • csv-generate (GitHub), a flexible generator of CSV string and Javascript objects.

  • csv-parse (GitHub), a parser converting CSV text into arrays or objects.

  • csv-stringify (GitHub), a stringifier converting records into a CSV text.

  • stream-transform (GitHub), a transformation framework.

The full documentation for the current version is available here.

Usage

Installation command is npm install csv.

Each package is fully compatible with the Node.js stream 2 and 3 specifications. Also, a simple callback-based API is always provided for convenience.

Sample

This example uses the Stream API to create a processing pipeline.

    // Import the package
    import * as csv from '../lib/index.js';

    // Run the pipeline
    csv
    // Generate 20 records
      .generate({
        delimiter: '|',
        length: 20
      })
    // Transform CSV data into records
      .pipe(csv.parse({
        delimiter: '|'
      }))
    // Transform each value into uppercase
      .pipe(csv.transform((record) => {
        return record.map((value) => {
          return value.toUpperCase();
        });
      }))
    // Convert objects into a stream
      .pipe(csv.stringify({
        quoted: true
      }))
    // Print the CSV stream to stdout
      .pipe(process.stdout);

Development

This parent project doesn't have tests itself but instead delegates the tests to its child projects.

Read the documentation of the child projects for additional information.

  • Pavel Kolesnikov "ya-csv": http://github.com/koles/ya-csv

  • Chris Williams "node-csv": http://github.com/voodootikigod/node-csv

  • Mat Holt "PapaParse": https://github.com/mholt/PapaParse

date-format

nodeJS 日期对象转换成字符串

detect-character-encoding

Detect character encoding using ICU

etcd

分布式集群部署 etcd3

iconv-lite

字符串不同格式转码

version

0.6.3 

downloads

74,008,351

repository

github.com/ashtuchkin/iconv-lite

homepage

github.com/ashtuchkin/iconv-lite

iconv-lite: Pure JS character encoding conversion

  • No need for native code compilation. Quick to install, works on Windows and in sandboxed environments like Cloud9.

  • Used in popular projects like Express.js (body_parser), Grunt, Nodemailer, Yeoman and others.

  • Faster than node-iconv (see below for performance comparison).

  • Intuitive encode/decode API, including Streaming support.

  • In-browser usage via browserify or webpack (~180kb gzip compressed with Buffer shim included).

  • Typescript type definition file included.

  • React Native is supported (need to install stream module to enable Streaming API).

  • License: MIT.

Usage

Basic API
var iconv = require('iconv-lite');

// Convert from an encoded buffer to a js string.
str = iconv.decode(Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]), 'win1251');

// Convert from a js string to an encoded buffer.
buf = iconv.encode("Sample input string", 'win1251');

// Check if encoding is supported
iconv.encodingExists("us-ascii")
Streaming API
// Decode stream (from binary data stream to js strings)
http.createServer(function(req, res) {
    var converterStream = iconv.decodeStream('win1251');
    req.pipe(converterStream);

    converterStream.on('data', function(str) {
        console.log(str); // Do something with decoded strings, chunk-by-chunk.
    });
});

// Convert encoding streaming example
fs.createReadStream('file-in-win1251.txt')
    .pipe(iconv.decodeStream('win1251'))
    .pipe(iconv.encodeStream('ucs2'))
    .pipe(fs.createWriteStream('file-in-ucs2.txt'));

// Sugar: all encode/decode streams have .collect(cb) method to accumulate data.
http.createServer(function(req, res) {
    req.pipe(iconv.decodeStream('win1251')).collect(function(err, body) {
        assert(typeof body == 'string');
        console.log(body); // full request body string
    });
});

Supported encodings

  • All node.js native encodings: utf8, ucs2 / utf16-le, ascii, binary, base64, hex.

  • Additional unicode encodings: utf16, utf16-be, utf-7, utf-7-imap, utf32, utf32-le, and utf32-be.

  • All widespread singlebyte encodings: Windows 125x family, ISO-8859 family, IBM/DOS codepages, Macintosh family, KOI8 family, all others supported by iconv library. Aliases like 'latin1', 'us-ascii' also supported.

  • All widespread multibyte encodings: CP932, CP936, CP949, CP950, GB2312, GBK, GB18030, Big5, Shift_JIS, EUC-JP.

See all supported encodings on wiki.

Encoding/decoding speed

Comparison with node-iconv module (1000x256kb, on MacBook Pro, Core i5/2.6 GHz, Node v0.12.0). Note: your results may vary, so please always check on your hardware.

BOM handling

  • Decoding: BOM is stripped by default, unless overridden by passing stripBOM: false in options (f.ex. iconv.decode(buf, enc, {stripBOM: false})). A callback might also be given as a stripBOM parameter - it'll be called if BOM character was actually found.

  • If you want to detect UTF-8 BOM when decoding other encodings, use node-autodetect-decoder-stream module.

  • Encoding: No BOM added, unless overridden by addBOM: true option.

UTF-16 Encodings

This library supports UTF-16LE, UTF-16BE and UTF-16 encodings. First two are straightforward, but UTF-16 is trying to be smart about endianness in the following ways:

  • Decoding: uses BOM and 'spaces heuristic' to determine input endianness. Default is UTF-16LE, but can be overridden with defaultEncoding: 'utf-16be' option. Strips BOM unless stripBOM: false.

  • Encoding: uses UTF-16LE and writes BOM by default. Use addBOM: false to override.

UTF-32 Encodings

This library supports UTF-32LE, UTF-32BE and UTF-32 encodings. Like the UTF-16 encoding above, UTF-32 defaults to UTF-32LE, but uses BOM and 'spaces heuristics' to determine input endianness.

  • The default of UTF-32LE can be overridden with the defaultEncoding: 'utf-32be' option. Strips BOM unless stripBOM: false.

  • Encoding: uses UTF-32LE and writes BOM by default. Use addBOM: false to override. (defaultEncoding: 'utf-32be' can also be used here to change encoding.)

Other notes

When decoding, be sure to supply a Buffer to decode() method, otherwise badthings usually happen.

Untranslatable characters are set to � or ?. No transliteration is currentlysupported.

Node versions 0.10.31 and 0.11.13 are buggy, don't use them (see #65, #77).

jsonwebtoken

服务端 JWT 登录验证

request

http 网络请求工具

socket.io

socket 服务端程序

uuid

生成 UUID

form-data

A library to create readable "multipart/form-data" streams. Can be used to submit forms and file uploads to other web applications.

https://www.npmjs.com/package/form-data

jest

单元测试工具

https://www.npmjs.com/package/jest

🃏 Delightful JavaScript Testing

  • 👩🏻‍💻 Developer Ready : Complete and ready to set-up JavaScript testing solution. Works out of the box for any React project.

  • 🏃🏽 Instant Feedback : Failed tests run first. Fast interactive mode can switch between running all tests or only test files related to changed files.

  • 📸 Snapshot Testing : Jest can capture snapshots of React trees or other serializable values to simplify UI testing.

version

29.7.0 

downloads

23,497,819

repository

github.com/jestjs/jest

homepage

jestjs.io/

supertest

HTTP assertions made easy via superagent. npmjs.com/package/supertest

chartjs

chartjs

version

0.3.24 

downloads

10,662

repository

github.com/timer/chartjs

homepage

github.com/timer/chartjs#readme

Chart is a simple and functional charting library which currently supports bar charts. Implementations are done on-top of a HTML5 canvas element.

excalidraw

一个前端画图工具,效果不错,目前项目中使用

77K stars 周下载量 7万

https://docs.excalidraw.com/docs/@excalidraw/excalidraw/integration

https://www.npmjs.com/package/@excalidraw/excalidraw

https://github.com/excalidraw/excalidraw

import { Excalidraw } from "@excalidraw/excalidraw";

function App() {
  return (
    <>
      <h1 style={{ textAlign: "center" }}>Excalidraw Example</h1>
      <div style={{ height: "500px" }}>
        <Excalidraw />
      </div>
    </>
  );
}

undefined

sw-precache-webpack-plugin

SWPrecacheWebpackPlugin 是一个 webpack 插件,用于使用 service worker 缓存外部项目依赖项。 它将使用 sw-precache 生成一个 Service Worker 文件并将其添加到您的构建目录中。 https://www.npmjs.com/package/sw-precache-webpack-plugin

unified

AST 转换器

url-parse

Url 对象转换工具

vfile

解析序列化转换数据

@testing-library/user-event

以与用户相同的方式触发事件 https://www.npmjs.com/package/@testing-library/user-event

@reach/router

react-router 的增强版

resumablejs

大文件分块上传下载

chart.js

前端 canvas 绘图

classnames

组合 HTML 中的类名

周下载量 1000 万

const classNames = require('classnames');

classNames('foo', 'bar'); // => 'foo bar'

classNames('foo', { bar: true }); // => 'foo bar'

classNames({ 'foo-bar': true }); // => 'foo-bar'

classNames({ 'foo-bar': false }); // => ''

classNames({ foo: true }, { bar: true }); // => 'foo bar'

classNames({ foo: true, bar: true }); // => 'foo bar'

// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

copy-to-clipboard

复制内容到剪切板

https://www.npmjs.com/package/copy-to-clipboard

周下载量 500万

import copy from 'copy-to-clipboard';

copy('Text');

// Copy with options
copy('Text', {
  debug: true,
  message: 'Press #{key} to copy',
});

faker

模拟请求假数据

immutability-helper

react 中不可变元素复制的库

konva

canvas 在线图形编辑工具

MD5

生成字符串对应的 md5 加密结果

merge

合并对象(Object.assign)

moment

时间转换显示 时间处理

object-assign

兼容早期浏览器中的 Object.assign

prismjs

代码片段高亮

prop-types

类型验证(react)

resolve

实现节点 require.resolve() 算法,以便您可以异步和同步地代表文件 require.resolve() https://www.npmjs.com/package/resolve

semver

npm 的语义版本器 https://www.npmjs.com/package/semver

ts-pnp

https://www.npmjs.com/package/semver npm 的语义版本器

url-loader

loader for transforms files into base64 URIs. https://www.npmjs.com/package/url-loader

number-precision

小数精确计算

数字精确计算,大量使用有性能问题

https://www.npmjs.com/package/number-precision

周下载量 3W,星星 4K

import NP from 'number-precision'

NP.strip(0.09999999999999998); // = 0.1

NP.plus(0.1, 0.2);             // = 0.3, not 0.30000000000000004

NP.plus(2.3, 2.4);             // = 4.7, not 4.699999999999999

NP.minus(1.0, 0.9);            // = 0.1, not 0.09999999999999998

NP.times(3, 0.3);              // = 0.9, not 0.8999999999999999

NP.times(0.362, 100);          // = 36.2, not 36.199999999999996

NP.divide(1.21, 1.1);          // = 1.1, not 1.0999999999999999

NP.round(0.105, 2);            // = 0.11, not 0.1

slugid

生成 UUID

socket.io-client

websocket 客户端

@testing-library/jest-dom

您想使用 jest 编写测试来断言有关 DOM 状态的各种事情。 作为该目标的一部分,您希望避免这样做时出现的所有重复模式。 检查一个元素的属性,它的文本内容,它的 css 类,你可以命名它。 https://www.npmjs.com/package/@testing-library/jest-dom

reselect

基于 redux 的选择器组件

shallowequal

浅比较两个对象是否相等

whatwg-fetch

window.fetch 的便携版

lodash

JS 工具库

version

4.17.21 

downloads

52,325,095

repository

github.com/lodash/lodash

homepage

lodash.com/

The Lodash library exported as Node.js modules.

// Load the full build.
var _ = require('lodash');
// Load the core build.
var _ = require('lodash/core');
// Load the FP build for immutable auto-curried iteratee-first data-last methods.
var fp = require('lodash/fp');

// Load method categories.
var array = require('lodash/array');
var object = require('lodash/fp/object');

// Cherry-pick methods for smaller browserify/rollup/webpack bundles.
var at = require('lodash/at');
var curryN = require('lodash/fp/curryN');

See the package source for more details.

https://github.com/lodash/lodash/tree/4.17.21-npm

jszip

zip文件压缩编辑解压

A library for creating, reading and editing .zip files with JavaScript, with a lovely and simple API.

See https://stuk.github.io/jszip for all the documentation.

version

3.10.1 

downloads

7,880,597

repository

github.com/Stuk/jszip

homepage

github.com/Stuk/jszip#readme

const zip = new JSZip();

zip.file("Hello.txt", "Hello World\n");

const img = zip.folder("images");
img.file("smile.gif", imgData, {base64: true});

zip.generateAsync({type:"blob"}).then(function(content) {
  // see FileSaver.js
  saveAs(content, "example.zip");
});

/*
    Results in a zip containing
    Hello.txt
    images/
        smile.gif
    */

camelcase

Convert a dash/dot/underscore/space separated string to camelCase or PascalCase: foo-bar → fooBar

https://www.npmjs.com/package/camelcase

dotenv

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology. https://www.npmjs.com/package/dotenv

dotenv-expand

Dotenv-expand adds variable expansion on top of dotenv. If you find yourself needing to expand environment variables already existing on your machine, then dotenv-expand is your tool. https://www.npmjs.com/package/dotenv-expand

is-wsl

如果您需要解决 WSL 中未实现或有问题的功能,这会很有用。 支持 WSL 1 和 WSL 2。

https://www.npmjs.com/package/is-wsl

version

3.1.0 

downloads

38,383,822

repository

github.com/sindresorhus/is-wsl

homepage

github.com/sindresorhus/is-wsl#readme

Check if the process is running inside Windows Subsystem for Linux (Bash on Windows)

Can be useful if you need to work around unimplemented or buggy features in WSL. Supports both WSL 1 and WSL 2.

import isWsl from 'is-wsl';

// When running inside Windows Subsystem for Linux
console.log(isWsl);
//=> true

axios

发送请求,是 promise 的封装

deep-copy

深拷贝引用类型变量

version

1.4.2 

downloads

222,536

repository

github.com/simov/deep-copy

homepage

github.com/simov/deep-copy

var dcopy = require('deep-copy')

// deep copy object
var copy = dcopy({a: {b: [{c: 5}]}})

// deep copy array
var copy = dcopy([1, 2, {a: {b: 5}}])

dom-helpers

兼容 ie9 的 DOM 操作方法

glamor

css-in-js 直接在JS中写入css的样式

html2canvas

HTML 网页转换成截图

i18next

翻译

i18next-browser-languagedetector

翻译插件

i18next-xhr-backend

翻译(从后端获取数据)

is-hotkey

工具库,监听键盘事件,兼容不同操作系统

周下载量80万,广泛使用

https://www.npmjs.com/package/is-hotkey?activeTab=readme

import isHotkey from 'is-hotkey'

const isSaveHotkey = isHotkey('mod+s')

function onKeyDown(e) {
  if (isSaveHotkey(e)) {
    ...
  }
}

keymirror

创建键和值相等的对象

这个库是 10 年前写的,从 react 源码中拿出来的,https://www.npmjs.com/package/keymirror

周下载量 20 万,实际项目使用不多

lodash.throttle

lodash 的节流函数接口

promise

文件上传异步转换成同步操作

raf

动画效果

lerna.js

https://www.npmjs.com/package/lerna

主要功能:将多个依赖包完美的组合在一个引用中。Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.

实际项目中没有使用,了解即可

pdfjs 打印空白页的问题

项目中使用了 pdfjs 处理 PDF 文件预览和打印(火狐团队的第三方库)当 pdf 只有一张,谷歌浏览器打印会出现两章,第二页是空白的。

解决:page-break-after CSS 属性调整当前元素之后的分页符。把原来的 always 改成 auto 即可避免打印空白页。目前还没有测试到其他副作用。

.container {
    page-break-after: 'auto';
}

https://developer.mozilla.org/zh-CN/docs/Web/CSS/page-break-after

https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-inside

https://developer.mozilla.org/zh-CN/docs/Web/CSS/break-inside

debug

https://www.npmjs.com/package/debug

A tiny JavaScript debugging utility modelled after Node.js core's debugging technique. Works in Node.js and web browsers.

var debug = require('debug')('http');
var http = require('http');
var name = 'My App';

debug('booting %o', name);

http.createServer(function(req, res){
  debug(req.method + ' ' + req.url);
  res.end('hello\n');
}).listen(3000, function(){
  debug('listening');
});

// fake worker of some kind

require('./worker');

jison

jison:An API for creating parsers in JavaScript,语法解析器

https://www.npmjs.com/package/jison

这个库6年前写的,最近4年没有更新,周下载量8万

jison 是一个语法解析器,可以直接把 '1+ 2 + 3' 这样的字符串解析转换成数学结果返回 6,具体语法类似 Bison

本地环境基本使用

1 全局安装 `npm install jison -g` 安装成功后,全局环境可以使用 jison 这个指令

2 获取解析规则 jison 格式的文件(这里可以从官方下载 `git://github.com/zaach/jison.git/examples`,或者自己写这个规则,例如脚本解析器的内容比较简答,公式解析器内容就比较复杂,具体涉及编译原理,暂时不展开)下面是部分 jison 文件

/* eslint-disable */
/* lexical grammar */
%lex
%%
\s+                                                                                             {/* skip whitespace */}
and|AND                                                                                         {return '&';}

3 使用 jison 工具创建编译器 jison calculator.jison, 然后就在当前目录下面生成一个 `calculator.js` 的文件,对外会暴露一个 Parser 类

4 准备一个计算的字符串 `echo "1 + 2 + 3" > MichaelTest`,写入文件

5 使用解析器处理这个字符串,可以获取结果 node calculator.js MichaelTest

mockjs 模拟数据

可以用于前后端模拟数据进行调试

const Mock = require('mockjs');
const Random = Mock.Random;

const data = Mock.mock(
    {
        id: '',
        title: Random.cparagraph(1, 5),
        time: Random.datetime('yyyy-MM-dd'),
        author: Random.cname(),
    }
);

guppy

一个项目管理工具,可以可视化分析不同脚本运行情况

可视化查看第三方依赖的版本和更新情况

使用1K

Storybook

https://storybook.js.org/

帮助一个 UI 组件库用于演示如何使用的工具。最新版本是 8,项目中使用的版本是 7。

可能官方文档和现在的配置不一样 https://storybook.js.org/docs/get-started/react-vite

下面是项目的配置(7)

安装

    "@storybook/addon-actions": "7.6.17",
    "@storybook/addon-docs": "7.6.17",
    "@storybook/addon-essentials": "7.6.17",
    "@storybook/addon-interactions": "7.6.17",
    "@storybook/addon-knobs": "7.0.2",
    "@storybook/addon-links": "7.6.17",
    "@storybook/addon-onboarding": "1.0.11",
    "@storybook/blocks": "7.6.17",
    "@storybook/preset-create-react-app": "7.6.17",
    "@storybook/react": "7.6.17",
    "@storybook/react-webpack5": "7.6.17",
    "@storybook/test": "7.6.17",

配置

.storybook/main.js

module.exports = {
  stories: ['../stories/**/*.stories.js'],
  staticDirs: ['../public'],
  // 插件
  addons: [
    '@storybook/addon-actions', 
    '@storybook/addon-links',
    '@storybook/addon-knobs',
    {
      name: '@storybook/addon-docs',
      options: {
        configureJSX: true,
      }
    }
  ],
  framework: {
    name: "@storybook/react-webpack5",
    options: {
      builder: {
        useSWC: true,
      },
    },
  }
};

.storybook/preview.js

import React from 'react';
import { Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks';

/** @type { import('@storybook/react').Preview } */
const preview = {
  parameters: {
    actions: { argTypesRegex: "^on[A-Z].*" },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
    options: {
      storySort: {
        method: '',
        order: [],
        locales: '',
      }
    },
    docs: {
      page: () => (
        <>
          <Title />
          <Subtitle />
          <Description />
          <Primary />
          <Controls />
        </>
      ),
    }
  },
};

export default preview;

开启服务

    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build -c .storybook -o docs",

使用 UI 组件

stories/components/cell-editor/text-editor.stories.js

import React from 'react';
import { action } from '@storybook/addon-actions';
import TextEditor from '../../../src/TextEditor';

const meta = {
  title: 'Editors/text-editor',
  component: TextEditor,
  tags: ['autodocs'],
  decorators: [
    (Story, context) => {
      return (
        <div>
          {context.parameters.title && <h1>{context.parameters.title}</h1>}
          {context.parameters.subTitle && <p className='storybook-sub'>{context.parameters.subTitle}</p>}
          <Story />
        </div>
      );
    }
  ],
  parameters: {
    title: '',
    subTitle: '',
  }
};

export default meta;

export const Demo1 = {
  args: {
    isReadOnly: false,
    value: value,
    column: column,
    onCommit: (updated) => { action('onCommit')(updated); },
  },
  parameters: {
    subTitle: ''
  }
};

printjs

https://printjs.crabbly.com/#documentation

https://github.com/crabbly/Print.js?tab=readme-ov-file

exif-js

https://www.npmjs.com/package/exif-js

从图片中提取 exif 信息(拍摄时间、拍摄位置等)

dotenv

https://www.npmjs.com/package/dotenv

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env.

可以把环境变量从 .env 文件中读出来,然后在代码中判断不同的环境,执行不同的逻辑。

S3_BUCKET="YOURS3BUCKET"

SECRET_KEY="YOURSECRETKEYGOESHERE"

在项目代码中

require('dotenv').config()

console.log(process.env)

GreaseMonkey

GreaseMonkey 油脂猴子,简称“油猴”,是一个浏览器插件,可以执行 JS 脚本。它们可以实现诸如自动化操作、改善用户界面、绕过限制等多种功能。

百度链接:https://baike.baidu.com/item/Greasemonkey/10727057

教程链接:

https://blog.csdn.net/qq_21561501/article/details/102696669

https://blog.csdn.net/jayandchuxu/article/details/79113755

https://blog.csdn.net/wujiayu31415/article/details/136191014

https://zhuanlan.zhihu.com/p/667584378

不同浏览器插件名称不一样,例如 Chrome ViolentMonkey 暴力猴

一个开源的用户脚本管理器,支持很多浏览器

Violentmonkey provides userscripts support for browsers. It works on browsers with WebExtensions support. It supports most scripts for Greasemonkey and Tampermonkey. Features: - Update automatically according to the meta data. - Scripts will be executed in order as shown in the list. - GM functions are supported. - Support import from and export to a zip file. - Sync to Dropbox, OneDrive, Google Drive and WebDAV!

这里提供了很多网站的功能(下载视频,复制粘贴等)例如 https://greasyfork.org/en/scripts/438182-seatable-custom-style-online

antd-mobile

阿里出品的移动端 UI 组件库

https://www.npmjs.com/package/antd-mobile

https://github.com/ant-design/ant-design-mobile

周下载量 2万,国内使用广泛

主要组件和案例(待完善)

<ActionSheet />
<Button />

个人案例演示:https://michael18811380328.github.io/react-demos/antd/

个人案例源码:https://github.com/Michael18811380328/react-demos/blob/master/src/routes/29-antd.jsx

注意版本升级后的 css 自定义:https://stackoverflow.com/questions/74529378/antd-5-module-not-found-error-cant-resolve-antd-dist-antd-less/74529656#74529656

autoprefixer

自动增加 css 前缀,兼容不同版本浏览器

fs-extra

fs 的高级版本

https://www.npmjs.com/package/fs-extra

express

中间层服务器

express-rate-limit

请求次数限制

response-time

HTTP 响应时间 nodejs 和 express 联合使用

rimraf

The UNIX command rm -rf for node. https://www.npmjs.com/package/rimraf

sharp

https://www.npmjs.com/package/sharp

nodejs 中图片工具库,可以生成图片(批量生成随机图片),或者图片格式转换等等

除了调整图像大小外,还可以进行旋转、提取、合成和伽玛校正等操作。

// 下面是批量生成随机图片的案例
// npm install sharp
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');
const util = require('util');

const mkdir = util.promisify(fs.mkdir);
const writeFile = util.promisify(fs.writeFile);

const IMAGE_WIDTH = 800; // 图片宽度
const IMAGE_HEIGHT = 600; // 图片高度
const IMAGE_COUNT = 1000; // 图片数量
const OUTPUT_DIR = 'random_images'; // 输出目录

async function createRandomImage(filename) {
  const red = Math.floor(Math.random() * 256);
  const green = Math.floor(Math.random() * 256);
  const blue = Math.floor(Math.random() * 256);

  const image = await sharp({
    create: {
      width: IMAGE_WIDTH,
      height: IMAGE_HEIGHT,
      channels: 4,
      background: { r: red, g: green, b: blue, alpha: 255 }
    }
  });

  await image.toFile(filename);
}

async function main() {
  try {
    await mkdir(OUTPUT_DIR, { recursive: true });

    for (let i = 0; i < IMAGE_COUNT; i++) {
      const filename = path.join(OUTPUT_DIR, `${i}.png`);
      await createRandomImage(filename);
    }
  } catch (error) {
    console.error(error);
  }
}

main();

转换图片

const semiTransparentRedPng = await sharp({
  create: {
    width: 48,
    height: 48,
    channels: 4,
    background: { r: 255, g: 0, b: 0, alpha: 0.5 }
  }
})
  .png()
  .toBuffer();

cheerio

一个为服务器特别定制的,快速、灵活、实施的jQuery核心实现.

https://www.npmjs.com/package/cheerio

https://github.com/cheeriojs/cheerio

https://github.com/cheeriojs/cheerio/wiki/Chinese-README

28K stars 周下载量900万,看起来还是很火,已经发布 1.0 版本,很多项目使用

把HTML告诉你的服务器

const cheerio = require('cheerio');
const $ = cheerio.load('<h2 class="title">Hello world</h2>');

$('h2.title').text('Hello there!');
$('h2').addClass('welcome');

$.html();
//=> <html><head></head><body><h2 class="title welcome">Hello there!</h2></body></html>

jquery 比较重,cheerio实现了核心jQuery的子集。

cheerio会从jQuery库中删除所有DOM矛盾和浏览器的尴尬部分,展示她真正华丽的API。

中文教程:https://www.cheeriojs.cn/docs/intro

目前实际项目不会使用,看起来这个主要用于服务器向客户端返回内容使用,或者服务器转换 HTML 使用。

image-size

nodejs 模块,获取任何图片的尺寸

const sizeOf = require("image-size")
const dimensions = sizeOf("images/funny-cats.png")

console.log(dimensions.width, dimensions.height)

tesseract

Tesseract 是一款由 Google 开发的开源 OCR(光学字符识别)库。它可以识别图片中的文字,并将其转换为可编辑的文本格式。

如果您想要使用 Tesseract 识别图片并将输出重定向到另一个文件,您可以使用命令行界面来执行这个操作。基本的命令行示例,它演示了如何使用 Tesseract 识别图片并将结果保存到文本文件中:

tesseract input.png output -l eng --oem 3 --psm 3 && echo "OCR Completed."

tesseract 1.png output -l chi_sim --psm 6 && cat ./output.txt

在这个命令中:

  • input.png 是需要进行 OCR 处理的图片文件。

  • output 是输出文本文件的文件名,不需要带有 .txt 扩展名,Tesseract 会自动添加。

  • -l eng 指定使用英文训练数据。

  • --oem 3 启用老式布局分析模式(LSTM-only)。OEM:OCR Engine Mode:引擎模式,取值 0123。 0:3.x以前的识别引擎 1:神经网络LSTM的识别引擎 2:混合模式,传统+LSTM 3:默认,那种支持就用那种

  • --psm 3 设置页面分割模式,这里设置为只有文本。PSM:Page Segmentation Mode,对每页文档进行结构化分析,默认的PSM的选项参数位PSM_AUTO=3

参考:https://cloud.tencent.com/developer/article/2205370

如果您想将输出重定向到一个文件

tesseract input.png output -l eng --oem 3 --psm 3 > newfile.txt && echo "OCR Completed."

在这两个示例中,输出都会被重定向到指定的文件,而不是打印到控制台。如果您想同时将输出保存到文件并在控制台上查看,可以使用 tee 命令。

tesseract input.png output -l eng --oem 3 --psm 3 | tee output.txt && echo "OCR Completed."

请确保您的系统上安装了 Tesseract-OCR,并且可以通过命令行访问 tesseract 命令。

1、brew install

2、下载中文识别包 brew install tesseract-lang

其他参考:

https://blog.csdn.net/s_ongfei/article/details/136500069

https://blog.csdn.net/qq_39522120/article/details/135503159

本地测试可以这样弄,然后写一个 bash 脚本循环

tesseract input.png output -l chi_sim --psm 3

使用 Tesseract 进行前端 ORM

嵌入 React 应用中

"tesseract.js": "^5.1.0",
import { createWorker } from 'tesseract.js';

const URLS = [
  'https://cloud.seatable.cn/seafhttp/files/628ad059-0a07-4dc4-a675-7ae2a1f15d81/image-1720508732396.png',
];

export default function Contact() {

  (async () => {
    const worker = await createWorker('chi_sim');
    for (let i = 0; i < URLS.length; i++) {
      const URL = URLS[i];
      const ret = await worker.recognize(URL);
      console.log(i);
      console.log(ret.data.text.replace(/[\s]/ig, ''));
    }
    await worker.terminate();
  })();

  return (
    <div id="contact"></div>
  );
}

nodejs 脚本

import { createWorker } from 'tesseract.js';

const URLS = [
  'https://cloud.seatable.cn/seafhttp/files/628ad059-0a07-4dc4-a675-7ae2a1f15d81/image-1720508732396.png',
];

(async () => {
  const worker = await createWorker('chi_sim');
  for (let i = 0; i < URLS.length; i++) {
    const URL = URLS[i];
    const ret = await worker.recognize(URL);
    console.log(i);
    console.log(ret.data.text.replace(/[\s]/ig, ''));
  }
  await worker.terminate();
})();

nodejs 批量 OCR 结果

const fs = require('fs');
const { exec } = require('child_process');

// 批量 ORM 图片文件(默认图片,识别效率不太高)
var runNodes = async function(files, father_path) {
  for (let i = 0; i < files.length; i++) {
    const URL = father_path + '/' + files[i];
    const command = `tesseract ${URL} output -l chi_sim --oem 3 --psm 3 && cat output.txt > ${i}.md`
    await exec(command, (error, stdout, stderr) => {
      if (error) {
        console.error(`执行的错误: ${error}`);
        return;
      }
      console.log(`stdout: ${stdout}`);
      if (stderr) {
        console.error(`stderr: ${stderr}`);
      }
    });
  }
}

const path = './images';

// check path valid (user input path may not valid)
if (!fs.existsSync(path)) {
  console.log(`${path} is invalid`);
  return;
}

var files = fs.readdirSync(path);

runNodes(files, path);

python 脚本

import pytesseract
from pathlib import Path
from PIL import Image

def ocr(filename):
    pth = Path(filename)
    image = Image.open(filename)

    # 图片二值化
    image = image.convert('L')
    # 可以定义阈值
    threshold = 200
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)
    # 识别图片
    curdir = pth.parent

    tessdata_dir_config = f'--tessdata-dir "{curdir}"'
    content = pytesseract.image_to_string(
        image, lang='chi_sim', config=tessdata_dir_config,)  # 使用简体中文解析图片
    print(content)

ocr('/root/dev/gotoolkits/figures/python-ocr-02.png')

问题和不足

如果识别清晰的截图,准确率能到 100%

如果截图中有其他的画笔颜色,或者图形比较多,那么准确率不太高,这种还需要手动处理

@antv/g2

链接

https://github.com/antvis/g2

项目介绍

数据驱动的高交互可视化图形语法 AntV - G2

G2 是一套基于可视化编码的图形语法,以数据驱动,具有高度的易用性和扩展性,用户无需关注各种繁琐的实现细节,一条语句即可构建出各种各样的可交互的统计图表。

同时,G2 也是 AntV 最重要的组成,始于《The Grammar of Graphics》一书描述的视觉编码语法系统(这也是 G2 项目命名的由来)。

星标

12K

Fusion Design

项目介绍

一套企业级中后台UI的解决方案,致力于解决设计师与前端在工作协同、产品体验一致性、开发效率方面的问题

你可以通过一站式协作平台灵活地定制自己的 DesignSystem,生成设计物料与代码分片到设计师的工具端 FusionCool 及开发者的工具端 Iceworks,同时保证代码和视觉稿之间的一致性

Fusion Design 是一种旨在提升设计与开发之间 UI 构建效率的工作方式。通过建设基于 DPL 模式的,设计、前端之间的标准协议与工作流,来快速构建符合业务诉求的 DPL,提升 DPL 的构建效率和应用效率,帮助业务快速实现 UI 构建。

npm 链接 github 链接 github 星标 使用建议
https://fusion.design/pc/?themeid=4 https://github.com/alibaba-fusion/next 4.6K 一般

使用案例

https://fusion.design/pc/doc/design/%E8%AE%BE%E8%AE%A1%E6%A6%82%E8%A7%88/11?themeid=2

痛点

适合alibaba内部使用,不适合小团队使用,有一定学习成本。在浏览器端进行编辑工作流等,和传统 APP 使用流畅度有区别。

zepto

zepto.js 是 jquery 在移动端的库,实际上 jquery 基本不使用了,zepto 也没有必要使用了,下面供参考:

zepto 源码注释 还是2013年的

使用 zeptojs 内嵌到 android webview 影响正常滚动时

https://github.com/madrobby/zepto/blob/master/src/touch.js 去掉 61 行,其实就是使用原生的滚动

babel

把ES6转换成ES5必备的工具

babel-plugin-rawest

  • React 的 DOM 直出方案。

babel-plugin-macros

  • 前端文件写 node 逻辑。

babel-plugin-dynamic-import-node

有些场景下会需要禁用 import() 语法。

babel-plugin-react-require

  • 自动为 jsx 语法加 react 引用。

babel-plugin-react-remove-prop-types

  • 删除 prop-types,生产环境用。

docz

文档

emotion

css modules

webrtc

移动端调用摄像头扫码

统计信息:字数 4653 阅读10分钟

基本技术和概念

webrtc

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。

扫码:使用 webRTC 技术,通过浏览器打开移动端的摄像头,进行扫码,并将扫码结果返回到 JS 中。

视频通话:使用 web-socket 技术和 webRTC 技术,实现视频通话。

本文档使用第一种功能,前端在移动端实现扫码功能。

webrtc-adapter

第三方库 webrtc-adapter 是一个垫片,用于处理浏览器 webRTC 兼容性。

WebRTC adapter https://www.npmjs.com/package/webrtc-adapter

只需要引入这个库,不需要其他的操作,No further action is required.

import adapter from 'webrtc-adapter';

ZXing

ZXing(“斑马线”)是1D/2D条形码图像处理库: https://github.com/zxing-js/library,官方案例是 TS 的

案例见两个 html,qr-camera.html 可以完整使用, bar-image.html 缺少图片

React 具体实现

import React from 'react';
import 'webrtc-adapter';
import { BrowserMultiFormatReader } from '@zxing/library';
import { Modal } from 'antd-mobile';
export default class Camera extends React.Component {
  constructor(props) {
    super(props);
    this.codeReader = new BrowserMultiFormatReader();
  }
  componentDidMount() {
    this.initCamera();
  }
  initCamera = () => {
    this.codeReader.listVideoInputDevices().then((videoInputDevices) => {
      // 这里使用默认的摄像头 undefined
      this.codeReader.decodeFromVideoDevice(undefined, 'video', (result, err) => {
        // 给扫描对象增加动画效果
        if (!this.scanRef.style.animation) {
          this.scanRef.style.animation = 'scanCode 3s linear infinite';
        }
        // 有结果后,把扫码的结果通过回调函数返回
        if (result) {
          this.props.changeInputValue(result.text);
        }
      });
    }).catch(() => {
      console.log('Failed to turn on camera');
    });
  }
  onCloseCamera = () => {
    this.codeReader.reset();
  }
  render() {
    return(
      <Modal
        onClose={this.props.onClose}
        transparent
        visible={true}
        className="mobile-custom-camera"
      >
        <div className="custom-scan-container">
          {/* 上面显示当前的视频效果,并进行扫码 */}
          <video
            id="video"
            width="300"
            height="200"
          ></video>
          {/* 下面是一个用于扫码的动画效果,一个线上下移动 */}
          <div className="custom-camera-line" ref={ref => this.scanRef = ref}></div>
        </div>
      </Modal>
    );
  }
}

对应的 CSS

.camera-auto-fill-value {
  position: absolute;
  top: 9px;
  right: 6px;
  cursor: pointer;
  color: #999;
  background: #fff;
  display: flex;
  justify-content: center;
  width: 24px;
  height: 24px;
}
.mobile-custom-camera {
  width: 310px;
}
.mobile-custom-camera .am-modal-content {
  padding-top: 0;
  width: 310px;
}
.mobile-custom-camera .am-modal-content .am-modal-body {
  padding: 0;
  line-height: 1;
  height: 210px;
  overflow: hidden;
}
.mobile-custom-camera .custom-scan-container {
  height: 210px;
  width: 310px;
  background: linear-gradient(#ddd, #ddd) left top,
    linear-gradient(#ddd, #ddd) left top,
    linear-gradient(#ddd, #ddd) right top,
    linear-gradient(#ddd, #ddd) right top,
    linear-gradient(#ddd, #ddd) right bottom,
    linear-gradient(#ddd, #ddd) right bottom,
    linear-gradient(#ddd, #ddd) left bottom,
    linear-gradient(#ddd, #ddd) left bottom;
  background-color: rgba(0,0,0,.4);
  background-repeat: no-repeat;
  background-size: 5px 50px, 50px 5px;
}
.mobile-custom-camera .custom-scan-container>video {
  background: #fff;
  margin-top: 5px;
  object-fit: fill;
}
/* 这是动画线段的样式 */
.mobile-custom-camera .custom-camera-line {
  position: absolute;
  width: 80%;
  left: 10%;
  border: 1px solid #ddd;
  top: -2px;
}
@keyframes scanCode {
  from {
    top: 0;
  }
  to {
    top: 200px;
  }
}

参考链接

Vue 移动端实现调用相机扫描二维码 https://blog.csdn.net/weixin_41856395/article/details/120597131

WebRTC 从实战到未来 https://juejin.cn/post/7151932832041058340

官方案例

qr-camera.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="author" content="ZXing for JS">

  <title>官方案例 |ZXing TypeScript | Decoding from camera stream</title>

  <!-- 引入线上样式库 -->
  <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
  <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://unpkg.com/normalize.css@8.0.0/normalize.css">
  <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null" href="https://unpkg.com/milligram@1.3.0/dist/milligram.min.css">

</head>

<body>

  <main class="wrapper" style="padding-top:2em">

    <section class="container" id="demo-content">
      <h1 class="title">Scan QR Code from Video Camera</h1>

      <p>This example shows how to scan a QR code with ZXing javascript library from the device video camera. If more
        than one video input devices are available (for example front and back camera) the example shows how to read
        them and use a select to change the input device.</p>

      <p>此示例显示如何使用ZXing javascript库从设备摄像机扫描二维码。如果有多个视频输入设备可用(例如前置和后置摄像头),该示例将显示如何读取它们并使用选择来更改输入设备。</p>

      <!-- 点击按钮,开始或者重置 -->
      <div>
        <a class="button" id="startButton">Start</a>
        <a class="button" id="resetButton">Reset</a>
      </div>

      <!-- 这里显示视频 -->
      <div>
        <video id="video" width="300" height="200" style="border: 1px solid gray"></video>
      </div>

      <!-- 更改视频来源,如果有多个摄像头 -->
      <div id="sourceSelectPanel" style="display:none">
        <label for="sourceSelect">Change video source 更改视频源</label>
        <select id="sourceSelect" style="max-width:400px">
        </select>
      </div>

      <div style="display: table">
        <label for="decoding-style"> Decoding Style 解码样式</label>
        <select id="decoding-style" size="1">
          <option value="once">Decode once 解码一次</option>
          <option value="continuously">Decode continuously 连续解码</option>
        </select>
      </div>

      <label>Result:</label>
      <pre>
        <code id="result"></code>
      </pre>

      <p>See the <a href="https://github.com/zxing-js/library/tree/master/docs/examples/qr-camera/">source code</a> for
        this example.</p>
    </section>

    <footer class="footer">
      <section class="container">
        <p>ZXing TypeScript Demo.</p>
      </section>
    </footer>

  </main>

  <script type="text/javascript" src="https://unpkg.com/@zxing/library@latest"></script>
  <script type="text/javascript">

    // 解码一次
    function decodeOnce(codeReader, selectedDeviceId) {
      codeReader.decodeFromInputVideoDevice(selectedDeviceId, 'video').then((result) => {
        console.log(result)
        // 捕获到视频中的二维码,解析后返回字符串,例如微信个人名片:https://u.wechat.com/EG_lz_oLmz6PHpvOemd5XMw
        document.getElementById('result').textContent = result.text
      }).catch((err) => {
        console.error(err)
        document.getElementById('result').textContent = err
      })
    }

    // 连续解码
    function decodeContinuously(codeReader, selectedDeviceId) {

      codeReader.decodeFromInputVideoDeviceContinuously(selectedDeviceId, 'video', (result, err) => {

        if (result) {
          // properly decoded qr code 正确解码的二维码
          console.log('Found QR code!', result)
          document.getElementById('result').textContent = result.text
        }
        if (err) {
          // As long as this error belongs into one of the following categories
          // the code reader is going to continue as excepted. Any other error
          // will stop the decoding loop.
          //
          // Excepted Exceptions:
          //  - NotFoundException
          //  - ChecksumException
          //  - FormatException
          if (err instanceof ZXing.NotFoundException) {
            console.log('No QR code found.')
          }
          if (err instanceof ZXing.ChecksumException) {
            console.log('A code was found, but it\'s read value was not valid.')
          }
          if (err instanceof ZXing.FormatException) {
            console.log('A code was found, but it was in a invalid format.')
          }
        }
      })
    }

    window.addEventListener('load', function () {

      // 设置变量保存选中摄像头
      let selectedDeviceId;

      // 初始化对象
      const codeReader = new ZXing.BrowserQRCodeReader()
      console.log('ZXing code reader initialized')

      // 先获取输入设备的信息
      codeReader.getVideoInputDevices()
        .then((videoInputDevices) => {

          // 获取当前设备的摄像头个数 videoInputDevices
          const sourceSelect = document.getElementById('sourceSelect')
          // 默认第一个是选中的设别ID
          selectedDeviceId = videoInputDevices[0].deviceId

          // 如果有多个摄像头
          if (videoInputDevices.length >= 1) {
            videoInputDevices.forEach((element) => {
              const sourceOption = document.createElement('option')
              sourceOption.text = element.label
              sourceOption.value = element.deviceId
              sourceSelect.appendChild(sourceOption)
            })

            sourceSelect.onchange = () => {
              selectedDeviceId = sourceSelect.value;
            };

            const sourceSelectPanel = document.getElementById('sourceSelectPanel')
            sourceSelectPanel.style.display = 'block'
          }

          // 点击开始按钮的回调函数
          document.getElementById('startButton').addEventListener('click', () => {
            // 获取渲染的次数,然后执行对应的函数
            const decodingStyle = document.getElementById('decoding-style').value;
            if (decodingStyle == "once") {
              decodeOnce(codeReader, selectedDeviceId);
            } else {
              decodeContinuously(codeReader, selectedDeviceId);
            }
            console.log(`Started decode from camera with id ${selectedDeviceId}`)
          })

          // 点击重置按钮的回调函数
          document.getElementById('resetButton').addEventListener('click', () => {
            // 重置对象
            codeReader.reset()
            document.getElementById('result').textContent = '';
            console.log('Reset.')
          })

        })
        .catch((err) => {
          // 本地使用 http-server 测试时,使用 http 协议,移动端报错 Can't enumerate devices, method not supported. 无法枚举设备,不支持方法。
          // https://stackoverflow.com/questions/63833315/zebra-crossing-javascript-not-detecting-devices
          // It turns out, the script requires a browser SSL connection. Not just on the JS, but the enveloping page as well.
          // 解决方法
          // 首先使用以下命令生成一个证书 ** 对 key.pem 和 cert.pem,它将有效期约10年(准确地说是3650天)
          // openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
          // # 然后便可以起服务了 下面两个命令都可以,后者会自动打开默认浏览器运行页面
          // http-server -S
          // http-server -S -C cert.pem -o
          // 本机直接使用 http-server 即可启动服务
          alert(err)
        })
    })
  </script>

</body>

</html>

bar-image.html

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="author" content="ZXing for JS">

  <title>ZXing TypeScript | Decoding Barcode from images</title>

  <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
    href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">
  <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
    href="https://unpkg.com/normalize.css@8.0.0/normalize.css">
  <link rel="stylesheet" rel="preload" as="style" onload="this.rel='stylesheet';this.onload=null"
    href="https://unpkg.com/milligram@1.3.0/dist/milligram.min.css">
</head>

<body>

  <main class="wrapper" style="padding-top:2em">

    <section class="container" id="demo-content">
      <h1 class="title">Scan barcode from <code>&lt;img&gt;</code></h1>

      <p>
        <a class="button-small button-outline" href="../../index.html">HOME 🏡</a>
      </p>

      <p>
        These examples show how to scan a barcode with ZXing javascript library from an image. The examples decode from
        the
        <code>src</code> in
        <code>img</code> tag, however is also possible to decode directly from an url without an
        <code>img</code> tag.
      </p>

      <div id="code-128">
        <h2 class="title">Scan barcode from Code 128</h2>
        <div>
          <a class="button decodeButton">Decode</a>
        </div>
        <div>
          <img class="img" src="../../resources/blackbox/code128-1/1.png" style="border: 1px solid gray" />
        </div>
        <label>Result:</label>
        <blockquote>
          <p class="result"></p>
        </blockquote>
      </div>

      <br />
      <br />

      <div id="ean-13">
        <h2 class="title">Scan barcode from EAN-13</h2>
        <div>
          <a class="button decodeButton">Decode</a>
        </div>
        <div>
          <img class="img" src="../../resources/blackbox/ean13-1/1.png" style="border: 1px solid gray" />
        </div>
        <label>Result:</label>
        <blockquote>
          <p class="result"></p>
        </blockquote>
      </div>

      <br />
      <br />

      <div id="itf">
        <h2 class="title">Scan barcode from ITF</h2>
        <div>
          <a class="button decodeButton">Decode</a>
        </div>
        <div>
          <img class="img" src="../../resources/blackbox/itf/1.png" style="border: 1px solid gray" />
        </div>
        <label>Result:</label>
        <blockquote>
          <p class="result"></p>
        </blockquote>
      </div>

      <p>
        See the
        <a href="https://github.com/zxing-js/library/tree/master/docs/examples/barcode-image/">source code</a>
        for these examples.
      </p>

    </section>

    <footer class="footer">
      <section class="container">
        <p>ZXing TypeScript Demo. Licensed under the <a target="_blank"
            href="https://github.com/zxing-js/library#license" title="MIT">MIT</a>.</p>
      </section>
    </footer>

  </main>

  <script type="text/javascript" src="https://unpkg.com/@zxing/library@latest"></script>
  <script type="text/javascript">
    window.addEventListener('load', () => {

      const codeReader = new ZXing.BrowserBarcodeReader();

      console.log('ZXing code reader initialized');

      const decodeFun = (e) => {

        const parent = e.target.parentNode.parentNode;
        const img = parent.getElementsByClassName('img')[0].cloneNode(true);
        const resultEl = parent.getElementsByClassName('result')[0];

        codeReader.decodeFromImage(img)
          .then(result => {
            console.log(result);
            resultEl.textContent = result.text;
          })
          .catch(err => {
            console.error(err);
            resultEl.textContent = err;
          });

        console.log(`Started decode for image from ${img.src}`)
      };

      for (const element of document.getElementsByClassName('decodeButton')) {
        element.addEventListener('click', decodeFun, false);
      }
    })
  </script>

</body>

</html>

jsdoc

根据 js 代码自动写文档

An API documentation generator for JavaScript.

https://jsdoc.app/about-getting-started.html

https://github.com/photonstorm/phaser3-docs/blob/master/package.json

可以根据需求生成 md 或者 HTML 格式的文档等

"build": "./node_modules/.bin/jsdoc *.js",
"gen": "node --max_old_space_size=8192 node_modules/jsdoc/jsdoc.js -c jsdoc.conf.json -R ../phaser/README.md",
"json": "jsdoc -c jsdoc.data.json"

在源代码中增加注释(函数注释和类注释)

/**
 * check the param is an array
 * @param {array} arr - input parameter
 * @returns boolean
 */
const isArray = (arr) => {
  return Array.isArray(arr);
};

export { isArray };
import isArray from './utils';

/** This is a description of the foo function. */
function foo() {
}

/**
 * Represents a book.
 * @constructor
 */
function Article(title, author) {
  console.log(isArray(title));
  return title + author;
}

/**
 * Represents a book.
 * @constructor
 * @param {string} title - The title of the book.
 * @param {string} author - The author of the book.
 */
class Book {
  constructor(props) {
    this.title = props.title;
    this.author = props.author;
  }
  /**
   * say hi to someone
   * @param {string} name - The user name.
   */
  sayHi(name) {
    console.log('Hi ' + name);
  }
}

具体配置文件

{
  "tags": {
      "allowUnknownTags": true
  },
  "source": {
      "include": [
          "../phaser/src/",
          "../phaser/plugins/fbinstant"
      ],
      "exclude": [
          "../phaser/src/phaser-arcade-physics.js",
          "../phaser/src/phaser-core.js",
          "../phaser/src/physics/matter-js/poly-decomp/",
          "../phaser/src/physics/matter-js/lib",
          "../phaser/src/polyfills",
          "../phaser/src/phaser-ie9.js"
      ],
      "includePattern": ".+\\.js?$",
      "excludePattern": "(^|\\/|\\\\)_"
  },
  "plugins": [
      "jsdoc-plugins/typedef",
      "jsdoc-plugins/this"
  ],
  "opts": {
      "debug": false,
      "destination": "./json/phaser.json",
      "encoding": "utf8",
      "outputSourceFiles": false,
      "outputSourcePath": true,
      "recurse": true,
      "private": false,
      "lenient": true,
      "sourceType": "script",
      "template": "node_modules/jsdoc-json"
  }
}