clsx源码阅读分析

clsx源码

版本 2.1.1

一个处理类名的函数。

地址:https://github.com/lukeed/clsx/blob/master/src/index.js

源码文件index.js

文件 src/index.js

//src/index.js
function toVal(mix) {
  var k,
    y,
    str = "";

  // 判断参数min类型, 字符串或数值类型 直接 拼接
  if (typeof mix === "string" || typeof mix === "number") {
    str += mix;
  } else if (typeof mix === "object") {
    // 数组类型
    if (Array.isArray(mix)) {
      var len = mix.length;
      for (k = 0; k < len; k++) {
        // 为真 才递归调用toVal函数处理
        if (mix[k]) {
          if ((y = toVal(mix[k]))) {
            str && (str += " ");
            str += y;
          }
        }
      }
    } else {
      // 对象类型
      for (y in mix) {
        // 为真 才拼接
        if (mix[y]) {
          str && (str += " ");
          str += y;
        }
      }
    }
  }

  return str;
}

export function clsx() {
  var i = 0,
    tmp,
    x,
    str = "",
    len = arguments.length;

  // 参数遍历
  for (; i < len; i++) {
    if ((tmp = arguments[i])) {
      // 处理参数, 最后都是拼接成字符串
      if ((x = toVal(tmp))) {
        str && (str += " ");
        str += x;
      }
    }
  }
  return str;
}

export default clsx;

源码文件lite.js

只处理字符串。

//src/lite.js
export function clsx() {
  // 定义声明变量
  var i = 0,
    tmp,
    str = "",
    len = arguments.length;

  // 参数遍历
  for (; i < len; i++) {
    if ((tmp = arguments[i])) {
      // 当参数为字符串时处理,拼接字符串
      if (typeof tmp === "string") {
        str += (str && " ") + tmp;
      }
    }
  }
  return str;
}

export default clsx;

使用

import clsx from "clsx";
// or
import { clsx } from "clsx";

// Strings (variadic)
clsx("foo", true && "bar", "baz");
//=> 'foo bar baz'

// Objects
clsx({ foo: true, bar: false, baz: isTrue() });
//=> 'foo baz'

// Objects (variadic)
clsx({ foo: true }, { bar: false }, null, { "--foobar": "hello" });
//=> 'foo --foobar'

// Arrays
clsx(["foo", 0, false, "bar"]);
//=> 'foo bar'

// Arrays (variadic)
clsx(["foo"], ["", 0, false, "bar"], [["baz", [["hello"], "there"]]]);
//=> 'foo bar baz hello there'

// Kitchen sink (with nesting)
clsx(
  "foo",
  [1 && "bar", { baz: false, bat: null }, ["hello", ["world"]]],
  "cya"
);
//=> 'foo bar hello world cya'

打包分析

{
  "name": "clsx",
  "version": "2.1.1",
  "repository": "lukeed/clsx",
  "description": "A tiny (239B) utility for constructing className strings conditionally.",
  "module": "dist/clsx.mjs",
  "unpkg": "dist/clsx.min.js",
  "main": "dist/clsx.js",
  "types": "clsx.d.ts",
  "license": "MIT",
  "exports": {
    //条件加载,利用.这个别名
    ".": {
      "import": {
        "types": "./clsx.d.mts",
        //default条件指定其他情况的入口(即 ES6 的入口)。
        "default": "./dist/clsx.mjs"
      },
      "default": {
        "types": "./clsx.d.ts",
        "default": "./dist/clsx.js"
      }
    },
    "./lite": {
      "import": {
        "types": "./clsx.d.mts",
        "default": "./dist/lite.mjs"
      },
      "default": {
        "types": "./clsx.d.ts",
        "default": "./dist/lite.js"
      }
    }
  },
  "author": {
    "name": "Luke Edwards",
    "email": "luke.edwards05@gmail.com",
    "url": "https://lukeed.com"
  },
  "engines": {
    "node": ">=6"
  },
  "scripts": {
    "build": "node bin",
    "test": "uvu -r esm test"
  },
  "files": ["*.d.mts", "*.d.ts", "dist"],
  "keywords": ["classes", "classname", "classnames"],
  "devDependencies": {
    "esm": "3.2.25",
    "terser": "4.8.0",
    "uvu": "0.5.4"//UVU是Node.js和浏览器的一个非常快速和轻量级的测试运行器
  }
}

main属性

定义这个 package 的入口文件位置。

在不支持 ES6 的 Nodejs 中,它指向的就是CommonJs模块系统的入口位置。

在 Nodejs 支持 ES6 的版本中,只要显示定义 "type": "module",那么它指向的就是 ESM 模块系统的入口位置

exports属性

export的使用:https://es6.ruanyifeng.com/#docs/module-loader#package-json-%E7%9A%84-exports-%E5%AD%97%E6%AE%B5

exports 字段可以配置不同环境对应的模块入口文件,并且当他存在时,它的优先级最高,当package.json文件中存在 exports 字段,设置的 main 字段会失效。exports 字段的优先级高于 main 字段。

示例

利用.这个别名,可以为 ES6 模块和 CommonJS 指定不同的入口。

{
  "type": "module",
  "exports": {
    ".": {
      "require": "./main.cjs",
      "default": "./main.js"
    }
  }
}

上面代码中,别名.require条件指定require()命令的入口文件(即 CommonJS 的入口),default条件指定其他情况的入口(即 ES6 的入口)。

执行打包

命令


{
    "scripts": {
        "build": "node bin",
        "test": "uvu -r esm test"
    },
}

bin/index.js文件

// @ts-check
const fs = require("fs");
// zlib 模块提供了使用 Gzip、Deflate/Inflate、以及 Brotli 实现的压缩功能。
const zlib = require("zlib");

// 一个用于ES6+的JavaScript管理器/压缩器工具包。
const { minify } = require("terser");
const pkg = require("../package.json");


// file 文件的路径 , source文件的内容
function write(file, source) {
  let isModule = !source.startsWith("!function");

  // 一个可配置的高级函数async minify(code, options),它将以可配置的方式执行所有缩小阶段。默认情况下,minify()将启用compress和mangle。
  let result = minify(source, {
    module: isModule,
    compress: true,
  });
// console.log(result.code);  // minified output: function add(n,d){return n+d}
// console.log(result.map);  // source map

  if (result.code) {
    fs.writeFileSync(file, result.code);
    // zlib.gzipSync压缩数据块   byteLength获取字节大小
    let size = zlib.gzipSync(result.code).byteLength;
    console.log('~> "%s" (%d b)', file, size);
  } else {
    console.error('!! "%s" ::', file, result.error);
  }
}

// file文件名称,entry文件别名
function bundle(file, entry) {
  // 判断是否存在文件夹dis,不存在则创建
  fs.existsSync("dist") || fs.mkdirSync("dist");

  //pkg 即package.json默认导出的对象
  let output = pkg.exports[entry];

  // 读取文件
  let input = fs.readFileSync(file, "utf8");

  // copy for ESM file
  write(output.import.default, input);

  // transform ESM -> CJS exports
  write(
    output.default.default,
    input
      .replace("export function", "function")
      .replace(
        "export default clsx;",
        "module.exports = clsx;\n" + "module.exports.clsx = clsx;"
      )
  );

  if (entry === ".") {
    // transform ESM -> UMD exports
    input = input
      .replace("export function", "function")
      .replace("export default clsx;", "return clsx.clsx=clsx, clsx;");

      // 写入文件
    write(
      pkg.unpkg,
      '!function(global,factory){"object"==typeof exports&&"undefined"!=typeof module?module.exports=factory():"function"==typeof define&&define.amd?define(factory):global.clsx=factory()}(this,function(){' +
        input +
        "});"
    );
  }
}

bundle("src/index.js", ".");

bundle("src/lite.js", "./lite");

package.josn文件中的exports配置信息


{
  "exports": {
    ".": {
      "import": {
        "types": "./clsx.d.mts",
        "default": "./dist/clsx.mjs"
      },
      "default": {
        "types": "./clsx.d.ts",
        "default": "./dist/clsx.js"
      }
    },
    "./lite": {
      "import": {
        "types": "./clsx.d.mts",
        "default": "./dist/lite.mjs"
      },
      "default": {
        "types": "./clsx.d.ts",
        "default": "./dist/lite.js"
      }
    }
  }
}

npm install过程

首先安装的依赖都会存放在根目录的node_modules,默认采用扁平化的方式安装,并且排序规则.bin第一个,然后@系列,再然后按照首字母排序abcd等,并且使用的算法是广度优先遍历,在遍历依赖树时,npm会首先处理项目根目录下的依赖,然后逐层处理每个依赖包的依赖,直到所有依赖都被处理完毕。在处理每个依赖时,npm会检查该依赖的版本号是否符合依赖树中其他依赖的版本要求,如果不符合,则会尝试安装适合的版本。

扁平化的理想状态

APP————A模块(c1.0)

APP————B模块(c1.0)

安装某个二级模块时,若发现第一层级有相同名称,相同版本的模块,便直接复用那个模块

因为A模块下的C模块被安装到了第一级,这使得B模块能够复用处在同一级下;且名称,版本,均相同的C模块

扁平化的非理想状态

APP————A模块(c1.0)

APP————B模块(c2.0)

因为B和A所要求的依赖模块不同,(B下要求是v2.0的C,A下要求是v1.0的C )所以B不能像2中那样复用A下的C v1.0模块 所以如果这种情况还是会出现模块冗余的情况,他就会给B继续搞一层node_modules,就是非扁平化了。

uvu插件

UVU是Node.js和浏览器的一个非常快速和轻量级的测试运行器.

# via `uvu` cli, for all `/tests/**` files
$ uvu -r esm tests

# via `node` directly, for file isolation
$ node -r esm tests/demo.js

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年07月03日 Redis部署方式和持久化

Redis持久化方式&#xff1a;RDB和AOF&#xff0c;和混合式 RDB&#xff1a;周期备份模式&#xff0c;每隔一段时间备份一份快照文件&#xff0c;从主线程Fork一个备份线程出来备份&#xff0c;缺点是会造成数据的丢失。 AOF&#xff1a;日志模式&#xff0c;每条命令都以操作…

【docker nvidia/cuda】ubuntu20.04安装docker踩坑记录

docker nvidia 1.遇到这个错误&#xff0c;直接上魔法(科学上网) OpenSSL SSL_connect: Could not connect to nvidia.github.io:443 这个error是运行 NVIDIA官方docker安装教程 第一个 curl 命令是遇到的 2. apt-get 更新 sudo apt update遇到 error https://download.do…

kylin arm xcb版本异常问题解决

源码编译qt 未生成xcb库&#xff0c;查看源码xcb readme.txt 提示 版本要求 下载 [ANNOUNCE] libxcb 1.14 [ANNOUNCE] xcb-proto 1.14 解压源码编译, 先编译xcb-proto sudo ./configure --prefix/usr/local/xcb-proto make make install 在编译xcb export PKG_CONFIG_PATH…

解决uni-app中全局设置页面背景颜色只有部分显示颜色的问题

在页面的style标签设置了背景色但是只显示一部分 <style lang="scss"> .content{background-color: #f7f7f7;height: 100vh; } </style>我们在app.vue里设置就行了 注意一定要是**page{}** <style>/*每个页面公共css */page{background-color:

劲爆!华为享界两款新车曝光,等等党有福了

文 | AUTO芯球 作者 | 雷慢 劲爆啊&#xff0c;北汽的一份环境影响分析报告&#xff0c; 不仅曝光了享界S9的生产进展&#xff0c; 还泄露了自家的另两款产品&#xff0c; 第一款是和享界S9同尺寸的旅行车&#xff0c; 我一看&#xff0c;这不是我最喜欢的“瓦罐”吗&…

【吊打面试官系列-MyBatis面试题】Xml 映射文件中,除了常见的 select|insert|updae|delete标签之外,还有哪些标签?

大家好&#xff0c;我是锋哥。今天分享关于 【Xml 映射文件中&#xff0c;除了常见的 select|insert|updae|delete标签之外&#xff0c;还有哪些标签&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; Xml 映射文件中&#xff0c;除了常见的 select|insert|updae|…

江汉大学刘春萌同学整理的wifi模块 上传mqtt实验步骤

一.固件烧录 1.打开安信可官网 2.点击wifi模组系列的ESP8266 3.点击各类固件后选择固件号1471下载 4.打开烧录工具将下载的二进制文件导入并将后面的起始地址写为0x00000,下面勾选40mhz QIO 8Mbit点击start下载即可 二.本地部署mqtt服务器(windows) 1.下载mosquitto后有一个m…

从零开始学量化~Ptrade使用教程(三)——行情界面主要功能

技术分析 除复权 提供向前复权、向后复权&#xff0c;系统默认不复权。此外&#xff0c;全面支持月、周、日线复权&#xff0c;支持向前和向后复权、不同时段分段复权等功能。系统能够根据盘中即时行情&#xff0c;个股K线图可以根据该股除权日的送股、配股及红利情况圆滑地画出…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【生成密钥(C/C++)】

生成密钥(C/C) 以生成ECC密钥为例&#xff0c;生成随机密钥。具体的场景介绍及支持的算法规格。 注意&#xff1a; 密钥别名中禁止包含个人数据等敏感信息。 开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复…

Stream的获取、中间方法、终结方法

1、获取Stream流 单列集合&#xff1a;foreach完整版 双列集合通过Ketset()、entryset() 数组的&#xff1a;通过Arrays Stream流的中间方法&#xff1a;链式编程&#xff0c;原stream流只能使用一次 filter&#xff1a; limit、skip&#xff1a; distinct(有自定义对象需要重写…

window.ai 开启你的内置AI之旅

❝ 成功是得你所想&#xff0c;幸福是享你所得 大家好&#xff0c;我是柒八九。一个专注于前端开发技术/Rust及AI应用知识分享的Coder ❝ 此篇文章所涉及到的技术有 AI( Gemini Nano) Chrome Ollama 因为&#xff0c;行文字数所限&#xff0c;有些概念可能会一带而过亦或者提供…

让你的 Rabbids Rockstar人物化身加入欢乐行列!

让你的 Rabbids Rockstar 人物化身加入欢乐行列&#xff01; https://www.youtube.com/watch?vwLBd20BxbS8 当这些调皮的小兔子以狂野的装扮、超棒的吉他弹奏和搞笑滑稽的动作登上舞台中央时&#xff0c;你将感受到它们异想天开的魅力。通过人物化身释放你内心的摇滚明星魅力&…

2024年7月3日 (周三) 叶子游戏新闻

老板键工具来唤去: 它可以为常用程序自定义快捷键&#xff0c;实现一键唤起、一键隐藏的 Windows 工具&#xff0c;并且支持窗口动态绑定快捷键&#xff08;无需设置自动实现&#xff09;。 卸载工具 HiBitUninstaller: Windows上的软件卸载工具 《魅魔》新DLC《Elysian Fields…

使用Spring Boot生成并下载包含下拉多选功能的Excel模板

步骤 1: 引入依赖 在pom.xml文件中添加EasyExcel <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version></dependency> 步骤2: 准备xlsm模板 首先&#xff0c;需要在Exc…

案例精选 | 聚铭综合日志分析系统为江苏省电子口岸构建高效安全的贸易生态

江苏省电子口岸有限公司&#xff0c;成立于2009年&#xff0c;由江苏省贸促会携手南京海关、江苏检验检疫局及江苏海事局等部门共同出资组建。公司承载着推动江苏乃至长三角地区国际贸易便利化的重大使命&#xff0c;致力于打造一个集先进性、创新性、高效性于一体的电子口岸综…

关于 VuePress 的插件

插件就好比第三方功能&#xff0c;例如增加一个阅读进度条、增加光标效果等。VuePress 官网对插件的介绍&#xff1a;插件通常会为 VuePress 添加全局功能。 这里简单介绍几个本站用的插件吧&#xff01; ‍ ‍ 插件就好比第三方功能&#xff0c;例如增加一个阅读进度条、增…

nginx安装演示(离线安装,直接安装在Linux中)

文章目录 1、创建文件夹 tool / nginx2、把安装文件放到 /opt/tool/nginx 目录下面3、yum install gcc4、yum install gcc-c5、tar -zxvf pcre-8.37.tar.gz6、./configure7、make8、make install9、tar -zxvf openssl-1.0.1t.tar.gz10、./config11、/config 1、创建文件夹 tool…

防静电监控系统在电子制造业智能化转型中的应用价值

在电子制造业迅速向智能化转型的当下&#xff0c;防静电监控系统正发挥着日益重要的作用&#xff0c;其应用价值体现在多个关键方面。 一、ESD防静电监控系统简介 ESD防静电监控系统是对企业防静电设备&#xff08;机器、台垫、离子风机&#xff09;和人员进行实时监控、数据存…

护航端侧大模型平稳健康发展,百度大模型内容安全Lite版正式发布

6月28日&#xff0c;WAVE SUMMIT深度学习开发者大会 2024 “智变应用、码动产业”平行论坛在北京召开。与会&#xff0c;百度大模型内容安全Lite版正式发布&#xff0c;可面向低算力和超低算力的终端大模型提供离线场景下的一站式安全解决方案&#xff0c;为各类终端大模型平稳…