web-infra-dev / modern.js

Modern.js is a web engineering system, including a web framework and a npm package solution.
https://modernjs.dev/en/
MIT License
4.4k stars 367 forks source link

[RFC]: 尝试使用`moduleTools`替代我的开源库`tsup`构建失败,求帮助 #3245

Closed zhangfisher closed 1 year ago

zhangfisher commented 1 year ago

What problem does this feature solve?

我的开源项目: https://github.com/zhangfisher/flex-tools

我个人的一个工具函数库

源码结构是这样的:

src
  ├─async
  ├─classs
  ├─collection
  ├─events
  ├─func
  ├─misc
  ├─object
  ├─project
  ├─shell
  ├─string
  ├─tree
  └─typecheck、
  index.ts

这样的特性要求就决定了不能只有一个打包入口indexts,不能启用treeshake

目前我是使用tsup来打包,其配置文件如下:

export default defineConfig({
    entry: [
        'src/**/*.ts'
    ],
    format: ['esm','cjs'],
    dts: true,
    splitting: true,
    sourcemap: false,
    clean: true,
    treeshake:true,  
    minify: true,
}

最终打包出来的是内容如下:

│  chunk-26OW6JSQ.mjs
│  chunk-2EIZ4UH2.js
│  chunk-UKD44UVX.js
│  .....    //  一砣的chunk
│  index.d.ts
│  ..... 
├─async
│      asyncSignal.d.ts
│      asyncSignal.js
│      ......
├─classs
│      getClassStaticValue.d.ts
│      ......
├─collection
│      dictArray.d.ts
│      dictArray.js
│      ......│      
├─events
│      flexEvent.d.ts
│      flexEvent.js
│      ......
├─func
│      applyParams.d.ts
│      applyParams.js
│      ......
├─misc
│      index.d.ts
│      ......
├─object
│      assignObject.d.ts
│      assignObject.js
│      ......
├─string
│      center.d.ts
│      center.js
│      center.mjs
│      ......
│
├─tree
│      consts.d.ts
│      consts.js
│      ......
│
└─typecheck
        canIterable.d.ts
        canIterable.js
        canIterable.mjs
        index.d.ts
      ......

接下来,我尝试使用moduleTools来替代tsup,想达到相同的效果,但没有成功

我做了以下尝试:

` error ModuleBuildError: bundleless DTS failed: error TS18003: No inputs were found in config file 'flex-tools/node_modules/.dts-temp/2889nKX7VOyU_CNA4w5gx/tsconfig.json'. Specified 'include' paths were '["*/"]' and 'exclude' paths were 'flex-tools\node_modules\.dts-temp\2889nKX7VOyU_CNA4w5gx\src"]'.



是否可以成功实现替代,求助!!!

### What does the proposed API look like?

是否可以成功实现替代,求助!!!
chenjiahan commented 1 year ago

出现这个报错的话,需要在 tsconfig.json 文件里添加 include 配置,不然没法生成 TS 类型喔

// tsconfig.json
{
  "include": ["src"]
}

另外你的场景可以参考如下的 buildConfig,分别生成 esmodule 和 commonjs 的 bundleless 产物,以及对应的 types 声明

import moduleTools, { defineConfig } from "@modern-js/module-tools";

export default defineConfig({
  plugins: [moduleTools()],
  buildConfig: [
    {
      format: "cjs",
      target: "es6",
      buildType: "bundleless",
      outDir: "./dist/lib",
    },
    {
      format: "esm",
      target: "es6",
      buildType: "bundleless",
      outDir: "./dist/es",
    },
    {
      buildType: "bundleless",
      outDir: "./dist/types",
      dts: {
        only: true,
      },
    },
  ],
});
zhangfisher commented 1 year ago

很不错,闪电般地成功构建出来了

有个问题,最终的构建是这样的:

dist
├─es
│  ├─async
│  ├─classs
│  ├─collection
│  ├─events
│  ├─func
│  ├─misc
│  ├─object
│  ├─project
│  ├─shell
│  ├─string
│  ├─tree
│  └─typecheck
├─lib
│  ├─async
│  ├─classs
│  ├─collection
│  ├─events
│  ├─func
│  ├─misc
│  ├─object
│  ├─project
│  ├─shell
│  ├─string
│  ├─tree
│  └─typecheck
└─types
    ├─async
    ├─classs
    ├─collection
    ├─events
    ├─func
    ├─misc
    ├─object
    ├─project
    ├─shell
    ├─string
    ├─tree
    └─typecheck

但这离我的预想还有点小差距,我希望是这样的:


├─dist
│  ├─async
│  ├──asyncSignal.js                                     // cjs
│  ├──asyncSignal.mjs                                  // mjs
│  ├──asyncSignal.d.ts
│  ├─classs
│  ├─collection
│  ├─events
│  ├─func
│  ├─misc
│  ├─object
│  ├─project
│  ├─shell
│  ├─string
│  ├─tree
│  └─typecheck

我想让构建在同一个文件夹中,不同的格式采用扩展名来区别。

我之前也是这样的操作的,但是有个问题,不同场景下的的导入操作路径不一样,体验不好。 比如在es下,必须采用import {} from "flex-tools/es/xxxx",而在nodejs下使用require "flex-tools/lib/xxx" 我想实现统一的路径导入,为此我使用了package.json中的exports`字段来为实现统一的路径导入。 一切很完美!!!

但是现实很残酷,使用exports字段的机制在nodejs中可以工作很好,但是在typescriptreact native中也有问题,所以不得不放弃。

所以,我最终选择将cjs和mjs文件放在同一个文件夹下的方案。

chenjiahan commented 1 year ago

exports 字段在 typescript 中应该没问题的,react native 倒没试过。

如果需要把 .mjs.js 放在同一个目录下的话,目前 module-tools 还不支持这种结构,我们先调研下,看看后续能不能提供相应的配置。

@10Derozan

zhangfisher commented 1 year ago

为了给调用者提供统一的导入路径,我一开始的package.json是这样的:

"exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "require": "./dist/index.js",
      "import": "./dist/index.mjs"
    },
    "./types": {
      "types": "./dist/types.d.ts",
      "require": "./dist/types.js",
      "import": "./dist/types.mjs"
    },
    "./async": {
      "types": "./dist/async/index.d.ts",
      "require": "./dist/async/index.js",
      "import": "./dist/async/index.mjs"
    },
    "./class": {
      "types": "./dist/class/index.d.ts",
      "require": "./dist/class/index.js",
      "import": "./dist/class/index.mjs"
    },
    "./collection": {
      "types": "./dist/collection/index.d.ts",
      "require": "./dist/collection/index.js",
      "import": "./dist/collection/index.mjs"
    },
    "./events": {
      "types": "./dist/events/index.d.ts",
      "require": "./dist/events/index.js",
      "import": "./dist/events/index.mjs"
    },
    "./func": {
      "types": "./dist/func/index.d.ts",
      "require": "./dist/func/index.js",
      "import": "./dist/func/index.mjs"
    },
    "./object": {
      "types": "./dist/object/index.d.ts",
      "require": "./dist/object/index.js",
      "import": "./dist/object/index.mjs"
    },
    "./tree": {
      "types": "./dist/tree/index.d.ts",
      "require": "./dist/tree/index.js",
      "import": "./dist/tree/index.mjs"
    },
    "./typecheck": {
      "types": "./dist/typecheck/index.d.ts",
      "require": "./dist/typecheck/index.js",
      "import": "./dist/typecheck/index.mjs"
    },
    "./string": {
      "types": "./dist/string/index.d.ts",
      "require": "./dist/string/index.js",
      "import": "./dist/string/index.mjs"
    },
    "./string/params": {
      "types": "./dist/string/params.d.ts",
      "require": "./dist/string/params.js",
      "import": "./dist/string/params.mjs"
    },
    "./string/firstUpper": {
      "types": "./dist/string/firstUpper.d.ts",
      "require": "./dist/string/firstUpper.js",
      "import": "./dist/string/firstUpper.mjs"
    },
    "./string/center": {
      "types": "./dist/string/center.d.ts",
      "require": "./dist/string/center.js",
      "import": "./dist/string/center.mjs"
    },
    "./string/reverse": {
      "types": "./dist/string/reverse.d.ts",
      "require": "./dist/string/reverse.js",
      "import": "./dist/string/reverse.mjs"
    },
    "./string/ljust": {
      "types": "./dist/string/ljust.d.ts",
      "require": "./dist/string/ljust.js",
      "import": "./dist/string/ljust.mjs"
    },
    "./string/rjust": {
      "types": "./dist/string/rjust.d.ts",
      "require": "./dist/string/rjust.js",
      "import": "./dist/string/rjust.mjs"
    },
    "./string/trimBeginChars": {
      "types": "./dist/string/trimBeginChars.d.ts",
      "require": "./dist/string/trimBeginChars.js",
      "import": "./dist/string/trimBeginChars.mjs"
    },
    "./string/trimEndChars": {
      "types": "./dist/string/trimEndChars.d.ts",
      "require": "./dist/string/trimEndChars.js",
      "import": "./dist/string/trimEndChars.mjs"
    }
  },
  "typesVersions": {
    "*": {
      "string": [
        "./dist/string/index.d.ts"
      ],
      "string/params": [
        "./dist/string/params.d.ts"
      ],
      "string/firstUpper": [
        "./dist/string/firstUpper.d.ts"
      ],
      "string/center": [
        "./dist/string/center.d.ts"
      ],
      "string/reverse": [
        "./dist/string/reverse.d.ts"
      ],
      "string/ljust": [
        "./dist/string/ljust.d.ts"
      ],
      "string/rjust": [
        "./dist/string/rjust.d.ts"
      ],
      "string/trimBeginChars": [
        "./dist/string/trimBeginChars.d.ts"
      ],
      "string/trimEndChars": [
        "./dist/string/trimEndChars.d.ts"
      ],
      "typecheck": [
        "./dist/typecheck/index.d.ts"
      ],
      "tree": [
        "./dist/tree/index.d.ts"
      ],
      "object": [
        "./dist/object/index.d.ts"
      ],
      "func": [
        "./dist/func/index.d.ts"
      ],
      "events": [
        "./dist/events/index.d.ts"
      ],
      "collection": [
        "./dist/collection/index.d.ts"
      ],
      "async": [
        "./dist/async/index.d.ts"
      ],
      "classs": [
        "./dist/classs/index.d.ts"
      ],
      "types": [
        "./dist/types.d.ts"
      ]
    }
  }

非常冗长的配置,不幸的是后来发现typescriptexports的支持是比较晚的 而且在react native下使用时问题出来了,react native 使用的打包工具是metro,不支持exports字段(也许是我没搞懂),总之是有问题,所以不得不放弃引入exports这个特性。

chenjiahan commented 1 year ago

确实,typescript 较新的版本才完整支持了 exports 字段。

zhangfisher commented 1 year ago

rspack引到此的,想尝尝鲜的,以为moduleTools也是采用rspack的,毕竟是一家人,才发现原来是esbuild构建,:)

chenjiahan commented 1 year ago

嗯嗯,Rspack 更适合做 Web 应用的构建。

对于 npm 包构建,目前我们是基于 esbuild 来实现的,esbuild 的能力也基本上可以满足 npm 包构建的场景。

zhangfisher commented 1 year ago

那是否会继续更新moduleTools,比如升级为采用rspack构建?

chenjiahan commented 1 year ago

moduleTools 会持续更新的哈,至于 moduleTools 切换到 Rspack 构建,我们还在评估中

10Derozan commented 1 year ago

我已经帮你完善了构建配置https://github.com/zhangfisher/flex-tools/pull/1

10Derozan commented 1 year ago

tsup是一个非常棒的工具,我们也借鉴了其一些设计,和tsup一样,module tools也是基于esbuild构建library,只不过module tools定位并不是一个构建工具而是一个解决方案,它可以帮你快速生成一个组件库/工具库的模板,集成了test、storybook、changeset等功能,覆盖开发一个库的全链路。

对于esbuild的封装,我们独立了libuild,相比tsup,对于 scss/less/postcss 的支持会更好,并且有一些对于不打包这个场景的探索(我个人的理解)。

由于本身module tools设计上的问题,部分esbuild配置并没有直接暴露,导致你迁移上的困难,很抱歉。现在我已帮你完善了构建配置,我想现在应该符合你的需求了,后续有问题也可以再交流。

zhangfisher commented 1 year ago

今天将flex-tools正式使用moduleTools进行构建发布

对比一下tsupmoduleTools的配置文件:

export default defineConfig({
    entry: [
        'src/**/*.ts'
    ],
    format: ['esm','cjs'],
    dts: true,
    splitting: true,
    sourcemap: false,
    clean: true,
    treeshake:true,  
    minify: true,
    esbuildPlugins:[
        // @ts-ignore
        copy({
            source:['package.json','README.md','LICENSE'],
            target:"dist/"
        })
    ], 
    banner: {
        js: `/**
*        
*   ---=== FlexTools ===---
*   https://zhangfisher.github.com/flex-tools
* 
*   一些实用工具函数
*
*/`}
}) 
const ModulePlugin = (): CliPlugin<ModuleTools> => ({
  name: 'module',
  setup: () => ({
    modifyLibuild(config) {
      config.esbuildOptions = c => {
        c.banner = esbuildOptions.banner;
        c.plugins?.push(...esbuildOptions.plugins);
        c.entryNames = '[dir]/[name]'
        c.chunkNames = '[name]-[hash]';
        if (config.format === 'esm') {
          c.outExtension = { '.js': '.mjs' }
        }
        return c;
      };
      return config;
    },
  }),
});

export default defineConfig({
  plugins: [moduleTools(), ModulePlugin()],
  buildConfig: [
    {
      input: ['src'],
      format: 'esm',
      splitting: true,
      sourceMap: false,
      minify: 'esbuild',
      dts: false,
      target: 'es2021',
    },
    {
      buildType: 'bundleless',
      dts: {
        only: true
      }
    },
    {
      input: ['src'],
      format: 'cjs',
      splitting: true,
      sourceMap: false,
      minify: 'esbuild',
      dts: false,
      target: 'es2021',
    },
  ]
}) 

tsup的配置更加友好易用,期待改进!

10Derozan commented 1 year ago

ok会继续改进

wangs1203 commented 4 months ago

rspack引到此的,想尝尝鲜的,以为moduleTools也是采用rspack的,毕竟是一家人,才发现原来是esbuild构建,:)

你去rsbuild看 有些子包是morden 构建的😋