IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    彻底搞懂 package.json 中的 exports, main, module, type

    小鱼发表于 2023-08-20 15:21:15
    love 0

    每个项目(npm上下载的包,或者其他的nodejs项目)的根目录下面,一般都有一个package.json文件, 定义了这个项目所需要的各种模块,以及项目的配置信息(比如名称、版本、许可证、如何启动项目、运行脚本等元数据)。但是你对里面的字段都很了解吗,本文将带你了解其中经常使用的一些字段。

    repository/homepage

    项目的仓库地址, 会显示在 npm package 右侧

    {
      "repository": {
        "type": "git",
        "url": "git+https://github.com/jerrywu001/sandpack-vue3.git"
      },
      "homepage": "https://sandpack-vue3.netlify.app",
    }

    main/module/types

    {
      "main": "./dist/index.js",
      "module": "./dist/index.mjs",
      "types": "./dist/index.d.ts",
    }
    • main

    对应commonjs引入方式的程序入口文件

    const { Sandpack } = require('sandpack-vue3);
    
    • module

    对应esmodule引入方式的程序入口文件

    import { Sandpack } from 'sandpack-vue3';
    
    • types

    描述了程序中所有组件以及变量的类型定义

    exports

    介绍

    exports定义了自定义导出规则,可以理解为路径映射

    {
       "exports": {
        ".": {
          "types": "./dist/index.d.ts",
          "import": "./dist/index.mjs",
          "require": "./dist/index.js"
        },
        "./unstyled": {
          "types": "./dist/unstyled.d.ts",
          "import": "./dist/unstyled.mjs",
          "require": "./dist/unstyled.js"
        }
      },
    }

    实战案例

    测试了vite|@vue/cli|nuxt3|vitepress,保证了解决方案的有效性。

    import { Sandpack } from 'sandpack-vue3';
    import { Sandpack as UnstyledPack } from 'sandpack-vue3/unstyled';
    import 'sandpack-vue3/dist/styles.css';
    

    以上的案例代码存在一些问题

    • build过程,无法识别’sandpack-vue3/dist/styles.css’路径

    – 解决方案:

    {
      "exports": {
        ".": {
          "types": "./dist/index.d.ts",
          "import": "./dist/index.mjs",
          "require": "./dist/index.js"
        },
        "./unstyled": {
          "types": "./dist/unstyled.d.ts",
          "import": "./dist/unstyled.mjs",
          "require": "./dist/unstyled.js"
        },
    +   "./*": [
    +      "./*",
    +      "./*.d.ts"
    +    ]
      },
    }
    • ts无法识别’sandpack-vue3/unstyled’路径

    – 解决方案 (*增加的两段内容,缺一不可!*):

    特别需要注意的是:dist目录下需要保证unstyled.d.ts存在,并且需要和exports中子路径名称一致,否则依然无法找到路径

    {
      "exports": {
       ".": {
         "types": "./dist/index.d.ts",
         "import": "./dist/index.mjs",
         "require": "./dist/index.js"
       },
       "./unstyled": { // <-需和dist下unstyled.d.ts文件名称一致
         "types": "./dist/unstyled.d.ts", // 可以省略,但不建议
         "import": "./dist/unstyled.mjs",
         "require": "./dist/unstyled.js"
       },
    +   "./*": [
    +      "./*",
    +      "./*.d.ts"
    +    ]
     },
    +  "typesVersions": {
    +    "*": {
    +      "*": [
    +        "./dist/*",
    +        "./*"
    +      ]
    +    }
     },
    }

    type和exports/main/module的关系

    首先我们需要理解type字段的含义:

    当设置为“module”时,所在项目中(不包含node_modules)所有.js文件将被视为EsModule类型文件。
    如果省略“type”字段或设置为“commonjs”,则项目中(不包含node_modules)所有.js文件都被视为CommonJS类型文件。

    type: “module”

    此时.js文件将被视为esmodule,并且我们需要将commonjs文件显示声明为.cjs

    改造配置如下:

    {
      ...,
      "type": "module",
      "main": "./dist/index.cjs",
      "module": "./dist/index.js",
      "types": "./dist/index.d.ts",
      "exports": {
        ".": {
          "types": "./dist/index.d.ts",
          "import": "./dist/index.js",
          "require": "./dist/index.cjs"
        },
        "./unstyled": {
          "types": "./dist/unstyled.d.ts", // 可以省略,但不建议
          "import": "./dist/unstyled.js",
          "require": "./dist/unstyled.cjs"
        },
        "./*": "./*"
      },
      ...
    }

    type: “commonjs” 或不设置

    此时.js将被视为commonjs,并且我们需要将esmodule文件显示声明为.mjs/.esm.js(实际上你声明成.xxx.js也可以,甚至.xxx也行,但不建议)

    改造配置如下:

    {
      ...,
      "main": "./dist/index.js",
      "module": "./dist/index.mjs",
      "types": "./dist/index.d.ts",
      "exports": {
        ".": {
          "types": "./dist/index.d.ts",
          "import": "./dist/index.mjs",
          "require": "./dist/index.js"
        },
        "./unstyled": {
          "types": "./dist/unstyled.d.ts", // 可以省略,但不建议
          "import": "./dist/unstyled.mjs",
          "require": "./dist/unstyled.js"
        },
        "./*": "./*"
      },
      ...
    }

    main/module 和 exports的关系

    exports省略场景

    如果没有子路径,比如m没有my-package/xxx,只是简单的my-package, 那配置可以简化为:

    {
      ...,
      "main": "./dist/index.js",
      "module": "./dist/index.mjs",
      "types": "./dist/index.d.ts",
      ...
    }

    exports不可省略场景

    存在子路径,此时需要添加exports进行路径映射,并且export中的”.”配置会具有较高优先级,所以”.”对应的路径必须是真实存在的(这么一说,即使你在main/module中的路径写错了,也没关系,感兴趣的可以自行尝试一下)。

    子路径不想放根目录下??

    有时候我们有想把子路径文件放单独文件夹的想法,可行吗?答案是,可以的,但是我们必须保证dist根目录下xxx.d.ts真实存在,除它之外的其他文件可以单独文件夹,举个 :



沪ICP备19023445号-2号
友情链接