From 239072a46e3a6841d2f8de80ad07f67e1b49afd4 Mon Sep 17 00:00:00 2001 From: fi3ework Date: Mon, 4 Nov 2024 16:02:30 +0800 Subject: [PATCH] docs: update structure / format / 3rd deps / glossary / TS --- packages/core/src/types/config/index.ts | 1 + packages/create-rslib/src/index.ts | 20 +-- scripts/dictionary.txt | 1 + website/docs/en/guide/advanced/_meta.json | 1 - website/docs/en/guide/advanced/templates.mdx | 1 - .../en/guide/advanced/third-party-deps.mdx | 80 +++++++++++ website/docs/en/guide/basic/_meta.json | 7 +- website/docs/en/guide/basic/bundle-mode.mdx | 1 - website/docs/en/guide/basic/cjs-esm.mdx | 1 - website/docs/en/guide/basic/output-files.mdx | 1 - website/docs/en/guide/basic/output-format.mdx | 126 ++++++++++++++++++ .../docs/en/guide/basic/output-structure.mdx | 20 +++ .../docs/en/guide/basic/typescript-usage.mdx | 1 - website/docs/en/guide/basic/typescript.mdx | 46 +++++++ .../docs/en/guide/start/components/CJS.mdx | 1 + .../docs/en/guide/start/components/ESM.mdx | 1 + .../docs/en/guide/start/components/UMD.mdx | 1 + website/docs/en/guide/start/glossary.mdx | 24 ++++ website/docs/en/guide/start/quick-start.mdx | 37 +++-- 19 files changed, 342 insertions(+), 29 deletions(-) delete mode 100644 website/docs/en/guide/advanced/templates.mdx delete mode 100644 website/docs/en/guide/basic/bundle-mode.mdx delete mode 100644 website/docs/en/guide/basic/cjs-esm.mdx delete mode 100644 website/docs/en/guide/basic/output-files.mdx create mode 100644 website/docs/en/guide/basic/output-format.mdx create mode 100644 website/docs/en/guide/basic/output-structure.mdx delete mode 100644 website/docs/en/guide/basic/typescript-usage.mdx create mode 100644 website/docs/en/guide/basic/typescript.mdx create mode 100644 website/docs/en/guide/start/components/CJS.mdx create mode 100644 website/docs/en/guide/start/components/ESM.mdx create mode 100644 website/docs/en/guide/start/components/UMD.mdx diff --git a/packages/core/src/types/config/index.ts b/packages/core/src/types/config/index.ts index 7b159240d..f2bb4800b 100644 --- a/packages/core/src/types/config/index.ts +++ b/packages/core/src/types/config/index.ts @@ -41,6 +41,7 @@ export type AutoExternal = | boolean | { dependencies?: boolean; + optionalDependencies?: boolean; devDependencies?: boolean; peerDependencies?: boolean; }; diff --git a/packages/create-rslib/src/index.ts b/packages/create-rslib/src/index.ts index 87000b7c7..81345e4ae 100644 --- a/packages/create-rslib/src/index.ts +++ b/packages/create-rslib/src/index.ts @@ -37,6 +37,16 @@ async function getTemplateName({ template }: Argv) { }), ); + const language = checkCancel( + await select({ + message: 'Select language', + options: [ + { value: 'ts', label: 'TypeScript' }, + { value: 'js', label: 'JavaScript' }, + ], + }), + ); + const supportStorybook = templateName === 'react'; type ExcludesFalse = (x: T | false) => x is T; @@ -56,16 +66,6 @@ async function getTemplateName({ template }: Argv) { }), ); - const language = checkCancel( - await select({ - message: 'Select language', - options: [ - { value: 'ts', label: 'TypeScript' }, - { value: 'js', label: 'JavaScript' }, - ], - }), - ); - return composeTemplateName({ template: templateName, lang: language as Lang, diff --git a/scripts/dictionary.txt b/scripts/dictionary.txt index 0846173cf..bdd78a973 100644 --- a/scripts/dictionary.txt +++ b/scripts/dictionary.txt @@ -131,6 +131,7 @@ unencapsulated unocss unpatch unplugin +unpredictibly unshift upath vitest diff --git a/website/docs/en/guide/advanced/_meta.json b/website/docs/en/guide/advanced/_meta.json index 7a91340c9..88c595ea9 100644 --- a/website/docs/en/guide/advanced/_meta.json +++ b/website/docs/en/guide/advanced/_meta.json @@ -1,6 +1,5 @@ [ "package-json", - "templates", "third-party-deps", "polyfill", "css", diff --git a/website/docs/en/guide/advanced/templates.mdx b/website/docs/en/guide/advanced/templates.mdx deleted file mode 100644 index 684234ff4..000000000 --- a/website/docs/en/guide/advanced/templates.mdx +++ /dev/null @@ -1 +0,0 @@ -# Templates diff --git a/website/docs/en/guide/advanced/third-party-deps.mdx b/website/docs/en/guide/advanced/third-party-deps.mdx index 40af82a4b..3c1edaaa5 100644 --- a/website/docs/en/guide/advanced/third-party-deps.mdx +++ b/website/docs/en/guide/advanced/third-party-deps.mdx @@ -1 +1,81 @@ # Handle Third-party Dependencies + +Generally, third-party dependencies required by a project can be installed via the `install` command in the package manager. After the third-party dependencies are successfully installed, they will generally appear under `dependencies` and `devDependencies` in the project `package.json`. + +```json title="package.json" +{ + "dependencies": {}, + "devDependencies": {} +} +``` + +Dependencies under `"dependencies"` are generally related to project code and builds, and if these third-party dependencies are declared under `"devDependencies"`, then there will be missing dependencies in production runtime. + +In addition to `"dependencies"`, `"peerDependencies"`can also declare dependencies that are needed in the production environment, but it puts more emphasis on the existence of these dependencies declared by `"peerDependencies"` in the project's runtime environment, similar to the plugin mechanism. + +## Default handling of third-party dependencies + +By default, **third-party dependencies under `"dependencies"`, `"optionalDependencies"` and `"peerDependencies"` are not bundled by Rslib**. + +This is because when the npm package is installed, its `"dependencies"` will also be installed. By not packaging `"dependencies"`, you can reduce the size of the package product. + +If you need to package some dependencies, it is recommended to move them from `"dependencies"` to `"devDependencies"`, which is equivalent to **prebundle** the dependencies and reduces the size of the dependency installation. + +### Example + +If the project has a dependency on `react`. + +```json title="package.json" +{ + "dependencies": { + "react": "^18" + }, + // or + "peerDependencies": { + "react": "^18" + } +} +``` + +When a `react` dependency is used in the source code: + +```tsx title="src/index.ts" +import React from 'react'; +console.info(React); +``` + +The `react` code will not be bundled into the output: + +```js title="dist/index.js" +import * as __WEBPACK_EXTERNAL_MODULE_react__ from 'react'; +console.info(__WEBPACK_EXTERNAL_MODULE_react__['default']); +``` + +If you want to modify the default processing, you can use the following API. + +- [`lib.autoExternal`](/config/lib/auto-external) + +## Exclude specified third-party dependencies + +We previously introduced the use of [`lib.autoExternal`](/config/lib/auto-external). This configuration lets you manage third-party dependencies more precisely. + +For example, when we need to leave only certain dependencies unbundled, we can configure it as follows. + +:::tip +In this case, some dependencies may not be suitable for bundling. If so, you can handle it as follows. +::: + +```ts +export default defineConfig({ + lib: [ + { + // ... + autoExternal: true, + output: { + externals: ['pkg-1', /pkg-2/], + }, + // ... + }, + ], +}); +``` diff --git a/website/docs/en/guide/basic/_meta.json b/website/docs/en/guide/basic/_meta.json index bcf7b076a..78cafde6d 100644 --- a/website/docs/en/guide/basic/_meta.json +++ b/website/docs/en/guide/basic/_meta.json @@ -1,10 +1,9 @@ [ "cli", "configure-rslib", - "typescript-usage", - "output-files", - "bundle-mode", + "typescript", + "output-format", + "output-structure", "upgrade-rslib", - "cjs-esm", "umd" ] diff --git a/website/docs/en/guide/basic/bundle-mode.mdx b/website/docs/en/guide/basic/bundle-mode.mdx deleted file mode 100644 index 7c13536c9..000000000 --- a/website/docs/en/guide/basic/bundle-mode.mdx +++ /dev/null @@ -1 +0,0 @@ -# Select Bundle Mode diff --git a/website/docs/en/guide/basic/cjs-esm.mdx b/website/docs/en/guide/basic/cjs-esm.mdx deleted file mode 100644 index cfa881420..000000000 --- a/website/docs/en/guide/basic/cjs-esm.mdx +++ /dev/null @@ -1 +0,0 @@ -# CJS and ESM diff --git a/website/docs/en/guide/basic/output-files.mdx b/website/docs/en/guide/basic/output-files.mdx deleted file mode 100644 index 0132e16c0..000000000 --- a/website/docs/en/guide/basic/output-files.mdx +++ /dev/null @@ -1 +0,0 @@ -# Output Files diff --git a/website/docs/en/guide/basic/output-format.mdx b/website/docs/en/guide/basic/output-format.mdx new file mode 100644 index 000000000..b5e4e97b2 --- /dev/null +++ b/website/docs/en/guide/basic/output-format.mdx @@ -0,0 +1,126 @@ +import ESM from '../start/components/ESM.mdx'; +import CJS from '../start/components/CJS.mdx'; +import UMD from '../start/components/UMD.mdx'; + +# Output Format + +This sets the output format for the generated JavaScript files. There are three supported values now: `esm`, `cjs`, and `umd`. In this guide, we will discuss the differences between these formats and how to choose the right one for your library. + +## ESM / CJS + +Library authors need to carefully consider which module formats to support. Let's understand ESM (ECMAScript Modules) and CJS (CommonJS) and when to use them. + +### What are ESM and CJS? + + + +- **ESM**: ESM is + +- **CommonJS**: [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules) is + +### What is the dilemma of esm / cjs + +> The following references are from [Node Modules at War: Why CommonJS and ES Modules Can't Get Along](https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1). + +1. You can't `require()` ESM scripts; you can only import ESM scripts, like this: `import {foo} from 'foo'` +2. CJS scripts can't use static `import` statements like the one above. +3. ESM scripts can `import` CJS scripts, but only by using the “default import” syntax `import _ from 'lodash'`, not the “named import” syntax `import {shuffle} from 'lodash'`, which is a hassle if the CJS script uses named exports. (Except, sometimes, unpredictibly, Node can figure out what you meant!) +4. ESM scripts can `require()` CJS scripts, even with named exports, but it's typically not worth the trouble, because it requires even more boilerplate, and, worst of all, bundlers like Webpack and Rollup don't/won't know how to work with ESM scripts that use `require()`. +5. CJS is the default; you have to opt-in to ESM mode. You can opt-in to ESM mode by renaming your script from `.js` to `.mjs`. Alternately, you can set `"type": "module"` in `package.json`, and then you can opt-out of ESM by renaming scripts from `.js` to `.cjs`. (You can even tweak just an individual subdirectory by putting a one-line `{"type": "module"}` `package.json` file in there.) + +### When to support which format? + +For different shapes of libraries, the choice of module format may vary. Here are two common scenarios: + +#### ship [pure ESM](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) package. + +shipping only ESM is the best choice for libraries that are intended to be used in modern environments, such as browser applications or Node.js applications that support ESM. However, if the upstream library is in format of CJS, they only can import pure ESM by using dynamic import like `const pureEsmLib = await import('pure-esm-lib')`. + +- **Pros:** + - ESM is the official JavaScript standard, making it more future-proof and widely supported across environments. + - ESM enables static analysis, which facilitates optimizations like tree-shaking to remove unused code. + - The syntax is cleaner and more intuitive, with import and export statements that are easier to read compared to CommonJS. + - ESM allows for better compatibility across both browser and server environments, making it ideal for isomorphic or universal JavaScript applications. +- **Cons:** + - ESM modules are loaded asynchronously, which can complicate conditional imports and lazy loading in some cases. + - Some Node.js tools and libraries still have limited or incomplete support for ESM, requiring workarounds or additional configuration. + - You must explicitly include file extensions in import paths, which can be cumbersome, especially when working with TypeScript or other transpiled languages. + +#### ship [ESM & CJS (dual)](https://antfu.me/posts/publish-esm-and-cjs#compatibility) package. + +The community is migrating to ESM, but there are still many projects using CJS. If you want to support both ESM and CJS, you can publish a dual package. For most library authors, offering dual formats is a safer and smoother way to access the best of both worlds. You could read antfu' blog post [Publish ESM and CJS packages](https://antfu.me/posts/publish-esm-and-cjs) for more details. + +- **Pros:** + + - Wider compatibility: Dual packages support both modern ESM environments and legacy CJS environments, ensuring broader usage across different ecosystems. + - Gradual migration: Developers can gradually transition from CJS to ESM without breaking existing projects, allowing for smoother adoption of the new standard. + - Flexibility for consumers: Users of the package can choose which module system best fits their project, providing flexibility in different build tools and environments. + - Cross-runtime support: Dual packages can work in multiple runtimes, such as Node.js and browsers, without requiring additional bundling or transpilation. + +- **Cons:** + + - Increased complexity: Maintaining two module formats adds complexity to the build process, requiring additional configuration and testing to ensure both versions work correctly14. + - Dual package hazard: Mixing ESM and CJS can lead to issues such as broken instanceof checks or unexpected behavior when dependencies are loaded in different formats13. + +## UMD + + + +### When to use UMD? + +If you are building a library that needs to be used in both the browser and Node.js environments, UMD is a good choice. UMD can be used as a standalone script tag in the browser or as a CommonJS module in Node.js. + +A detailed answer from StackOverflow: [What is the Universal Module Definition (UMD)?](https://stackoverflow.com/a/77284527/8063488) + +> However, for frontend libraries, you still offer a single file for convenience, that users can download (from a CDN) and directly embed in their web pages. This still commonly employs a UMD pattern, it's just no longer written/copied by the library author into their source code, but added automatically by the transpiler/bundler. +> +> And similarly, for backend/universal libraries that are supposed to work in +> node.js, you still also distribute a commonjs module build via npm to support +> all the users who still use a legacy version of node.js (and don't want/need +> to employ a transpiler themselves). This is less common nowadays for new +> libraries, but existing ones try hard to stay backwards-compatible and not +> cause applications to break. + +### How to build a UMD library? + +- Set the `output.format` to `umd` in the Rslib configuration file. +- If the library need to be exported with a name, set `output.umdName` to the name of the UMD library. +- Use `output.externals` to specify the external dependencies that the UMD library depends on, `lib.autoExtension` is enabled by default for UMD. + +### Examples + +The following Rslib config is an example to build a UMD library. + +- `output.format: 'umd'`: instruct Rslib to build in UMD format. +- `output.umdName: 'RslibUmdExample'`: set the export name of the UMD library. +- `output.externals.react: 'React'`: specify the external dependency `react` could be accessed by `window.React`. +- `runtime: 'classic'`: use the classic runtime of React to support applications that using React version under 18. + +```ts title="rslib.config.ts" {7-12,22} +import { pluginReact } from '@rsbuild/plugin-react'; +import { defineConfig } from '@rslib/core'; + +export default defineConfig({ + lib: [ + { + format: 'umd', + umdName: 'RslibUmdExample', + output: { + externals: { + react: 'React', + }, + distPath: { + root: './dist/umd', + }, + }, + }, + ], + plugins: [ + pluginReact({ + swcReactOptions: { + runtime: 'classic', + }, + }), + ], +}); +``` diff --git a/website/docs/en/guide/basic/output-structure.mdx b/website/docs/en/guide/basic/output-structure.mdx new file mode 100644 index 000000000..7627a9a91 --- /dev/null +++ b/website/docs/en/guide/basic/output-structure.mdx @@ -0,0 +1,20 @@ +# Output Structure + +## bundle / bundleless + +So first let's understand bundle and bundleless. + +A bundle is a package of build artifacts, which may be a single file or multiple files based on a certain [code splitting strategy](https://esbuild.github.io/api/#splitting). + +bundleless, on the other hand, means that each source file is compiled and built separately, but not bundled together. Each output file can be found with its corresponding source code file. The process of **bundleless build can also be understood as the process of code conversion of source files only**. + +They have their own benefits. + +- bundle can reduce the size of build artifacts and also pre-package dependencies to reduce the size of installed dependencies. Packaging libraries in advance can speed up application project builds. +- bundleless maintains the original file structure and is more conducive to debugging and tree shaking. + +:::warning +bundleless is a single-file compilation mode, so for referencing and exporting types, you need to add the `type` keyword. For example, `import type { A } from './types'`. Please refer to [TypeScript - isolatedModules](/guide/basic/typescript#isolatedmodules) for more information. +::: + +You can specify whether to bundle using the [bundle](/config/lib/bundle) option, which is set to `true` by default. diff --git a/website/docs/en/guide/basic/typescript-usage.mdx b/website/docs/en/guide/basic/typescript-usage.mdx deleted file mode 100644 index e7452683b..000000000 --- a/website/docs/en/guide/basic/typescript-usage.mdx +++ /dev/null @@ -1 +0,0 @@ -# Use Typescript diff --git a/website/docs/en/guide/basic/typescript.mdx b/website/docs/en/guide/basic/typescript.mdx new file mode 100644 index 000000000..c59369d51 --- /dev/null +++ b/website/docs/en/guide/basic/typescript.mdx @@ -0,0 +1,46 @@ +# Use Typescript + +Rslib supports TypeScript by default, allowing you to directly use `.ts` and `.tsx` files in your projects. + +## TypeScript Transpilation + +Rslib uses SWC by default for transpiling TypeScript code, and it also supports switching to Babel for transpilation. + +### isolatedModules + +Unlike the native TypeScript compiler, tools like SWC and Babel compile each file separately and cannot determine whether an imported name is a type or a value. Therefore, when using TypeScript in Rslib, you need to enable the [isolatedModules](https://typescriptlang.org/tsconfig/#isolatedModules) option in your `tsconfig.json` file: + +```json title="tsconfig.json" +{ + "compilerOptions": { + "isolatedModules": true + } +} +``` + +This option can help you avoid using certain syntax that cannot be correctly compiled by SWC and Babel, such as cross-file type references. It will guide you to correct the corresponding usage: + +```ts +// Wrong +export { SomeType } from './types'; + +// Correct +export type { SomeType } from './types'; +``` + +> See [SWC - Migrating from tsc](https://swc.rs/docs/migrating-from-tsc) for more details about the differences between SWC and tsc. + +## tsconfig.json Path + +Rslib by default reads the `tsconfig.json` file from the root directory. You can use [source.tsconfigPath](https://rsbuild.dev/config/source/tsconfig-path) to configure a custom tsconfig.json file path. + +```ts +export default { + lib: [ + // ... + ], + source: { + tsconfigPath: './tsconfig.custom.json', + }, +}; +``` diff --git a/website/docs/en/guide/start/components/CJS.mdx b/website/docs/en/guide/start/components/CJS.mdx new file mode 100644 index 000000000..6914198b9 --- /dev/null +++ b/website/docs/en/guide/start/components/CJS.mdx @@ -0,0 +1 @@ +a module system used in JavaScript, particularly in server-side environments like Node.js. It was created to allow JavaScript to be used outside of the browser by providing a way to manage modules and dependencies. diff --git a/website/docs/en/guide/start/components/ESM.mdx b/website/docs/en/guide/start/components/ESM.mdx new file mode 100644 index 000000000..8774f4bc9 --- /dev/null +++ b/website/docs/en/guide/start/components/ESM.mdx @@ -0,0 +1 @@ +a modern module system introduced in ES2015 that allows JavaScript code to be organized into reusable, self-contained modules. ESM is now the standard for both [browser](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) and [Node.js](https://nodejs.org/api/esm.html) environments, replacing older module systems like [CommonJS (CJS)](https://nodejs.org/api/modules.html) and [AMD](https://requirejs.org/docs/whyamd.html). diff --git a/website/docs/en/guide/start/components/UMD.mdx b/website/docs/en/guide/start/components/UMD.mdx new file mode 100644 index 000000000..14851f7aa --- /dev/null +++ b/website/docs/en/guide/start/components/UMD.mdx @@ -0,0 +1 @@ +UMD stands for [Universal Module Definition](https://github.com/umdjs/umd), a pattern for writing JavaScript modules that can work universally across different environments, such as both the browser and Node.js. Its primary goal is to ensure compatibility with the most popular module systems, including AMD (Asynchronous Module Definition), CommonJS (CJS), and browser globals. diff --git a/website/docs/en/guide/start/glossary.mdx b/website/docs/en/guide/start/glossary.mdx index ca3c82769..ddc5d38d4 100644 --- a/website/docs/en/guide/start/glossary.mdx +++ b/website/docs/en/guide/start/glossary.mdx @@ -1 +1,25 @@ +import ESM from './components/ESM.mdx'; +import CJS from './components/CJS.mdx'; +import UMD from './components/UMD.mdx'; + # Glossary + +## ESM + +ESM stands for ECMAScript Modules, + +## CJS + +CJS stands for [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules), + +## UMD + + + +## Bundleless + +Bundleless refers to a development approach that avoids the traditional practice of bundling multiple JavaScript / TypeScript files into a single or fewer output files before serving them to the client. Instead, it aims to serve individual modules directly. + +## More + +See more glossary in [Rsbuild - Glossary](https://rsbuild.dev/guide/start/glossary) and [Rspack - Glossary](https://rspack.dev/misc/glossary). diff --git a/website/docs/en/guide/start/quick-start.mdx b/website/docs/en/guide/start/quick-start.mdx index f7f818712..2bd7d0bcc 100644 --- a/website/docs/en/guide/start/quick-start.mdx +++ b/website/docs/en/guide/start/quick-start.mdx @@ -23,7 +23,7 @@ nvm use --lts ## Creating an Rslib Project -You can use the `create-rslib` to create a new Rslib project. Run the following command: +You can use the [`create-rslib`](https://www.npmjs.com/package/create-rslib) to create a new Rslib project. Run the following command: import { PackageManagerTabs } from '@theme'; @@ -40,18 +40,37 @@ Then follow the prompts to complete the operation. ### Templates -When creating a project, you can choose from the following templates provided by `create-rslib`: +`create-rslib` is a tool for quickly creating Rslib projects. When creating a project, you can choose from the following templates: -| Template | Description | -| ------------ | -------------------------------------------------- | -| node-dual-js | Node.js dual ESM/CJS package | -| node-dual-ts | Node.js dual ESM/CJS package written in TypeScript | -| node-esm-js | Node.js pure ESM package | -| node-esm-ts | Node.js pure ESM package written in TypeScript | +| Template | Description | +| ---------------------------- | ---------------------------- | +| Node.js dual ESM/CJS package | Node.js dual ESM/CJS package | +| Node.js pure ESM package | Node.js pure ESM package | +| React | React component library | + +Each template supports both JavaScript and TypeScript, along with optional development tools, formatters, and linters. + +:::info +We're working to provide templates for more frameworks (such as Vue). +::: + +### Development Tools + +`create-rslib` can help you set up some commonly used development linter tools, including [Vitest](https://vitest.dev/), [Storybook](https://storybook.js.org/). You can use the arrow keys and the space bar to make your selections. If you don't need these tools, you can simply press Enter to skip. + +- Vitest is available for all templates, it will be adapted based on the template's selection. +- Storybook is available for web targeted templates (React), it will be adapted based on the template's selection. + +```text +◆ Select development tools (Use to select, to continue) +│ ◻ Storybook +│ ◻ Vitest +└ +``` ### Optional Tools -`create-rslib` can help you set up some commonly used tools, including [Biome](https://github.com/biomejs/biome), [ESLint](https://github.com/eslint/eslint), and [prettier](https://github.com/prettier/prettier). You can use the arrow keys and the space bar to make your selections. If you don't need these tools, you can simply press Enter to skip. +`create-rslib` can help you set up some commonly used formatter and linter tools, including [Biome](https://biomejs.dev/), [ESLint](https://eslint.org/), and [prettier](https://prettier.io/). You can use the arrow keys and the space bar to make your selections. If you don't need these tools, you can simply press Enter to skip. ```text ◆ Select additional tools (Use to select, to continue)