packlets

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
Packlets are a nice way to keep your JavaScript codebase somewhat loosely-coupled, without having to separate things into different npm packages.
You follow these 5 rules:
  1. Packlets live in
    ./src/packlets/<name>/
    and the entry point is
    index.ts
    .
  2. Files outside a packlet can only import from packlet’s entry point,
    index.ts
    .
  3. Files inside a packlet may not import its own entry point,
    index.ts
    .
  4. Packlets can import other packlets but cannot create circular dependencies.
  5. Packlets can only import other packlets and npm packages.
Packlets 是一种无需将代码拆分为不同npm包,即可让你的JavaScript代码库保持一定松散耦合性的好方法。
你需要遵循以下5条规则
  1. Packlets 存放于
    ./src/packlets/<name>/
    目录下,入口文件为
    index.ts
  2. Packlet外部的文件只能从packlet的入口文件
    index.ts
    导入内容。
  3. Packlet内部的文件不得导入自身的入口文件
    index.ts
  4. Packlet可以导入其他packlet,但不能产生循环依赖。
  5. Packlet只能导入其他packlet和npm包。

About packlets

关于packlets

Motivation

设计动机

When building a large application, it's a good idea to organize source files into modules, so that their dependencies can be managed. For example, suppose an application's source files can be grouped as follows:
  • src/logging/*.ts
    - the logging system
  • src/data-model/*.ts
    - the data model
  • src/reports/*.ts
    - the report engine
  • src/*.ts
    - other arbitrary files such as startup code and the main application
Using file folders is helpful, but it's not very strict. Files under
src/logging
can easily import files from
/src/reports
, creating a confusing circular import. They can also import arbitrary application files. Also, there is no clear distinction between which files are the "public API" for
src/logging
versus its private implementation details.
All these problems can be solved by reorganizing the project into NPM packages (or Rush projects). Something like this:
  • @my-app/logging
    - the logging system
  • @my-app/data-model
    - the data model
  • @my-app/reports
    - the report engine
  • @my-app/application
    - other arbitrary files such as startup code and the main application
However, separating code in this way has some downsides. The projects need to build separately, which has some tooling costs (for example, "watch mode" now needs to consider multiple projects). In a large monorepo, the library may attract other consumers, before the API has been fully worked out.
Packlets provide a lightweight alternative that offers many of the same benefits of packages, but without the
package.json
file. It's a great way to prototype your project organization before later graduating your packlets into proper NPM packages.
在构建大型应用程序时,将源文件组织为模块是个好主意,这样可以管理它们的依赖关系。例如,假设某个应用的源文件可以按以下方式分组:
  • src/logging/*.ts
    - 日志系统
  • src/data-model/*.ts
    - 数据模型
  • src/reports/*.ts
    - 报表引擎
  • src/*.ts
    - 其他任意文件,如启动代码和主应用程序
使用文件夹组织代码会有帮助,但约束性不强。
src/logging
下的文件可以轻松导入
/src/reports
中的文件,从而产生混乱的循环导入。它们还可以导入任意应用文件。此外,
src/logging
的“公开API”与其私有实现细节之间也没有明确区分。
所有这些问题都可以通过将项目重组为NPM包(或Rush项目)来解决。例如:
  • @my-app/logging
    - 日志系统
  • @my-app/data-model
    - 数据模型
  • @my-app/reports
    - 报表引擎
  • @my-app/application
    - 其他任意文件,如启动代码和主应用程序
不过,以这种方式拆分代码也有一些缺点。各个项目需要单独构建,这会带来一些工具成本(例如,“监听模式”现在需要考虑多个项目)。在大型单体仓库中,库可能会在API完全确定前就吸引其他使用者。
Packlets提供了一种轻量级的替代方案,它具备包管理的诸多优势,却不需要
package.json
文件。这是在将packlets升级为正式NPM包之前,原型化项目组织结构的绝佳方式。

5 rules for packlets

Packlets的5条规则

With packlets, our folders would be reorganized as follows:
  • src/packlets/logging/*.ts
    - the logging system
  • src/packlets/data-model/*.ts
    - the data model
  • src/packlets/reports/*.ts
    - the report engine
  • src/*.ts
    - other arbitrary files such as startup code and the main application
The packlets-tutorial sample project illustrates this layout in full detail.
The basic design can be summarized in 5 rules:
  1. A "packlet" is defined to be a folder path
    ./src/packlets/<packlet-name>/index.ts
    . The index.ts file will have the exported APIs. The
    <packlet-name>
    name must consist of lower case words separated by hyphens, similar to an NPM package name.
    Example file paths:
    src/packlets/controls
    src/packlets/logger
    src/packlets/my-long-name
    NOTE: The
    packlets
    cannot be nested deeper in the tree. Like with NPM packages,
    src/packlets
    is a flat namespace.
  2. Files outside the packlet folder can only import the packlet root index.ts:
    src/app/App.ts
    ts
    // Okay
    import { MainReport } from '../packlets/reports';
    
    // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics)
    import { MainReport } from '../packlets/reports/index';
    
    // Error: The import statement does not use the packlet's entry point (@rushstack/packlets/mechanics)
    import { MainReport } from '../packlets/reports/MainReport';
  3. Files inside a packlet folder should import their siblings directly, not via their own index.ts (which might create a circular reference):
    src/packlets/logging/Logger.ts
    ts
    // Okay
    import { MessageType } from "./MessageType";
    
    // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics)
    import { MessageType } from ".";
    
    // Error: Files under a packlet folder must not import from their own index.ts file (@rushstack/packlets/mechanics)
    import { MessageType } from "./index";
  4. Packlets may reference other packlets, but not in a way that would introduce a circular dependency:
    src/packlets/data-model/DataModel.ts
    ts
    // Okay
    import { Logger } from '../../packlets/logging';
    src/packlets/logging/Logger.ts
    ts
    // Error: Packlet imports create a circular reference:  (@rushstack/packlets/circular-deps)
    //   "logging" is referenced by src/packlets/data-model/DataModel.ts
    //   "data-model" is referenced by src/packlets/logging/Logger.ts
    import { DataModel } from '../../packlets/data-model';
  5. Other source files are allowed outside the src/packlets folder. They may import a packlet, but packlets must only import from other packlets or NPM packages.
    src/app/App.ts
    ts
    // Okay
    import { MainReport } from '../packlets/reports';
    src/packlets/data-model/ExampleModel.ts
    ts
    // Error: A local project file cannot be imported. A packlet's dependencies must be
    // NPM packages and/or other packlets. (@rushstack/packlets/mechanics)
    import { App } from '../../app/App';
使用packlets后,我们的文件夹结构会重组如下:
  • src/packlets/logging/*.ts
    - 日志系统
  • src/packlets/data-model/*.ts
    - 数据模型
  • src/packlets/reports/*.ts
    - 报表引擎
  • src/*.ts
    - 其他任意文件,如启动代码和主应用程序
packlets-tutorial示例项目详细展示了这种目录结构。
基本设计可总结为5条规则:
  1. “packlet”的定义是路径为
    ./src/packlets/<packlet-name>/index.ts
    的文件夹。index.ts文件包含对外导出的API。
    <packlet-name>
    必须由小写单词组成,单词间用连字符分隔,类似于NPM包名称。
    示例文件路径:
    src/packlets/controls
    src/packlets/logger
    src/packlets/my-long-name
    注意: packlets不能在目录树中嵌套。与NPM包一样,
    src/packlets
    是一个扁平命名空间。
  2. Packlet文件夹外部的文件只能导入packlet根目录下的index.ts
    src/app/App.ts
    ts
    // 合法
    import { MainReport } from '../packlets/reports';
    
    // 错误:导入语句未使用packlet的入口文件 (@rushstack/packlets/mechanics)
    import { MainReport } from '../packlets/reports/index';
    
    // 错误:导入语句未使用packlet的入口文件 (@rushstack/packlets/mechanics)
    import { MainReport } from '../packlets/reports/MainReport';
  3. Packlet文件夹内部的文件应直接导入同级文件,而非通过自身的index.ts(这可能会产生循环引用):
    src/packlets/logging/Logger.ts
    ts
    // 合法
    import { MessageType } from "./MessageType";
    
    // 错误:packlet文件夹下的文件不得导入自身的index.ts文件 (@rushstack/packlets/mechanics)
    import { MessageType } from ".";
    
    // 错误:packlet文件夹下的文件不得导入自身的index.ts文件 (@rushstack/packlets/mechanics)
    import { MessageType } from "./index";
  4. Packlet可以引用其他packlet,但不能以引入循环依赖的方式引用:
    src/packlets/data-model/DataModel.ts
    ts
    // 合法
    import { Logger } from '../../packlets/logging';
    src/packlets/logging/Logger.ts
    ts
    // 错误:Packlet导入产生了循环引用:  (@rushstack/packlets/circular-deps)
    //   "logging" 被 src/packlets/data-model/DataModel.ts 引用
    //   "data-model" 被 src/packlets/logging/Logger.ts 引用
    import { DataModel } from '../../packlets/data-model';
  5. src/packlets文件夹外也可以有其他源文件。这些文件可以导入packlet,但packlet只能导入其他packlet或NPM包。
    src/app/App.ts
    ts
    // 合法
    import { MainReport } from '../packlets/reports';
    src/packlets/data-model/ExampleModel.ts
    ts
    // 错误:无法导入本地项目文件。packlet的依赖只能是
    // NPM包和/或其他packlet。(@rushstack/packlets/mechanics)
    import { App } from '../../app/App';