From adf66da20e9ab6769a835e9c1b870342678459a3 Mon Sep 17 00:00:00 2001 From: barbapapazes Date: Sun, 17 Sep 2023 22:38:37 +0200 Subject: [PATCH 1/6] content: create unbuild 101 --- .../1.learn/3.unbuild-101-first-hand.md | 567 ++++++++++++++++++ 1 file changed, 567 insertions(+) create mode 100644 content/4.resources/1.learn/3.unbuild-101-first-hand.md diff --git a/content/4.resources/1.learn/3.unbuild-101-first-hand.md b/content/4.resources/1.learn/3.unbuild-101-first-hand.md new file mode 100644 index 00000000..cfb03b6e --- /dev/null +++ b/content/4.resources/1.learn/3.unbuild-101-first-hand.md @@ -0,0 +1,567 @@ +--- +title: unbuild 101 - first hand +description: +authors: + - name: Estéban Soubiran + picture: https://esteban-soubiran.site/esteban.webp + twitter: soubiran_ +packages: + - unbuild +publishedAt: 2023-09-12 +modifiedAt: 2023-09-12 +layout: learn-post +--- + + + + +## Installation + +First, let's create a new project: + +```bash +mkdir unbuild-101 +cd unbuild-101 +``` + +::alert{type="info"} +Do not initialize a new project with `npm init` or `yarn init` since we will explore how `unbuild` infer the configuration from `package.json`. +:: + +Then, install [`unjs/unbuild`](https://github.com/unjs/unbuild): + +```bash +npm install unbuild --save-dev +``` + +We now have a `package.json` file that looks like this: + +```json [package.json] +{ + "devDependencies": { + "unbuild": "^2.0.0" // or version could differ + } +} +``` + +::alert{type="info"} +We can use the package manager of our choice like `npm`, `yarn`, `pnpm` or `bun`. +:: + +## Our First Build + +By default, [`unjs/unbuild`](https://github.com/unjs/unbuild) works out of the box without configuration. + +Let's add a little script to our `package.json`: + +```json [package.json] +{ + "scripts": { + "build": "unbuild" + } +} +``` + +And create a `src/index.js` file: + +```js [src/index.js] +export function sayFoo() { + console.log('foo') +} +``` + +::alert{type="info"} +It's important to note that we use a `src` folder to store our source code. This is a default behavior of [`unjs/unbuild`](https://github.com/unjs/unbuild) to search for an entrypoint in this folder. +:: + +Now, let's run our build: + +```bash +npm run build +``` + +We expect to have a `dist/index.js` file with the content of `src/index.js` but we got nothing and the output show a dist size of 0 bytes. :thinking: + +::alert{type="info"} +By default, [`unjs/unbuild`](https://github.com/unjs/unbuild) will build package in `dist` folder, even is we specify another location in our `package.json` file. +:: + +```bash +ℹ Automatically detected entries: [esm] +ℹ Building default +✔ Build succeeded for default +Σ Total dist size (byte size): 0 B +``` + +**And that's totally normal!** + +### Setup `package.json` + +[`unjs/unbuild`](https://github.com/unjs/unbuild) exists to allow us to build our package to publish it to npm. So, if our `package.json` is not configured to then be usable by other people, it's useless to build it so [`unjs/unbuild`](https://github.com/unjs/unbuild) does not build it. + +This behavior is very interesting because it allows us to have build warnings when exported files are not present in the build. + +First of all, we need to tell to [`unjs/unbuild`](https://github.com/unjs/unbuild) that our package is an ES module: + +```json [package.json] +{ + "type": "module" +} +``` + +Then, we need to tell him what is exported by our package. In our case, we want to export the `sayFoo` function from `src/index.js`. For a better compatibility, we will build our project to CommonJS and ES module: + +```json [package.json] +{ + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + } + } +} +``` + +We will add a `main` entry point as a fallback for CommonJS users: + +```json [package.json] +{ + "main": "./dist/index.cjs" +} +``` + +Finally, we will tell to `npm` which files we want to publish: + +```json [package.json] +{ + "files": ["dist"] +} +``` + +Now, we can run our build again: + +```bash +npm run build +``` + +And we got our `dist/index.js` file with the content of `src/index.js`: + +```bash +ℹ Automatically detected entries: src/index [esm] [cjs] +ℹ Building default +ℹ Cleaning dist directory: ./dist +✔ Build succeeded for default + dist/index.cjs (total size: 85 B, chunk size: 85 B, exports: sayFoo) + + dist/index.mjs (total size: 64 B, chunk size: 64 B, exports: sayFoo) + +Σ Total dist size (byte size): 149 B +``` + +As expected, we've got our exported files with content from `src/index.js`. :tada: + + +::alert{type="info"} +Read more about [package.json exports](https://nodejs.org/api/packages.html#packages_exports). +:: + +### TypeScript Support + +Out of the box, [`unjs/unbuild`](https://github.com/unjs/unbuild) will support TypeScript. + +Let's rename our `src/index.js` file to `src/index.ts` and add some TypeScript code: + +```ts [src/index.ts] +export function sayFoo() { + console.log('foo') +} +``` + +If we run our build again, everything works as expected but because we're using TypeScript, we want to export the types of our package too. + +To do that, we need to add a `types` entry point to our `package.json` before the key `main`: + +```json [package.json] +{ + "types": "./dist/index.d.ts" // Note that we use `.d.ts` instead of `.mts` +} +``` + +Then, we also need to add `types` to `import` and `require` keys: + +```json [package.json] +{ + "exports": { + ".": { + "import": { + "types": "./dist/index.d.mts", // Note that we use `.d.mts` + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", // Note that we use `.d.cts` + "default": "./dist/index.cjs" + } + } + } +} +``` + +::alert{type="warning"} +The `types` condition should always come first in `exports`. +:: + +Now, everything is well configured and we can run our build again: + +```bash +npm run build +``` + +And we've got a `dist` folder like this: + +```bash +dist +├── index.cjs +├── index.d.cts +├── index.d.mts +├── index.d.ts +└── index.mjs +``` + +Perfect and we're now sure that our package is well configured to be used by other people once published! :ok_hand: + +::alert{type="info"} +Read more about the [TypeScript usage](https://www.typescriptlang.org/docs/handbook/esm-node.html#packagejson-exports-imports-and-self-referencing). +:: + +## Configuration + +Of course, [`unjs/unbuild`](https://github.com/unjs/unbuild) is fully configurable and we will see how to do that. But in most cases, we don't need to configure it or we just need to write some lines! + +To do that, we've just to write a `build.config.ts` at the root of the folder: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({}) +``` + +Starting from now, we must be careful. Adding content to the configuration file will break the infer configuration and it may happen some unexpected behavior. + +### Changing the Output Directory + +Imagine we do not want to publish a `dist` directory but a `output` one, we can simply specify it in our config file: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + outDir: 'output' +}) +``` + +The default value is `dist` whatever is the value defined in our `package.json` file. + +::alert{type="warning"} +We absolutely need to update our paths in our `package.json` file. +:: + +### Adding entries + +`entries` refers to the entrypoint of the compiler. For example, imagine we have a `plugins` folder with `vite.ts` and `webpack.ts` file in it. + +```ts [./src/plugins/vite.ts] +export default function defineVitePlugin() { + console.log('vite') +} +``` + +```ts [./src/plugins/webpack.ts] +export default function defineWebpackPlugin() { + console.log('webpack') +} +``` + +If we build our package, the compiler will totally ignore these files. + +First, we need to add an export option to our `package.json`: + +```json [package.json] +{ + "exports": { + "./plugins/*": { + "import": { + "types": "./dist/*.d.mts", + "default": "./dist/*.mjs" + }, + "require": { + "types": "./dist/*.d.cts", + "default": "./dist/*.cjs" + } + } + } +} +``` + +Then, we will need to tell to [`unjs/unbuild`](https://github.com/unjs/unbuild) to build our plugins. + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + entries: [ + './src/index.ts', // We need to add the default value + './src/plugins/' + ], + declaration: true, // Create `.d.*ts` files. Must be set since we overwrite default configuration. + rollup: { + emitCJS: true, // Create `.cjs` file. Must be set since we overwrite default configuration. + } +}) +``` + +When building our project, we got this structure: + +```bash +dist +├── index.cjs +├── index.d.cts +├── index.d.mts +├── index.d.ts +├── index.mjs +├── vite.d.ts +├── vite.mjs +├── webpack.d.ts +└── webpack.mjs +``` + +Clearly, that's far from ideal since the folder structure is not respected. This can be an issue if some files have the same name. Also, we do not generate Common JS file. + +To fix that, we can personalize the builder used: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + entries: [ + './src/index.ts', + { + builder: 'mkdist', + input: './src/plugins/', + outDir: './dist/plugins/', + } + ], + declaration: true, + rollup: { + emitCJS: true, + } +}) +``` + +And now, we've got this structure: + +```bash +dist +├── index.cjs +├── index.d.cts +├── index.d.mts +├── index.d.ts +├── index.mjs +└── plugins + ├── vite.cjs + ├── vite.d.cts + ├── vite.d.mts + ├── vite.d.ts + ├── vite.mjs + ├── webpack.cjs + ├── webpack.d.cts + ├── webpack.d.mts + ├── webpack.d.ts + └── webpack.mjs +``` + + + +::alert{type="info"} +[`unjs/mkdist`](https://github.com/unjs/mkdist) is a file-to-file transpiler. +:: + +## Using Externals Dependencies + +[`unjs/unbuild`](https://github.com/unjs/unbuild) will use our `package.json` to infer the dependencies to include or not in the build. + +### Dependencies + +By default, all dependencies will stay as external dependencies. This means that they will not be included in the build and the user will need to install them to use our package. + +For example, we can try to use [`unjs/consola`](https://github.com/unjs/consola). First, we can instlal it: + +```bash +npm install consola +``` + +Then, we can use it in our `src/index.ts` file: + +```ts [src/index.ts] +import consola from 'consola' + +export function sayFoo() { + consola.info('foo') +} +``` + +If we run our build and take a look at `dist/index.mjs`, we can see that `consola` is not included in the build: + +```js [dist/index.mjs] +import consola from 'consola' + +function sayFoo() { + consola.info('foo') +} + +export { sayFoo } +``` + +### Dev Dependencies + +By default, all dev dependencies will be included in the build. This means that they will be included in the build and the user will not need to install them to use our package. + +In the same time, [`unjs/unbuild`](https://github.com/unjs/unbuild) will warn us that we should not include dev dependencies in our build and fail to finish the build. + +::alert{type="info"} +We can disable `failOnWarn` to allow the build to finish but it's **not recommended**. +:: + +We can try this behavior by installing [`unjs/scule`](https://github.com/unjs/scule) as a dev dependency: + +```bash +npm install scule --save-dev +``` + +Then, we can use it in our `src/index.ts` file: + +```ts [src/index.ts] +import { camelCase } from 'scule' + +export function sayFoo() { + console.log(camelCase('foo')) +} +``` + +If we build our package, we got this warning: + +```bash + WARN Build is done with some warnings: + +- Inlined implicit external scule +``` + +To deal with that, we have two options: + +- We can explicitly tell to [`unjs/unbuild`](https://github.com/unjs/unbuild) to threat a dev dependency as an external dependency. + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + externals: ['scule'] +}) +``` + +- We can inline dependencies. + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + rollup: { + inlineDependencies: true + } +}) +``` + +Now, if we take a look at `dist/index.mjs`, we can see that `scule` is included in the build. We can search for the function `camelCase` and we can see that it's inlined: + +```js [dist/index.mjs] +function camelCase(string_) { + return lowerFirst(pascalCase(string_)) +} +``` + +In the same time, we got a line in the build log to indicate that `scule` is inlined: + +```bash + 📦 node_modules/.pnpm/scule@1.0.0/node_modules/scule/dist/index.mjs (1.74 kB) +``` + +::alert{type="info"} +Inlining dependencies is a tradeoff since it increase the size of the build and slow down the update (user can manually update a dependency) but it could result in a faster runtime. +:: + +## Stub + +[`unjs/unbuild`](https://github.com/unjs/unbuild) allows us to use a stub to build our package. A stub is a link to the project with [`unjs/jiti`](https://github.com/unjs/jiti) in the middle to compile on the fly. + +It's very useful when we want to test our package or when we work in a monorepo. + +To create a stub, we can pass the option `--stub` to the build command: + +```bash +npm run build -- --stub +``` + +Or we can add it to our `build.config.ts` file: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + stub: true +}) +``` + +To understand what is a stub, we can take a look at the `dist/index.mjs` file. We can see the entry file is load by [`unjs/jiti`](https://github.com/unjs/jiti) and exported from the file. + +## Hooks + +We can easily access to different steps of the build process by using hooks. + +For examples, we can use the `build:done` to log a message when the build is done: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + hooks: { + 'build:done': (ctx) => { + console.log('Build is done!') + } + } +}) +``` + +There is a lot of hooks available: + +- `build:prepare`: Called when the build is prepared before entries are resolved. +- `build:before`: Called before the build start. +- `build:done`: Called when the build is done. + +- `rollup:options`: Called when the rollup options are prepared. +- `rollup:build`: Called when the rollup build is done. +- `rollup:dts:options`: Called when the rollup options for the declaration file are prepared. +- `rollup:dts:build`: Called when the rollup build for the declaration file is done. +- `rollup:done`: Called when the rollup build is done. + +- `mkdist:entries`: Called when the entries for `mkdist` are prepared. +- `mkdist:entry:options`: Called when the options for `mkdist` are prepared. +- `mkdist:entry:build`: Called when the build for `mkdist` is done. +- `mkdist:done`: Called when the build for `mkdist` is done. + +- `untyped:entries`: Called when the entries for `untyped` are prepared. +- `untyped:entry:options`: Called when the options for `untyped` are prepared. +- `untyped:entry:schema`: Called when the schema for `untyped` is prepared. +- `untyped:entry:outputs`: Called when the outputs for `untyped` are prepared. +- `untyped:done`: Called when the build for `untyped` is done. + +## Conclusion + + From df1b8da12d32327a99f49749c921e826e757d3b2 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 17 Sep 2023 20:40:45 +0000 Subject: [PATCH 2/6] [autofix.ci] apply automated fixes --- content/4.resources/1.learn/3.unbuild-101-first-hand.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/4.resources/1.learn/3.unbuild-101-first-hand.md b/content/4.resources/1.learn/3.unbuild-101-first-hand.md index cfb03b6e..49314f89 100644 --- a/content/4.resources/1.learn/3.unbuild-101-first-hand.md +++ b/content/4.resources/1.learn/3.unbuild-101-first-hand.md @@ -160,7 +160,6 @@ And we got our `dist/index.js` file with the content of `src/index.js`: As expected, we've got our exported files with content from `src/index.js`. :tada: - ::alert{type="info"} Read more about [package.json exports](https://nodejs.org/api/packages.html#packages_exports). :: From 42de40d2d6a2b0c20c3d4a8fb24ad466fada097a Mon Sep 17 00:00:00 2001 From: barbapapazes Date: Sun, 5 Nov 2023 22:37:34 +0100 Subject: [PATCH 3/6] chore: save 3.unbuild-101-first-hand.md before correcting --- .../1.learn/3.unbuild-101-first-hand.md | 575 ++++++++++++++++++ 1 file changed, 575 insertions(+) create mode 100644 content/3.resources/1.learn/3.unbuild-101-first-hand.md diff --git a/content/3.resources/1.learn/3.unbuild-101-first-hand.md b/content/3.resources/1.learn/3.unbuild-101-first-hand.md new file mode 100644 index 00000000..95afe12c --- /dev/null +++ b/content/3.resources/1.learn/3.unbuild-101-first-hand.md @@ -0,0 +1,575 @@ +--- +title: unbuild 101 - first hand +description: # add description +authors: + - name: Estéban Soubiran + picture: https://esteban-soubiran.site/esteban.webp + twitter: soubiran_ +packages: + - unbuild +project: # I need to write unbuild example (at least one) +publishedAt: 2023-10-05 +modifiedAt: 2023-10-05 +layout: article +--- + +[unbuild] is a utility package to build packages for npm with zero configuration by default. + + + + + + + + + + +## Installation + +First, let's create a new project: + +```bash +mkdir unbuild-101 +cd unbuild-101 +``` + +::alert{type="info"} +Do not initialize a new project with `npm init` or `yarn init` since we will explore how `unbuild` infer the configuration from `package.json`. +:: + +Then, install [unjs/unbuild](https://github.com/unjs/unbuild): + +```bash +npm install unbuild --save-dev +``` + +We now have a `package.json` file that looks like this: + +```json [package.json] +{ + "devDependencies": { + "unbuild": "^2.0.0" // or the latest version + } +} +``` + +::alert{type="info"} +We can use the package manager of our choice like `npm`, `yarn`, `pnpm` or `bun`. +:: + +## Our First Build + +By default, [unjs/unbuild](https://github.com/unjs/unbuild) works out of the box without configuration by inferring the configuration founded in the `package.json` used by `npm` to publish our package. + +Let's add a little script to our `package.json`: + +```json [package.json] +{ + "scripts": { + "build": "unbuild" + } +} +``` + +And create a `src/index.js` file: + +```js [src/index.js] +export function sayFoo() { + console.log('foo') +} +``` + +::alert{type="info"} +It's important to note that we use a `src` folder to store our source code. This is a default behavior of [unjs/unbuild](https://github.com/unjs/unbuild) to search for an entrypoint in this folder. +:: + +Now, let's run our build: + +```bash +npm run build +``` + +We expect to have a `dist/index.js` file with the content of `src/index.js` but we got nothing and the output show a dist size of 0 bytes. :thinking: + +::alert{type="info"} +By default, [unjs/unbuild](https://github.com/unjs/unbuild) will build package in `dist` folder, even is we specify another location in our `package.json` file. +:: + +```bash +ℹ Automatically detected entries: [esm] +ℹ Building default +✔ Build succeeded for default +Σ Total dist size (byte size): 0 B +``` + +**And that's totally normal!** + +### Setup `package.json` + +[unjs/unbuild](https://github.com/unjs/unbuild) exists to allow us to build our package to publish it to npm. So, if our `package.json` is not configured to then be usable by other people, it's useless to build it so [unjs/unbuild](https://github.com/unjs/unbuild) does not build it. + +This behavior is very interesting because it allows us to have build warnings when exported files are not present in the build. + +First of all, we need to tell to [unjs/unbuild](https://github.com/unjs/unbuild) that our package is an ES module: + +```json [package.json] +{ + "type": "module" +} +``` + +Then, we need to tell him what is exported by our package. In our case, we want to export the `sayFoo` function from `src/index.js`. For a better compatibility, we will build our project to CommonJS and ES module: + +```json [package.json] +{ + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + } + } +} +``` + +We will add a `main` entry point as a fallback for CommonJS users: + +```json [package.json] +{ + "main": "./dist/index.cjs" +} +``` + +Finally, we will tell to `npm` which files we want to publish: + +```json [package.json] +{ + "files": ["dist"] +} +``` + +Now, we can run our build again: + +```bash +npm run build +``` + +And we got our `dist/index.js` file with the content of `src/index.js`: + +```bash +ℹ Automatically detected entries: src/index [esm] [cjs] +ℹ Building default +ℹ Cleaning dist directory: ./dist +✔ Build succeeded for default + dist/index.cjs (total size: 85 B, chunk size: 85 B, exports: sayFoo) + + dist/index.mjs (total size: 64 B, chunk size: 64 B, exports: sayFoo) + +Σ Total dist size (byte size): 149 B +``` + +As expected, we've got our exported files with content from `src/index.js`. :tada: + +::alert{type="info"} +Read more about [package.json exports](https://nodejs.org/api/packages.html#packages_exports). +:: + +### TypeScript Support + +Out of the box, [unjs/unbuild](https://github.com/unjs/unbuild) will support TypeScript. + +Let's rename our `src/index.js` file to `src/index.ts` and add some TypeScript code: + +```ts [src/index.ts] +export function sayFoo() { + console.log('foo') +} +``` + +If we run our build again, everything works as expected but because we're using TypeScript, we want to export the types of our package too. + +To do that, we need to add a `types` entry point to our `package.json` before the key `main`: + +```json [package.json] +{ + "types": "./dist/index.d.ts" // Note that we use `.d.ts` instead of `.mts` +} +``` + +Then, we also need to add `types` to `import` and `require` keys: + +```json [package.json] +{ + "exports": { + ".": { + "import": { + "types": "./dist/index.d.mts", // Note that we use `.d.mts` + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", // Note that we use `.d.cts` + "default": "./dist/index.cjs" + } + } + } +} +``` + +::alert{type="warning"} +The `types` condition should always come first in `exports`. +:: + +Now, everything is well configured and we can run our build again: + +```bash +npm run build +``` + +And we've got a `dist` folder like this: + +```bash +dist +├── index.cjs +├── index.d.cts +├── index.d.mts +├── index.d.ts +└── index.mjs +``` + +Perfect and we're now sure that our package is well configured to be used by other people once published! :ok_hand: + +::alert{type="info"} +Read more about the [TypeScript usage](https://www.typescriptlang.org/docs/handbook/esm-node.html#packagejson-exports-imports-and-self-referencing). +:: + +## Configuration + +Of course, [unjs/unbuild](https://github.com/unjs/unbuild) is fully configurable and we will see how to do that. But in most cases, we don't need to configure it or we just need to write some lines! + +To do that, we've just to write a `build.config.ts` at the root of the folder: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({}) +``` + +Starting from now, we must be careful. Adding content to the configuration file will break the infer configuration and it may happen some unexpected behavior. + +### Changing the Output Directory + +Imagine we do not want to publish a `dist` directory but a `output` one, we can simply specify it in our config file: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + outDir: 'output' +}) +``` + +The default value is `dist` whatever is the value defined in our `package.json` file. + +::alert{type="warning"} +We absolutely need to update our paths in our `package.json` file. +:: + +### Adding entries + +`entries` refers to the entrypoint of the compiler. For example, imagine we have a `plugins` folder with `vite.ts` and `webpack.ts` file in it. + +```ts [./src/plugins/vite.ts] +export default function defineVitePlugin() { + console.log('vite') +} +``` + +```ts [./src/plugins/webpack.ts] +export default function defineWebpackPlugin() { + console.log('webpack') +} +``` + +If we build our package, the compiler will totally ignore these files. + +First, we need to add an export option to our `package.json`: + +```json [package.json] +{ + "exports": { + "./plugins/*": { + "import": { + "types": "./dist/*.d.mts", + "default": "./dist/*.mjs" + }, + "require": { + "types": "./dist/*.d.cts", + "default": "./dist/*.cjs" + } + } + } +} +``` + +Then, we will need to tell to [unjs/unbuild](https://github.com/unjs/unbuild) to build our plugins. + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + entries: [ + './src/index.ts', // We need to add the default value + './src/plugins/' + ], + declaration: true, // Create `.d.*ts` files. Must be set since we overwrite default configuration. + rollup: { + emitCJS: true, // Create `.cjs` file. Must be set since we overwrite default configuration. + } +}) +``` + +When building our project, we got this structure: + +```bash +dist +├── index.cjs +├── index.d.cts +├── index.d.mts +├── index.d.ts +├── index.mjs +├── vite.d.ts +├── vite.mjs +├── webpack.d.ts +└── webpack.mjs +``` + +Clearly, that's far from ideal since the folder structure is not respected. This can be an issue if some files have the same name. Also, we do not generate Common JS file. + +To fix that, we can personalize the builder used: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + entries: [ + './src/index.ts', + { + builder: 'mkdist', + input: './src/plugins/', + outDir: './dist/plugins/', + } + ], + declaration: true, + rollup: { + emitCJS: true, + } +}) +``` + +And now, we've got this structure: + +```bash +dist +├── index.cjs +├── index.d.cts +├── index.d.mts +├── index.d.ts +├── index.mjs +└── plugins + ├── vite.cjs + ├── vite.d.cts + ├── vite.d.mts + ├── vite.d.ts + ├── vite.mjs + ├── webpack.cjs + ├── webpack.d.cts + ├── webpack.d.mts + ├── webpack.d.ts + └── webpack.mjs +``` + + + +::alert{type="info"} +[`unjs/mkdist`](https://github.com/unjs/mkdist) is a file-to-file transpiler. +:: + +## Using Externals Dependencies + +[unjs/unbuild](https://github.com/unjs/unbuild) will use our `package.json` to infer the dependencies to include or not in the build. + +### Dependencies + +By default, all dependencies will stay as external dependencies. This means that they will not be included in the build and the user will need to install them to use our package. + +For example, we can try to use [`unjs/consola`](https://github.com/unjs/consola). First, we can instlal it: + +```bash +npm install consola +``` + +Then, we can use it in our `src/index.ts` file: + +```ts [src/index.ts] +import consola from 'consola' + +export function sayFoo() { + consola.info('foo') +} +``` + +If we run our build and take a look at `dist/index.mjs`, we can see that `consola` is not included in the build: + +```js [dist/index.mjs] +import consola from 'consola' + +function sayFoo() { + consola.info('foo') +} + +export { sayFoo } +``` + +### Dev Dependencies + +By default, all dev dependencies will be included in the build. This means that they will be included in the build and the user will not need to install them to use our package. + +In the same time, [unjs/unbuild](https://github.com/unjs/unbuild) will warn us that we should not include dev dependencies in our build and fail to finish the build. + +::alert{type="info"} +We can disable `failOnWarn` to allow the build to finish but it's **not recommended**. +:: + +We can try this behavior by installing [`unjs/scule`](https://github.com/unjs/scule) as a dev dependency: + +```bash +npm install scule --save-dev +``` + +Then, we can use it in our `src/index.ts` file: + +```ts [src/index.ts] +import { camelCase } from 'scule' + +export function sayFoo() { + console.log(camelCase('foo')) +} +``` + +If we build our package, we got this warning: + +```bash + WARN Build is done with some warnings: + +- Inlined implicit external scule +``` + +To deal with that, we have two options: + +- We can explicitly tell to [unjs/unbuild](https://github.com/unjs/unbuild) to threat a dev dependency as an external dependency. + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + externals: ['scule'] +}) +``` + +- We can inline dependencies. + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + rollup: { + inlineDependencies: true + } +}) +``` + +Now, if we take a look at `dist/index.mjs`, we can see that `scule` is included in the build. We can search for the function `camelCase` and we can see that it's inlined: + +```js [dist/index.mjs] +function camelCase(string_) { + return lowerFirst(pascalCase(string_)) +} +``` + +In the same time, we got a line in the build log to indicate that `scule` is inlined: + +```bash + 📦 node_modules/.pnpm/scule@1.0.0/node_modules/scule/dist/index.mjs (1.74 kB) +``` + +::alert{type="info"} +Inlining dependencies is a tradeoff since it increase the size of the build and slow down the update (user can manually update a dependency) but it could result in a faster runtime. +:: + +## Stub + +[unjs/unbuild](https://github.com/unjs/unbuild) allows us to use a stub to build our package. A stub is a link to the project with [`unjs/jiti`](https://github.com/unjs/jiti) in the middle to compile on the fly. + +It's very useful when we want to test our package or when we work in a monorepo. + +To create a stub, we can pass the option `--stub` to the build command: + +```bash +npm run build -- --stub +``` + +Or we can add it to our `build.config.ts` file: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + stub: true +}) +``` + +To understand what is a stub, we can take a look at the `dist/index.mjs` file. We can see the entry file is load by [`unjs/jiti`](https://github.com/unjs/jiti) and exported from the file. + +## Hooks + +We can easily access to different steps of the build process by using hooks. + +For examples, we can use the `build:done` to log a message when the build is done: + +```ts [build.config.ts] +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + hooks: { + 'build:done': (ctx) => { + console.log('Build is done!') + } + } +}) +``` + +There is a lot of hooks available: + +- `build:prepare`: Called when the build is prepared before entries are resolved. +- `build:before`: Called before the build start. +- `build:done`: Called when the build is done. + +- `rollup:options`: Called when the rollup options are prepared. +- `rollup:build`: Called when the rollup build is done. +- `rollup:dts:options`: Called when the rollup options for the declaration file are prepared. +- `rollup:dts:build`: Called when the rollup build for the declaration file is done. +- `rollup:done`: Called when the rollup build is done. + +- `mkdist:entries`: Called when the entries for `mkdist` are prepared. +- `mkdist:entry:options`: Called when the options for `mkdist` are prepared. +- `mkdist:entry:build`: Called when the build for `mkdist` is done. +- `mkdist:done`: Called when the build for `mkdist` is done. + +- `untyped:entries`: Called when the entries for `untyped` are prepared. +- `untyped:entry:options`: Called when the options for `untyped` are prepared. +- `untyped:entry:schema`: Called when the schema for `untyped` is prepared. +- `untyped:entry:outputs`: Called when the outputs for `untyped` are prepared. +- `untyped:done`: Called when the build for `untyped` is done. + +## Conclusion + + From b3596b0bd011c9c2fe4b53996b37556dc2f44a97 Mon Sep 17 00:00:00 2001 From: barbapapazes Date: Mon, 6 Nov 2023 14:49:54 +0100 Subject: [PATCH 4/6] content: update unbuild --- .../1.learn/3.unbuild-101-first-hand.md | 63 +- .../1.learn/3.unbuild-101-first-hand.md | 566 ------------------ 2 files changed, 34 insertions(+), 595 deletions(-) delete mode 100644 content/4.resources/1.learn/3.unbuild-101-first-hand.md diff --git a/content/3.resources/1.learn/3.unbuild-101-first-hand.md b/content/3.resources/1.learn/3.unbuild-101-first-hand.md index 95afe12c..a60231ee 100644 --- a/content/3.resources/1.learn/3.unbuild-101-first-hand.md +++ b/content/3.resources/1.learn/3.unbuild-101-first-hand.md @@ -15,14 +15,19 @@ layout: article [unbuild] is a utility package to build packages for npm with zero configuration by default. - + - + - - + + + + - + ## Installation @@ -34,7 +39,7 @@ cd unbuild-101 ``` ::alert{type="info"} -Do not initialize a new project with `npm init` or `yarn init` since we will explore how `unbuild` infer the configuration from `package.json`. +Do not initialize a new project with `npm init` or `yarn init` since we will explore how `unbuild` infers the configuration from `package.json`. :: Then, install [unjs/unbuild](https://github.com/unjs/unbuild): @@ -59,7 +64,7 @@ We can use the package manager of our choice like `npm`, `yarn`, `pnpm` or `bun` ## Our First Build -By default, [unjs/unbuild](https://github.com/unjs/unbuild) works out of the box without configuration by inferring the configuration founded in the `package.json` used by `npm` to publish our package. +By default, [unjs/unbuild](https://github.com/unjs/unbuild) works out of the box without configuration by inferring the configuration found in the `package.json` used by `npm` to publish our package. Let's add a little script to our `package.json`: @@ -89,10 +94,10 @@ Now, let's run our build: npm run build ``` -We expect to have a `dist/index.js` file with the content of `src/index.js` but we got nothing and the output show a dist size of 0 bytes. :thinking: +We expect to have a `dist/index.js` file with the contents of `src/index.js` but we got nothing and the output shows a dist size of 0 bytes. :thinking: ::alert{type="info"} -By default, [unjs/unbuild](https://github.com/unjs/unbuild) will build package in `dist` folder, even is we specify another location in our `package.json` file. +By default, [unjs/unbuild](https://github.com/unjs/unbuild) will build the package in the `dist` folder, even if we specify another location in our `package.json` file. :: ```bash @@ -106,11 +111,11 @@ By default, [unjs/unbuild](https://github.com/unjs/unbuild) will build package i ### Setup `package.json` -[unjs/unbuild](https://github.com/unjs/unbuild) exists to allow us to build our package to publish it to npm. So, if our `package.json` is not configured to then be usable by other people, it's useless to build it so [unjs/unbuild](https://github.com/unjs/unbuild) does not build it. +[unjs/unbuild](https://github.com/unjs/unbuild) exists to allow us to build our package to publish it to npm. So, if our `package.json` is not configured to be then usable by other people, it's useless to build it so [unjs/unbuild](https://github.com/unjs/unbuild) does not build it. This behavior is very interesting because it allows us to have build warnings when exported files are not present in the build. -First of all, we need to tell to [unjs/unbuild](https://github.com/unjs/unbuild) that our package is an ES module: +First of all, we need to tell [unjs/unbuild](https://github.com/unjs/unbuild) that our package is an ES module: ```json [package.json] { @@ -118,7 +123,7 @@ First of all, we need to tell to [unjs/unbuild](https://github.com/unjs/unbuild) } ``` -Then, we need to tell him what is exported by our package. In our case, we want to export the `sayFoo` function from `src/index.js`. For a better compatibility, we will build our project to CommonJS and ES module: +Then, we need to tell him what is exported by our package. In our case, we want to export the `sayFoo` function from `src/index.js`. For better compatibility, we will build our project to CommonJS and ES module: ```json [package.json] { @@ -139,7 +144,7 @@ We will add a `main` entry point as a fallback for CommonJS users: } ``` -Finally, we will tell to `npm` which files we want to publish: +Finally, we will tell `npm` which files we want to publish: ```json [package.json] { @@ -195,7 +200,7 @@ To do that, we need to add a `types` entry point to our `package.json` before th } ``` -Then, we also need to add `types` to `import` and `require` keys: +Then, we also need to add `types` to the `import` and `require` keys: ```json [package.json] { @@ -257,7 +262,7 @@ Starting from now, we must be careful. Adding content to the configuration file ### Changing the Output Directory -Imagine we do not want to publish a `dist` directory but a `output` one, we can simply specify it in our config file: +Imagine we do not want to publish a `dist` directory but an `output` one, we can simply specify it in our config file: ```ts [build.config.ts] import { defineBuildConfig } from 'unbuild' @@ -455,17 +460,17 @@ export function sayFoo() { } ``` -If we build our package, we got this warning: +If we build our package, we get this warning: ```bash - WARN Build is done with some warnings: +WARN Build is done with some warnings: - Inlined implicit external scule ``` To deal with that, we have two options: -- We can explicitly tell to [unjs/unbuild](https://github.com/unjs/unbuild) to threat a dev dependency as an external dependency. +- We can explicitly tell [unjs/unbuild](https://github.com/unjs/unbuild) to treat a dev dependency as an external dependency. ```ts [build.config.ts] import { defineBuildConfig } from 'unbuild' @@ -487,22 +492,22 @@ export default defineBuildConfig({ }) ``` -Now, if we take a look at `dist/index.mjs`, we can see that `scule` is included in the build. We can search for the function `camelCase` and we can see that it's inlined: +Now, if we take a look at `dist/index.mjs`, we can see that `scule` is included in the build. We can search for the function `camelCase`, and we can see that it's inlined: ```js [dist/index.mjs] function camelCase(string_) { - return lowerFirst(pascalCase(string_)) + return lowerFirst(pascalCase(string_)); } ``` -In the same time, we got a line in the build log to indicate that `scule` is inlined: +At the same time, we have a line in the build log to indicate that `scule` is inlined: ```bash - 📦 node_modules/.pnpm/scule@1.0.0/node_modules/scule/dist/index.mjs (1.74 kB) +📦 node_modules/.pnpm/scule@1.0.0/node_modules/scule/dist/index.mjs (1.74 kB) ``` ::alert{type="info"} -Inlining dependencies is a tradeoff since it increase the size of the build and slow down the update (user can manually update a dependency) but it could result in a faster runtime. +Inlining dependencies is a tradeoff since it increases the size of the build and slows down the update (users can manually update a dependency), but it could result in a faster runtime. :: ## Stub @@ -527,13 +532,13 @@ export default defineBuildConfig({ }) ``` -To understand what is a stub, we can take a look at the `dist/index.mjs` file. We can see the entry file is load by [`unjs/jiti`](https://github.com/unjs/jiti) and exported from the file. +To understand what a stub is, we can take a look at the `dist/index.mjs` file. We can see that the entry file is loaded by [`unjs/jiti`](https://github.com/unjs/jiti) and exported from the file. ## Hooks -We can easily access to different steps of the build process by using hooks. +We can easily access different steps of the build process by using hooks. -For examples, we can use the `build:done` to log a message when the build is done: +For example, we can use the `build:done` hook to log a message when the build is done: ```ts [build.config.ts] import { defineBuildConfig } from 'unbuild' @@ -547,10 +552,10 @@ export default defineBuildConfig({ }) ``` -There is a lot of hooks available: +There are a lot of hooks available: - `build:prepare`: Called when the build is prepared before entries are resolved. -- `build:before`: Called before the build start. +- `build:before`: Called before the build starts. - `build:done`: Called when the build is done. - `rollup:options`: Called when the rollup options are prepared. @@ -572,4 +577,4 @@ There is a lot of hooks available: ## Conclusion - + diff --git a/content/4.resources/1.learn/3.unbuild-101-first-hand.md b/content/4.resources/1.learn/3.unbuild-101-first-hand.md deleted file mode 100644 index 49314f89..00000000 --- a/content/4.resources/1.learn/3.unbuild-101-first-hand.md +++ /dev/null @@ -1,566 +0,0 @@ ---- -title: unbuild 101 - first hand -description: -authors: - - name: Estéban Soubiran - picture: https://esteban-soubiran.site/esteban.webp - twitter: soubiran_ -packages: - - unbuild -publishedAt: 2023-09-12 -modifiedAt: 2023-09-12 -layout: learn-post ---- - - - - -## Installation - -First, let's create a new project: - -```bash -mkdir unbuild-101 -cd unbuild-101 -``` - -::alert{type="info"} -Do not initialize a new project with `npm init` or `yarn init` since we will explore how `unbuild` infer the configuration from `package.json`. -:: - -Then, install [`unjs/unbuild`](https://github.com/unjs/unbuild): - -```bash -npm install unbuild --save-dev -``` - -We now have a `package.json` file that looks like this: - -```json [package.json] -{ - "devDependencies": { - "unbuild": "^2.0.0" // or version could differ - } -} -``` - -::alert{type="info"} -We can use the package manager of our choice like `npm`, `yarn`, `pnpm` or `bun`. -:: - -## Our First Build - -By default, [`unjs/unbuild`](https://github.com/unjs/unbuild) works out of the box without configuration. - -Let's add a little script to our `package.json`: - -```json [package.json] -{ - "scripts": { - "build": "unbuild" - } -} -``` - -And create a `src/index.js` file: - -```js [src/index.js] -export function sayFoo() { - console.log('foo') -} -``` - -::alert{type="info"} -It's important to note that we use a `src` folder to store our source code. This is a default behavior of [`unjs/unbuild`](https://github.com/unjs/unbuild) to search for an entrypoint in this folder. -:: - -Now, let's run our build: - -```bash -npm run build -``` - -We expect to have a `dist/index.js` file with the content of `src/index.js` but we got nothing and the output show a dist size of 0 bytes. :thinking: - -::alert{type="info"} -By default, [`unjs/unbuild`](https://github.com/unjs/unbuild) will build package in `dist` folder, even is we specify another location in our `package.json` file. -:: - -```bash -ℹ Automatically detected entries: [esm] -ℹ Building default -✔ Build succeeded for default -Σ Total dist size (byte size): 0 B -``` - -**And that's totally normal!** - -### Setup `package.json` - -[`unjs/unbuild`](https://github.com/unjs/unbuild) exists to allow us to build our package to publish it to npm. So, if our `package.json` is not configured to then be usable by other people, it's useless to build it so [`unjs/unbuild`](https://github.com/unjs/unbuild) does not build it. - -This behavior is very interesting because it allows us to have build warnings when exported files are not present in the build. - -First of all, we need to tell to [`unjs/unbuild`](https://github.com/unjs/unbuild) that our package is an ES module: - -```json [package.json] -{ - "type": "module" -} -``` - -Then, we need to tell him what is exported by our package. In our case, we want to export the `sayFoo` function from `src/index.js`. For a better compatibility, we will build our project to CommonJS and ES module: - -```json [package.json] -{ - "exports": { - ".": { - "import": "./dist/index.mjs", - "require": "./dist/index.cjs" - } - } -} -``` - -We will add a `main` entry point as a fallback for CommonJS users: - -```json [package.json] -{ - "main": "./dist/index.cjs" -} -``` - -Finally, we will tell to `npm` which files we want to publish: - -```json [package.json] -{ - "files": ["dist"] -} -``` - -Now, we can run our build again: - -```bash -npm run build -``` - -And we got our `dist/index.js` file with the content of `src/index.js`: - -```bash -ℹ Automatically detected entries: src/index [esm] [cjs] -ℹ Building default -ℹ Cleaning dist directory: ./dist -✔ Build succeeded for default - dist/index.cjs (total size: 85 B, chunk size: 85 B, exports: sayFoo) - - dist/index.mjs (total size: 64 B, chunk size: 64 B, exports: sayFoo) - -Σ Total dist size (byte size): 149 B -``` - -As expected, we've got our exported files with content from `src/index.js`. :tada: - -::alert{type="info"} -Read more about [package.json exports](https://nodejs.org/api/packages.html#packages_exports). -:: - -### TypeScript Support - -Out of the box, [`unjs/unbuild`](https://github.com/unjs/unbuild) will support TypeScript. - -Let's rename our `src/index.js` file to `src/index.ts` and add some TypeScript code: - -```ts [src/index.ts] -export function sayFoo() { - console.log('foo') -} -``` - -If we run our build again, everything works as expected but because we're using TypeScript, we want to export the types of our package too. - -To do that, we need to add a `types` entry point to our `package.json` before the key `main`: - -```json [package.json] -{ - "types": "./dist/index.d.ts" // Note that we use `.d.ts` instead of `.mts` -} -``` - -Then, we also need to add `types` to `import` and `require` keys: - -```json [package.json] -{ - "exports": { - ".": { - "import": { - "types": "./dist/index.d.mts", // Note that we use `.d.mts` - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.cts", // Note that we use `.d.cts` - "default": "./dist/index.cjs" - } - } - } -} -``` - -::alert{type="warning"} -The `types` condition should always come first in `exports`. -:: - -Now, everything is well configured and we can run our build again: - -```bash -npm run build -``` - -And we've got a `dist` folder like this: - -```bash -dist -├── index.cjs -├── index.d.cts -├── index.d.mts -├── index.d.ts -└── index.mjs -``` - -Perfect and we're now sure that our package is well configured to be used by other people once published! :ok_hand: - -::alert{type="info"} -Read more about the [TypeScript usage](https://www.typescriptlang.org/docs/handbook/esm-node.html#packagejson-exports-imports-and-self-referencing). -:: - -## Configuration - -Of course, [`unjs/unbuild`](https://github.com/unjs/unbuild) is fully configurable and we will see how to do that. But in most cases, we don't need to configure it or we just need to write some lines! - -To do that, we've just to write a `build.config.ts` at the root of the folder: - -```ts [build.config.ts] -import { defineBuildConfig } from 'unbuild' - -export default defineBuildConfig({}) -``` - -Starting from now, we must be careful. Adding content to the configuration file will break the infer configuration and it may happen some unexpected behavior. - -### Changing the Output Directory - -Imagine we do not want to publish a `dist` directory but a `output` one, we can simply specify it in our config file: - -```ts [build.config.ts] -import { defineBuildConfig } from 'unbuild' - -export default defineBuildConfig({ - outDir: 'output' -}) -``` - -The default value is `dist` whatever is the value defined in our `package.json` file. - -::alert{type="warning"} -We absolutely need to update our paths in our `package.json` file. -:: - -### Adding entries - -`entries` refers to the entrypoint of the compiler. For example, imagine we have a `plugins` folder with `vite.ts` and `webpack.ts` file in it. - -```ts [./src/plugins/vite.ts] -export default function defineVitePlugin() { - console.log('vite') -} -``` - -```ts [./src/plugins/webpack.ts] -export default function defineWebpackPlugin() { - console.log('webpack') -} -``` - -If we build our package, the compiler will totally ignore these files. - -First, we need to add an export option to our `package.json`: - -```json [package.json] -{ - "exports": { - "./plugins/*": { - "import": { - "types": "./dist/*.d.mts", - "default": "./dist/*.mjs" - }, - "require": { - "types": "./dist/*.d.cts", - "default": "./dist/*.cjs" - } - } - } -} -``` - -Then, we will need to tell to [`unjs/unbuild`](https://github.com/unjs/unbuild) to build our plugins. - -```ts [build.config.ts] -import { defineBuildConfig } from 'unbuild' - -export default defineBuildConfig({ - entries: [ - './src/index.ts', // We need to add the default value - './src/plugins/' - ], - declaration: true, // Create `.d.*ts` files. Must be set since we overwrite default configuration. - rollup: { - emitCJS: true, // Create `.cjs` file. Must be set since we overwrite default configuration. - } -}) -``` - -When building our project, we got this structure: - -```bash -dist -├── index.cjs -├── index.d.cts -├── index.d.mts -├── index.d.ts -├── index.mjs -├── vite.d.ts -├── vite.mjs -├── webpack.d.ts -└── webpack.mjs -``` - -Clearly, that's far from ideal since the folder structure is not respected. This can be an issue if some files have the same name. Also, we do not generate Common JS file. - -To fix that, we can personalize the builder used: - -```ts [build.config.ts] -import { defineBuildConfig } from 'unbuild' - -export default defineBuildConfig({ - entries: [ - './src/index.ts', - { - builder: 'mkdist', - input: './src/plugins/', - outDir: './dist/plugins/', - } - ], - declaration: true, - rollup: { - emitCJS: true, - } -}) -``` - -And now, we've got this structure: - -```bash -dist -├── index.cjs -├── index.d.cts -├── index.d.mts -├── index.d.ts -├── index.mjs -└── plugins - ├── vite.cjs - ├── vite.d.cts - ├── vite.d.mts - ├── vite.d.ts - ├── vite.mjs - ├── webpack.cjs - ├── webpack.d.cts - ├── webpack.d.mts - ├── webpack.d.ts - └── webpack.mjs -``` - - - -::alert{type="info"} -[`unjs/mkdist`](https://github.com/unjs/mkdist) is a file-to-file transpiler. -:: - -## Using Externals Dependencies - -[`unjs/unbuild`](https://github.com/unjs/unbuild) will use our `package.json` to infer the dependencies to include or not in the build. - -### Dependencies - -By default, all dependencies will stay as external dependencies. This means that they will not be included in the build and the user will need to install them to use our package. - -For example, we can try to use [`unjs/consola`](https://github.com/unjs/consola). First, we can instlal it: - -```bash -npm install consola -``` - -Then, we can use it in our `src/index.ts` file: - -```ts [src/index.ts] -import consola from 'consola' - -export function sayFoo() { - consola.info('foo') -} -``` - -If we run our build and take a look at `dist/index.mjs`, we can see that `consola` is not included in the build: - -```js [dist/index.mjs] -import consola from 'consola' - -function sayFoo() { - consola.info('foo') -} - -export { sayFoo } -``` - -### Dev Dependencies - -By default, all dev dependencies will be included in the build. This means that they will be included in the build and the user will not need to install them to use our package. - -In the same time, [`unjs/unbuild`](https://github.com/unjs/unbuild) will warn us that we should not include dev dependencies in our build and fail to finish the build. - -::alert{type="info"} -We can disable `failOnWarn` to allow the build to finish but it's **not recommended**. -:: - -We can try this behavior by installing [`unjs/scule`](https://github.com/unjs/scule) as a dev dependency: - -```bash -npm install scule --save-dev -``` - -Then, we can use it in our `src/index.ts` file: - -```ts [src/index.ts] -import { camelCase } from 'scule' - -export function sayFoo() { - console.log(camelCase('foo')) -} -``` - -If we build our package, we got this warning: - -```bash - WARN Build is done with some warnings: - -- Inlined implicit external scule -``` - -To deal with that, we have two options: - -- We can explicitly tell to [`unjs/unbuild`](https://github.com/unjs/unbuild) to threat a dev dependency as an external dependency. - -```ts [build.config.ts] -import { defineBuildConfig } from 'unbuild' - -export default defineBuildConfig({ - externals: ['scule'] -}) -``` - -- We can inline dependencies. - -```ts [build.config.ts] -import { defineBuildConfig } from 'unbuild' - -export default defineBuildConfig({ - rollup: { - inlineDependencies: true - } -}) -``` - -Now, if we take a look at `dist/index.mjs`, we can see that `scule` is included in the build. We can search for the function `camelCase` and we can see that it's inlined: - -```js [dist/index.mjs] -function camelCase(string_) { - return lowerFirst(pascalCase(string_)) -} -``` - -In the same time, we got a line in the build log to indicate that `scule` is inlined: - -```bash - 📦 node_modules/.pnpm/scule@1.0.0/node_modules/scule/dist/index.mjs (1.74 kB) -``` - -::alert{type="info"} -Inlining dependencies is a tradeoff since it increase the size of the build and slow down the update (user can manually update a dependency) but it could result in a faster runtime. -:: - -## Stub - -[`unjs/unbuild`](https://github.com/unjs/unbuild) allows us to use a stub to build our package. A stub is a link to the project with [`unjs/jiti`](https://github.com/unjs/jiti) in the middle to compile on the fly. - -It's very useful when we want to test our package or when we work in a monorepo. - -To create a stub, we can pass the option `--stub` to the build command: - -```bash -npm run build -- --stub -``` - -Or we can add it to our `build.config.ts` file: - -```ts [build.config.ts] -import { defineBuildConfig } from 'unbuild' - -export default defineBuildConfig({ - stub: true -}) -``` - -To understand what is a stub, we can take a look at the `dist/index.mjs` file. We can see the entry file is load by [`unjs/jiti`](https://github.com/unjs/jiti) and exported from the file. - -## Hooks - -We can easily access to different steps of the build process by using hooks. - -For examples, we can use the `build:done` to log a message when the build is done: - -```ts [build.config.ts] -import { defineBuildConfig } from 'unbuild' - -export default defineBuildConfig({ - hooks: { - 'build:done': (ctx) => { - console.log('Build is done!') - } - } -}) -``` - -There is a lot of hooks available: - -- `build:prepare`: Called when the build is prepared before entries are resolved. -- `build:before`: Called before the build start. -- `build:done`: Called when the build is done. - -- `rollup:options`: Called when the rollup options are prepared. -- `rollup:build`: Called when the rollup build is done. -- `rollup:dts:options`: Called when the rollup options for the declaration file are prepared. -- `rollup:dts:build`: Called when the rollup build for the declaration file is done. -- `rollup:done`: Called when the rollup build is done. - -- `mkdist:entries`: Called when the entries for `mkdist` are prepared. -- `mkdist:entry:options`: Called when the options for `mkdist` are prepared. -- `mkdist:entry:build`: Called when the build for `mkdist` is done. -- `mkdist:done`: Called when the build for `mkdist` is done. - -- `untyped:entries`: Called when the entries for `untyped` are prepared. -- `untyped:entry:options`: Called when the options for `untyped` are prepared. -- `untyped:entry:schema`: Called when the schema for `untyped` is prepared. -- `untyped:entry:outputs`: Called when the outputs for `untyped` are prepared. -- `untyped:done`: Called when the build for `untyped` is done. - -## Conclusion - - From 572808641814d25aa96b6d05b5c58466f1806fde Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 13:50:53 +0000 Subject: [PATCH 5/6] [autofix.ci] apply automated fixes --- content/3.resources/1.learn/3.unbuild-101-first-hand.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/3.resources/1.learn/3.unbuild-101-first-hand.md b/content/3.resources/1.learn/3.unbuild-101-first-hand.md index a60231ee..9e83c059 100644 --- a/content/3.resources/1.learn/3.unbuild-101-first-hand.md +++ b/content/3.resources/1.learn/3.unbuild-101-first-hand.md @@ -496,7 +496,7 @@ Now, if we take a look at `dist/index.mjs`, we can see that `scule` is included ```js [dist/index.mjs] function camelCase(string_) { - return lowerFirst(pascalCase(string_)); + return lowerFirst(pascalCase(string_)) } ``` From 99bcd5e2fd31d44b9420198babcfe3998b62983a Mon Sep 17 00:00:00 2001 From: barbapapazes Date: Mon, 6 Nov 2023 22:40:06 +0100 Subject: [PATCH 6/6] content: add intro and conclusion to unbuild --- .../1.learn/3.unbuild-101-first-hand.md | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/content/3.resources/1.learn/3.unbuild-101-first-hand.md b/content/3.resources/1.learn/3.unbuild-101-first-hand.md index 9e83c059..b8d47939 100644 --- a/content/3.resources/1.learn/3.unbuild-101-first-hand.md +++ b/content/3.resources/1.learn/3.unbuild-101-first-hand.md @@ -1,33 +1,21 @@ --- title: unbuild 101 - first hand -description: # add description +description: A zero-config utility that simplifies npm package builds by automatically generating commonjs, esm, and declaration files from TypeScript, with security checks and customization hooks, based on rollup and mkdist. authors: - name: Estéban Soubiran picture: https://esteban-soubiran.site/esteban.webp twitter: soubiran_ packages: - unbuild -project: # I need to write unbuild example (at least one) +project: # https://github.com/unjs/unbuild/tree/main/examples publishedAt: 2023-10-05 modifiedAt: 2023-10-05 layout: article --- -[unbuild] is a utility package to build packages for npm with zero configuration by default. +[unbuild](https://unbuild.unjs.io) is a utility package to build packages for npm with zero configuration by default by inferring the configuration from your `package.json` file. It takes your TypeScript code to generate commonjs, esm and declaration files. - - - - - - - - - - +It's built on top of [rollup](https://rollupjs.org/) and [mkdist](https://mkdist.unjs.io/), have a passive watcher and a lot of hooks to customize the build. At the same time, it create secure builds by checking various build issues such as potential missing and unused dependencies. ## Installation @@ -577,4 +565,4 @@ There are a lot of hooks available: ## Conclusion - +Finally, unbuild offers a versatile and efficient solution for building npm packages with minimal configuration. By leveraging rollup and mkdist, it streamlines the process of transpiling TypeScript into usable formats for npm distribution, ensuring a smooth workflow for developers. It automatically generates commonjs, esm, and declaration files, and provides security checks to prevent build issues. Its passive watcher and customizable hooks further enhance the developer experience, making it an excellent tool for modern package development. With its ability to infer settings from `package.json` and support for TypeScript out of the box, unbuild simplifies the build process, allowing developers to focus on their code rather than build configurations.