构建NodeJS库--前端项目的打包发布

news2025/1/18 10:02:28

1. 前言

学习如何打包发布前端项目,需要学习以下相关知识:

  • package.json 如何初始化配置,以及学习npm配置项;
    • 模块类型type配置, 这是nodejs的package.json的配置
    • main 入口文件的配置
  • webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具,使用说明,推荐阅读;
  • babel-loader JavaScript通常需要做语法转化和polyfills以便可以使用高级语法而不必担心浏览器兼容性问题,Babel的作用便在于此,而babel-loader正好可以与webpack结合使用;
  • eslint 一个好的项目离不开代码格式规范;
  • jest 一款js测试框架,写好测试用例覆盖测试的功能点,确保软件质量,推荐阅读;

2. 概念区别

Node.js是JavaScript的一种运行环境,是对Google V8引擎进行的封装。是一个服务器端的JavaScript的解释器。npm(Node Package Manager)是nodejs的包管理器。

有一些概念容易混淆,注意区分。

2.1 CommonJS vs Es module

关于type的配置值有:

  • module 可以指示 Node.js 通过使用.cjs扩展名命名特定文件,将其解释为CommonJS
  • commonjs 可以通过使用.mjs扩展名命名特定文件,指示 Node.js 将其解释为 ES module

ps:js文件两种类型都能识别。

ES module 更加现代化和灵活,支持动态导入、异步加载、静态作用域等特性,

而 CommonJS 更加简单和适用于早期的 Node.js 环境。

在实际开发中,需要根据具体的项目需求和环境来选择使用哪种模块系统。

看到深入浅出 Commonjs 和 Es Module一文描述的很详细,感兴趣可以详细了解。

2.2 package.json入口mainmodulebrower

总结:其他项目引用时,会根据项目自身的type来选择定义的lib的入口文件,三个配置的主要区别在于优先级。

一般通常认为browser = browser+mjs > module > browser+cjs > main

推荐阅读入口文件配置的区别一文。

2.3 ES5 vs ES6

  • ES5指的是ECMScript的第五个版本,发布于2009年,是目前最广泛使用的JavaScript版本。
  • ES6是ECMScript的第六个版本,也成为ES2015,发布于2015年,引入了许多新的语言特性和语法糖。
  • ES2015是ES6的官方名称,但是由于ES6引入了太多的新特性,因此人们通常使用ES2015来指代ES6。

推荐阅读ES5和ES6的区别以及ES6常用特性

2.4 webpack config中的 output.library.type

官方使用说明中配置可选项很多,这里介绍:

  • commonjs
  • module
  • umd 统一模块定义,这种模块语法,兼容了以上的CommonJS、AMD、ES Module使用方式,也就是Vue脚手lib模式打包的这种模式,设置改值后,注意globalObject配置项可设置值为'this'

推荐阅读CommonJS/AMD/UMD/ES Module介绍和区别

3. 项目实战

源码:https://github.com/SkylerHu/js-enum

3.1 目录结构

在这里插入图片描述

3.2 主要配置文件

3.2.1 .babelrc

{
  "presets": [
    "@babel/preset-env"
  ],
  "plugins": [
    "@babel/plugin-proposal-class-properties"
  ]
}

3.2.2 .eslintignore

# node_modules
node_modules/

# build
build/

# dist
dist/
docs/

3.2.3 .estlintrc.json

{
  "env": {
    "browser": true,
    "es6": true,
    "mocha": true,
    "jest": true,
    "node": true
  },
  "globals": {
    "dashjs": true,
    "WebKitMediaSource": true,
    "MediaSource": true,
    "WebKitMediaKeys": true,
    "MSMediaKeys": true,
    "MediaKeys": true
  },
  "parser": "babel-eslint",
  "rules": {
    "no-caller": 2,
    "no-undef": 2,
    "no-unused-vars": 2,
    "no-use-before-define": 0,
    "object-curly-spacing": ["error", "always"],
    "strict": 0,
    "semi": 2,
    "no-loop-func": 0,
    "no-multi-spaces": "error",
    "keyword-spacing": [
      "error",
      {
        "before": true,
        "after": true
      }
    ],
    "quotes": [
      "error",
      "single",
      {
        "allowTemplateLiterals": true
      }
    ],
    "indent": [
      "error",
      2,
      {
        "SwitchCase": 1
      }
    ]
  },
  "ignorePatterns": ["releases/**/*"],
  "overrides": [
    {
      "files": ["tests/**/*"],
      "env": {
        "jest": true
      }
    }
  ]
}

3.2.3 jest.config.json

{
  "verbose": true,
  "collectCoverage": true,
  "coverageDirectory": "./.coverage",
  "moduleFileExtensions": [
    "js",
    "json"
  ],
  "testMatch": [
    "**/tests/**/*.js"
  ],
  "collectCoverageFrom": [
    "src/**/*.{js,jsx}",
    "!**/node_modules/**"
  ],
  "testEnvironment": "node"
}

3.2.2 package.json

{
  "author": "SkylerHu",
  "name": "js-enumerate",
  "version": "1.0.2",
  "private": false,
  "type": "module",
  "main": "dist/index.js",
  "files": [
    "dist"
  ],
  "publishConfig": {
    "access": "public",
    "registry": "https://registry.npmjs.org/"
  },
  "engines": {
    "node": "^14.21.3"
  },
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "build": "webpack --config webpack.config.js",
    "test": "jest"
  },
  "dependencies": {},
  "devDependencies": {
    "@babel/core": "^7.24.4",
    "@babel/plugin-proposal-class-properties": "^7.18.6",
    "@babel/preset-env": "^7.24.4",
    "@jest/globals": "^29.7.0",
    "babel-eslint": "^10.1.0",
    "babel-loader": "^9.1.3",
    "clean-webpack-plugin": "^4.0.0",
    "eslint": "7.32.0",
    "eslint-loader": "^4.0.2",
    "identity-obj-proxy": "^3.0.0",
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "webpack": "^5.91.0",
    "webpack-cli": "^5.1.4"
  },
  "description": "Enum is a javascript enumeration module. It works with Node.js and the browser.",
  "keywords": [
    "enum",
    "enumerate",
    "javascript",
    "js-enum",
    "js-enumerate",
    "react-enum",
    "vue-enum"
  ],
  "homepage": "https://github.com/SkylerHu/js-enum",
  "repository": {
    "type": "git",
    "url": "git@github.com:SkylerHu/js-enum.git"
  },
  "bugs": {
    "url": "https://github.com/SkylerHu/js-enum/issues"
  },
  "license": "MIT"
}

3.2.3 webpack.config.js

import path from 'path';
import { CleanWebpackPlugin } from 'clean-webpack-plugin';

import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';

const __dirname = dirname(fileURLToPath(import.meta.url));


const PATHS = {
  src: path.join(__dirname, 'src'),
  build: path.join(__dirname, 'dist'),
};

const config = {
  mode: 'production',
  // devtool: 'source-map',
  entry: path.join(PATHS.src, 'index.js'),
  output: {
    path: PATHS.build,
    clean: true,
    filename: 'index.js',
    library: {
      name: 'Enum',
      type: 'umd', // 采用通用模块定义
      export: 'default', // 兼容 ES6 的模块系统、CommonJS 和 AMD 模块规范
    },
    globalObject: 'this',
  },
  resolve: {
    extensions: ['.js', '.jsx', '.json'],
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/, //排除node_modules文件夹
        enforce: 'pre', //提前加载使用
        use: { //使用eslint-loader解析
          loader: 'eslint-loader'
        }
      },
      {
        // 使用 babel-loader 来编译处理 js 和 jsx 文件
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
  ],
  optimization: {
    minimize: true,
  },
};

export default config;

3.3 如何构建发版

  • 安装依赖npm install .
  • 代码格式npm run lint
  • 测试用例npm run test
  • 构建npm run build
  • 发版npm publish ,具体命令可以npm help查看,也可以查看官方文档
    • 需要在nodejs.org上注册账号,可以npm adduser通过命令行操作;
    • publish前需要npm login登录账号;
    • 也可以直接npmrc配置中配置好账号,或者创建auth_token配置

3.4 其他注意的问题

  • 3.4.1 jestwebpack版本对node版本的要求,node版本可以通过nvm控制;
> jest
./node_modules/jest/node_modules/jest-cli/build/run.js:135
    if (error?.stack) {
              ^
SyntaxError: Unexpected token '.'

升级node版本解决,该项目使用的node 14+

语法标准中,可选链运算符(?.) 要求node版本14+

  • 3.4.2 Babel编译缺少plugin
> jest

 FAIL  tests/test_enum.js
  ● Test suite failed to run
    Jest encountered an unexpected token
    Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.

    ...

    Details:
    SyntaxError: ./src/index.js: Missing class properties transform.
       8 |
       9 | export default class Enum {
    > 10 |   #items = [];
         |   ^^^^^^^^^^^^
      11 |   #config = {};
      12 |   /**
      13 |    *

通过安装和配置@babel/plugin-proposal-class-properties解决,参考

  • 3.4.3 webpack配置output.type为umd时,注意配置globalObject: 'this'
file:///.../node_modules/js-enumerate/dist/index.js:1
ReferenceError: self is not defined
    at file:///Users/skyler/Documents/github/test/node_modules/js-enumerate/dist/index.js:1:190
    at ModuleJob.run (internal/modules/esm/module_job.js:183:25)
    at async Loader.import (internal/modules/esm/loader.js:178:24)
    at async Object.loadESM (internal/process/esm_loader.js:68:5)
    at async handleMainPromise (internal/modules/run_main.js:59:12)

报错参考typescript-webpack-library-generates-referenceerror-self-is-not-defined解决。

  • 3.4.4 当nodejs.org上仅publish一个版本,操作npm unpublish后,导致无法找寻项目名,24小时内无法再次publish
    • 具体阅读关于取消版本发布的说明;
npm ERR! code E403
npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/js-enumerate - js-enumerate cannot be republished until 24 hours have passed.
npm ERR! 403 In most cases, you or one of your dependencies are requesting
npm ERR! 403 a package version that is forbidden by your security policy.

npm ERR! A complete log of this run can be found in:
npm ERR!     ./.npm/_logs/2024-04-21T18_27_39_505Z-debug.log

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1628086.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

golang反射

go反射 反射基本介绍应用场景基本使用结构体注意练习最佳实践遍历结构体的方法,调用接头体的方法,获取结构体的标签 反射 基本介绍 反射可以在运行时动态获取变量的各种信息,比如变量的类型(type)、类别(kind)如果是结构体变量,…

Java应用开发必备:使用 easy-captcha 组件生成验证码的详细介绍

一、前言 最近系统开发在优化验证码的相关功能,第一反应就是有没有开源的第三方组件可以使用呢。 在一番寻觅以后,还真发现一个好用的第三方验证码组件Easy-captcha。Easy-captcha是一个开源的Java库,用于生成和验证验证码,它的…

RGB灯珠的控制-单片机通用模板

RGB灯珠的控制-单片机通用模板 一、RGB控制的原理二、RGB.c的实现三、RGB.h的实现四、color色彩空间变换以及控制渐变一、RGB控制的原理 ①通过IO发送脉冲识别0/1编码,组合24Bit的RGB数据,从而控制RGB;②每个RGB灯珠通过DIN、DOU进行级联起来;③通过HSV色彩转换成RGB从而控…

Tomcat架构设计精髓分析-Connector高内聚低耦合设计

优秀的模块化设计通常都会采用高内聚、低耦合 高内聚是指相关度比较高的功能要尽可能集中,不要分散。低耦合是指两个相关的模块要尽可能减少依赖的部分和降低依赖的程序,不要让两个模块产中强依赖。 Tomca连接器需要实现的功能: 监听网络端口 接受网络…

手撕netty源码(一)- NioEventLoopGroup

文章目录 前言一、NIO 与 netty二、NioEventLoopGroup 对象的创建过程2.1 创建流程图2.2 EventExecutorChooser 的创建 前言 processOn文档跳转 本文是手撕netty源码系列的开篇文章,会先介绍一下netty对NIO关键代码的封装位置,主要介绍 NioEventLoopGro…

使用PyCharm开发工具创建工程

一. 简介 前面文章实现了开发 python程序使用的 开发工具PyCharm,本文来学习使用 PyCharm开发工具创建一个 python工程。 二. 使用PyCharm开发工具创建工程 1. 首先,打开 PyCharm开发工具,打开 "New project" 选项: …

hive启动beeline报错

问题一在zpark启动集群报错 出现上面的问题执行以下代码 chmod 777 /opt/apps/hadoop-3.2.1/logs 问题二启动beeline报错 执行 cd /opt/apps/hadoop-3.2.1 bin/hadoop dfsadmin -safemode leave 问题三执行查询语句报错 执行 set hive.exec.mode.local.autotrue;

java接口加密解密

这里写目录标题 controller加解密工具类加密(本质是对ResponseBody加密)解密(本质是对RequestBody传参解密)注解 controller Controller public class PathVariableController {GetMapping(value "/test")ResponseBod…

Redis缓存问题:穿透,击穿,雪崩等

Redis缓存问题:穿透,击穿,雪崩等 在高并发场景下,数据库往往是最薄弱的环节,我们通常选择使用redis来进行缓存,以起到缓冲作用,来降低数据库的压力,但是一旦缓存出现问题,也会导致数据库瞬间压力过大甚至崩溃,从而导致整个系统崩溃.今天就聊聊常见的redis缓存问题. 缓存击穿 …

相关分析方法

目录 1.什么是相关分析方法 2.相关系数 3.常见的相关分析方法 3.1.皮尔逊相关系数 3.2.斯皮尔曼等级相关 ​​​​​​​3.3.肯德尔等级相关 ​​​​​​​3.4.其它 4.应用 5.注意事项 6.结语 1.什么是相关分析方法 相关分析是数据分析中的一种统计方法&#xff0c…

[C++基础学习]----02-C++运算符详解

前言 C中的运算符用于执行各种数学或逻辑运算。下面是一些常见的C运算符及其详细说明:下面详细解释一些常见的C运算符类型,包括其原理和使用方法。 正文 01-运算符简介 算术运算符: a、加法运算符():对两个…

RabbitMQ(高级)笔记

一、生产者可靠性 (1)生产者重连(不建议使用) logging:pattern:dateformat: MM-dd HH:mm:ss:SSSspring:rabbitmq:virtual-host: /hamllport: 5672host: 192.168.92.136username: hmallpassword: 123listener:simple:prefetch: 1c…

AWTK 开源串口屏开发(17) - 通过 MODBUS 访问数组数据

在 AWTK 串口屏中,内置了 MODBUS Client Channel 的模型,不用编写代码即可实现在 ListView 中显示数组数据。 MODBUS 协议一次只能读取 125 个 WORD,AWTK-MODBUS Client Channel 支持长数据,自动分成多个请求访问。 1. 功能 不用…

浏览器的同源策略与解决跨域

同源策略(协议、域名、端口) 同源策略(Same-Origin Policy)是一个在浏览器安全模型中被实施的重要安全机制。它是基于域名、协议和端口号的限制,用于防止不同源的网页间的恶意行为和信息泄露。 根据同源策略&#xf…

【Diffusion实战】训练一个diffusion模型生成蝴蝶图像(Pytorch代码详解)

上一篇Diffusion实战是确确实实一步一步走的公式,这回采用一个更方便的库:diffusers,来实现Diffusion模型训练。 Diffusion实战篇:   【Diffusion实战】训练一个diffusion模型生成S曲线(Pytorch代码详解)…

【Linux学习】​​学习Linux的准备工作和Linux的基本指令

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

并并并并·病查坤

P1、什么是并查集 引用自百度百科: 并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合…

【数据标注】使用LabelImg标注YOLO格式的数据(案例演示)

文章目录 LabelImg介绍LabelImg安装LabelImg界面标注常用的快捷键标注前的一些设置案例演示检查YOLO标签中的标注信息是否正确参考文章 LabelImg介绍 LabelImg是目标检测数据标注工具,可以标注两种格式: VOC标签格式,标注的标签存储在xml文…

insightface 环境配置

首先创建续集环境: conda create -n insightface3 python3.8 然后打开此虚拟环境:conda activate insightface3 然后安装: pip install insightface 再安装:pip install onnxruntime-gpu 就可以了