|
| 1 | +# Files in `dist` |
| 2 | + |
| 3 | +When you build your new package, you'll find various files `dist`. Here we'll try to explain what they are and why you need them. |
| 4 | + |
| 5 | +Each file targets a different use case. You'll find several of the files referenced in `package.json`, which tells other tools which file to use. If you're familiar with those fields in `package.json` then you should be able to get some sense of what those files are for. |
| 6 | + |
| 7 | +A project will look something like this, using the name `my-lib` as an example: |
| 8 | + |
| 9 | +``` |
| 10 | +📁 packages |
| 11 | + 📁 my-lib |
| 12 | + 📁 dist |
| 13 | + 📁 src |
| 14 | + 📄 package.json |
| 15 | + 📄 vite.config.mts |
| 16 | +``` |
| 17 | + |
| 18 | +Inside `dist` you should see files like these: |
| 19 | + |
| 20 | +``` |
| 21 | +📁 dist |
| 22 | + 📄 my-lib.cjs |
| 23 | + 📄 my-lib.css |
| 24 | + 📄 my-lib.d.ts |
| 25 | + 📄 my-lib.esm.dev.js |
| 26 | + 📄 my-lib.esm-browser.prod.js |
| 27 | + 📄 my-lib.esm-bundler.prod.mjs |
| 28 | + 📄 my-lib.global.dev.js |
| 29 | + 📄 my-lib.global.prod.js |
| 30 | + 📄 my-lib.prod.css |
| 31 | +``` |
| 32 | + |
| 33 | +We'll go into detail about these files later, but in brief: |
| 34 | +- Files with a `.css` ending are CSS. |
| 35 | +- The file ending `.d.ts` contains the TypeScript types. |
| 36 | +- The other files (with `.cjs`, `.js` and `.mjs` endings) are JavaScript files. |
| 37 | +- Files with `dev` in their names are intended to be used during development. |
| 38 | +- Files with `prod` in their names are intended to be used in production. |
| 39 | +- `esm` indicates that a file is an ES module (i.e. it supports `import`/`export`). |
| 40 | +- `.cjs` indicates a CommonJS file (i.e. it supports `require()`). |
| 41 | +- `global` indicates that a file exposes the library via a global variable. |
| 42 | + |
| 43 | +Depending on the specifics of your project, it's possible that you don't need all of these files, or maybe you need more alternatives for other use cases. Either way, you can change which files are built by modifying `vite.config.mts` and `package.json`. |
| 44 | + |
| 45 | +## Building `.vue` files |
| 46 | + |
| 47 | +Libraries that use `.vue` files face specific challenges. The default project configuration assumes that you do want to use `.vue` files in your library source code. |
| 48 | + |
| 49 | +There are two ways to handle `.vue` files in libraries: |
| 50 | +- Include the raw `.vue` files in the built library. |
| 51 | +- Compile the `.vue` files down to `.js` files. |
| 52 | + |
| 53 | +The key difference is when the files are compiled. The first approach forces the consuming application to compile them, whereas the second approach performs the compilation as part of the library's build. |
| 54 | + |
| 55 | +There are pros and cons with either approach, but the project scaffolded with this tool uses the second approach. |
| 56 | + |
| 57 | +### Development vs production |
| 58 | + |
| 59 | +When building `.vue` files, the SFC compiler needs to know whether to generate a development or production build. The main difference is that a development build is fully compatible with Vue Devtools, whereas a production build only has limited Devtools support. Externally available properties, like `$props` and `$attrs`, will be shown in the Devtools in either build, but component state inside `<script setup>` will only be exposed in development builds. |
| 60 | + |
| 61 | +They also differ in how they compile type-based prop definitions. Development builds will try to generate a helpful runtime `props` option, whereas a production build will aim for minimal code. |
| 62 | + |
| 63 | +You can see the differences for yourself in the Vue Playground at <https://play.vuejs.org/>. The compiled component is visible in the JS tab, and you can toggle between `DEV` and `PROD` using the button at the top of the page. |
| 64 | + |
| 65 | +But having two different compiled forms means we need to commit to which one we want when we build the library. |
| 66 | + |
| 67 | +To accommodate this, we need to generate `dev` and `prod` builds, even when the downstream application is using a bundler. The `package.json` then tells the bundler which one to use in each case. |
| 68 | + |
| 69 | +### SSR |
| 70 | + |
| 71 | +The SFC compiler can also generate special SSR builds for `.vue` files, allowing them to skip VNodes on the server and just generate HTML strings directly. You can see this in the Vue Playground at <https://play.vuejs.org/>, in the SSR tab. |
| 72 | + |
| 73 | +Currently, the project created using this scaffolding tool does not generate special SSR builds. It should still work with SSR, but it'll use the slower VNode-based approach. |
| 74 | + |
| 75 | +## The files |
| 76 | + |
| 77 | +### `<name>.cjs` |
| 78 | + |
| 79 | +This is a CommonJS build. It is intended to be used in Node applications that use `require()`. |
| 80 | + |
| 81 | +Some features of this build: |
| 82 | +- The file is not minified, as it isn't used in the browser. |
| 83 | +- The global `__DEV__` flag will depend on the runtime value of `process.env.NODE_ENV`. This is only relevant if you're using it in your library code. |
| 84 | +- SFCs will be compiled in production mode. |
| 85 | + |
| 86 | +There is an argument for having separate `dev` and `prod` builds, but the generated project won't currently be configured that way. |
| 87 | + |
| 88 | +### `<name>.css` and `<name>.prod.css` |
| 89 | + |
| 90 | +These are the built CSS files for the project. The `<style>` sections of any components will end up in these files. |
| 91 | + |
| 92 | +The `prod` file is minified, but they should otherwise be the same. If the consuming application is using a bundler then it should minify the CSS itself, so the minified build is only really relevant to applications that don't have a build step. |
| 93 | + |
| 94 | +There currently isn't any support in the generated project for splitting the CSS file into smaller chunks. |
| 95 | + |
| 96 | +Consuming applications will need to include the CSS file manually. With a bundler that would usually mean importing it, without a bundler it'd usually be a `<link rel="stylesheet">` in the HTML file. |
| 97 | + |
| 98 | +### `<name>.d.ts` |
| 99 | + |
| 100 | +This file contains the TypeScript types. This should include type information for anything exported by the package, including any components. |
| 101 | + |
| 102 | +Tooling in the consuming application should pick this up automatically, as it's referenced from `package.json`. |
| 103 | + |
| 104 | +### `<name>.esm.dev.js` |
| 105 | + |
| 106 | +This file exposes the library as an ES module. It is intended to be used during development, either with a bundler or directly in the browser via `<script type="module">` and import maps. |
| 107 | + |
| 108 | +Some features of this build: |
| 109 | +- The file is not minified, to make debugging easier. |
| 110 | +- The global `__DEV__` flag will be set to `true`. This is only relevant if you're using it in your library code. |
| 111 | +- SFCs will be compiled in development mode. |
| 112 | + |
| 113 | +In production, you would use either `<name>.esm-browser.prod.js` or `<name>.esm-bundler.prod.mjs` instead. |
| 114 | + |
| 115 | +If your library needs to differentiate between bundlers and direct browser usage during development then you may need to adjust the build to generate more files. |
| 116 | + |
| 117 | +### `<name>.esm-browser.prod.js` |
| 118 | + |
| 119 | +This file is an ES module build intended to be used directly in the browser, not via a bundler. For example: |
| 120 | + |
| 121 | +```html |
| 122 | +<script type="importmap"> |
| 123 | +{ |
| 124 | + "imports": { |
| 125 | + "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.prod.js", |
| 126 | + "@skirtle/example-lib": "https://unpkg.com/@skirtle/example-lib/dist/example-lib.esm-browser.prod.js" |
| 127 | + } |
| 128 | +} |
| 129 | +</script> |
| 130 | +<script type="module"> |
| 131 | +import { ExampleComponent } from '@skirtle/example-lib' |
| 132 | +// ... |
| 133 | +</script> |
| 134 | +``` |
| 135 | + |
| 136 | +It's a production build, so in real code the versions should be pinned. |
| 137 | + |
| 138 | +Some features of this build: |
| 139 | +- The file is minified, reducing its size. Note that Vite doesn't fully minify `esm` builds for libraries. |
| 140 | +- The global `__DEV__` flag will be set to `false` and dead code removed. This is only relevant if you're using it in your code. |
| 141 | +- SFCs will be compiled in production mode. |
| 142 | + |
| 143 | +During development, you'd normally use `<name>.esm.dev.js` instead. |
| 144 | + |
| 145 | +### `<name>.esm-bundler.prod.mjs` |
| 146 | + |
| 147 | +This is a production ES module build, intended to be used by a bundler. |
| 148 | + |
| 149 | +Some features of this build: |
| 150 | +- The file is not minified. The bundler will be expected to handle that. |
| 151 | +- The global `__DEV__` variable will depend on the bundler's value for `process.env.NODE_ENV`. |
| 152 | +- SFCs will be compiled in production mode. |
| 153 | + |
| 154 | +From a bundler's perspective, the only significant difference between this build and the `<name>.esm.dev.js` build is that `.vue` files are built in production mode. If you aren't using `.vue` files in your library code then this file can be used in both development and production. That would be similar to libraries like Vue core, Vue Router and Pinia, which just have an `esm-bundler` build, with no distinction between `dev` and `prod`. In that scenario, `<name>.esm.dev.js` is only used in the browser, so it could be renamed to something like `<name>.esm-browser.dev.js`. |
| 155 | + |
| 156 | +### `<name>.global.dev.js` and `<name>.global.prod.js` |
| 157 | + |
| 158 | +Global builds can be used without build tools, just by including a `<script>` tag in the HTML page. They are built using the IIFE format. |
| 159 | + |
| 160 | +The library is exposed using a global variable. For example, let's imagine our package is called `@skirtle/example-lib`, it might be used something like this: |
| 161 | + |
| 162 | +```html |
| 163 | +<body> |
| 164 | +<div id="app"> |
| 165 | + <ExampleComponent /> |
| 166 | +</div> |
| 167 | +<script src="https://unpkg.com/vue@3"></script> |
| 168 | +<script src="https://unpkg.com/@skirtle/example-lib/dist/example-lib.global.dev.js"></script> |
| 169 | +<script> |
| 170 | +Vue.createApp({ |
| 171 | + components: { |
| 172 | + ExampleComponent: ExampleLib.ExampleComponent |
| 173 | + } |
| 174 | +}).mount('#app') |
| 175 | +</script> |
| 176 | +</body> |
| 177 | +``` |
| 178 | + |
| 179 | +The global build of Vue creates a global variable called `Vue`, exposing `createApp`. The global build of `@skirtle/example-lib` creates a global variable called `ExampleLib`, allowing us to access `ExampleComponent`. |
| 180 | + |
| 181 | +In production applications, the `prod` builds of both `vue` and `@skirtle/example-lib` should be used instead, and exact versions should be pinned in the URL. |
| 182 | + |
| 183 | +The differences between the `dev` and `prod` builds are: |
| 184 | +- `prod` is minified, `dev` isn't. |
| 185 | +- `dev` sets `__DEV__` to `true`, `prod` sets it to `false`, with any dead code removed. |
| 186 | +- SFCs will be compiled in development or production modes accordingly. |
| 187 | + |
| 188 | +## `build:dev`, `build:neutral`, `build:prod` |
| 189 | + |
| 190 | +The default build for the generated project is split into 3 targets in `scripts`, to accommodate the files we need to generate. If you decide to add or remove more built files then you may also need to add or remove build targets from `package.json`, as well as adjusting `vite.config.mts`. |
| 191 | + |
| 192 | +A single Vite build can produce multiple files, but those files must share most of their build options and only one file can be created for each format. |
| 193 | + |
| 194 | +There's nothing special about having 3 builds, that's just how many we need to create the combinations we need. We generate 3 `esm` files in `dist`, so we need at least 3 builds to achieve that. |
| 195 | + |
| 196 | +Roughly speaking: |
| 197 | +- `build:dev` - unminified development builds that can be served to the browser without further build tools: `<name>.esm.dev.js` and `<name>.global.dev.js`. |
| 198 | +- `build:neutral` - unminified builds that won't go directly to the browser: `<name>.cjs` and `<name>.esm-bundler.prod.js`. |
| 199 | +- `build:prod` - minified production builds to be served directly to the browser: `<name>.esm.prod.js` and `<name>.global.prod.js` |
| 200 | + |
| 201 | +The TypeScript types only need to be generated once, so they get bolted onto `build:neutral`. |
| 202 | + |
| 203 | +Each build will also generate a CSS file, but two of them will be the same and will be given the same name. |
0 commit comments