vite-plugin-fvtt 0.1.4 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,78 @@
1
+ # Changelog
2
+
3
+ ## [0.2.1] - 2025-09-09
4
+
5
+ ### Fixed
6
+
7
+ - Fixed language generation to not error out on mixed entries.
8
+
9
+ ## [0.2.0] - 2025-09-08
10
+
11
+ ### Added
12
+
13
+ - Automatic compiling of packs for watch and build mode, when discovered.
14
+ - Option to skip the automatic compilation of packs `{ buildPacks: false }`.
15
+ - Documenting the changes in a `CHANGELOG.md` for the plugin.
16
+
17
+ ## [0.1.4] - 2025-09-06
18
+
19
+ ### Added
20
+
21
+ - In watch mode, the plugin now automatically avoids cleaning the output directory, if `emptyOutDir`
22
+ is not set.
23
+
24
+ ### Fixed
25
+
26
+ - By using rollupOptions, the output files are now correctly named as specified by the foundry vtt
27
+ manifest, even in case `{ "type": "module" }` is not set in the `package.json`.
28
+
29
+ ### Changed
30
+
31
+ - Defaults in case of unspecified `esmodules`, `scripts`, or `styles` in the foundry vtt manifest
32
+ now default to the folder structure suggested by foundry vtt.
33
+
34
+ ## [0.1.3] - 2025-09-04
35
+
36
+ ### Added
37
+
38
+ - Manifest and language files not in the public directory are now watched during `--watch`.
39
+
40
+ ### Changed
41
+
42
+ - Updated the documentation.
43
+
44
+ ### Fixed
45
+
46
+ - HMR for language files only manually reloads all active translations for the current module.
47
+ - HMR for templates now manually reassigns them on successful compilation instead of using
48
+ `getTemplate`. This prevents an missing template from appearing after a failed HMR compilation.
49
+
50
+ ## [0.1.2] - 2025-09-03
51
+
52
+ ### Added
53
+
54
+ - Automatic npm deployment on tag push.
55
+
56
+ ### Changed
57
+
58
+ - Replaced glob with tinyglobby to match vite's dependencies and not add more unnecessary modules.
59
+ - Default to `bundle.css` if no style file is specified in the manifest, but one was found during
60
+ compilation as an asset.
61
+
62
+ ### Fixed
63
+
64
+ - Add typechecks to guard against missing manifest entries.
65
+
66
+ ## [0.1.1] - 2025-09-02
67
+
68
+ ### Added
69
+
70
+ - Initial Release
71
+
72
+ [unreleased]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.2.1...HEAD
73
+ [0.2.1]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.2.0...v0.2.1
74
+ [0.2.0]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.1.4...v0.2.0
75
+ [0.1.4]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.1.3...v0.1.4
76
+ [0.1.3]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.1.2...v0.1.3
77
+ [0.1.2]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.1.1...v0.1.2
78
+ [0.1.1]: https://github.com/MatyeusM/vite-plugin-fvtt/releases/tag/v0.1.1
package/README.md CHANGED
@@ -1,83 +1,115 @@
1
1
  # **vite-plugin-fvtt**
2
2
 
3
- A [Vite](https://vitejs.dev/) plugin to **streamline and automate** the development of Foundry VTT modules and systems.
3
+ A [Vite](https://vitejs.dev/) plugin to **streamline and automate** the development of Foundry VTT
4
+ modules and systems.
4
5
 
5
- It handles manifest resolution, asset copying, language file composition, and template handling with **minimal setup**, letting you focus on your code.
6
+ It handles manifest resolution, asset copying, language file composition, and template handling with
7
+ **minimal setup**, letting you focus on your code.
6
8
 
7
- The plugin's core goal is to enable a robust HMR workflow via Vite's development server, freeing you from Foundry VTT's native HMR and build watch commands.
9
+ The plugin's core goal is to enable a robust HMR workflow via Vite's development server, freeing you
10
+ from Foundry VTT's native HMR and build watch commands.
11
+
12
+ [**Changelog**](CHANGELOG.md)
8
13
 
9
14
  ## **🚀 Getting Started**
10
15
 
11
16
  ### **Step 1. Setup a Foundry VTT Project**
12
17
 
13
- Create a standard [Foundry VTT module or system](https://foundryvtt.com/article/module-development/).
14
- Place your `module.json` or `system.json` manifest in either your **project root** or your **public/** directory.
18
+ Create a standard
19
+ [Foundry VTT module or system](https://foundryvtt.com/article/module-development/). Place your
20
+ `module.json` or `system.json` manifest in either your **project root** or your **public/**
21
+ directory.
15
22
 
16
23
  ### **Step 2. Add the Plugin to your Vite Config**
17
24
 
18
25
  Install the plugin with `npm i -D vite-plugin-fvtt`.
19
26
 
20
- Add the plugin to your vite.config.js. The **build.lib.entry** field is required; most of the other settings are inferred by the plugin from your Foundry VTT manifest.
27
+ Add the plugin to your vite.config.js. The **build.lib.entry** field is required; most of the other
28
+ settings are inferred by the plugin from your Foundry VTT manifest.
21
29
 
22
30
  ```js
23
31
  // vite.config.js
24
- import { defineConfig } from 'vite';
25
- import foundryVTT from 'vite-plugin-fvtt';
32
+ import { defineConfig } from 'vite'
33
+ import foundryVTT from 'vite-plugin-fvtt'
26
34
 
27
35
  export default defineConfig({
28
36
  plugins: [foundryVTT()],
29
37
  build: {
30
38
  // ⚠️ Required: The entry point for your module/system.
31
39
  // This file should import your main CSS/SCSS/LESS file.
32
- lib: {
33
- entry: './src/main.js',
34
- },
40
+ lib: { entry: './src/main.js' },
35
41
  sourcemap: true,
36
42
  },
37
- });
43
+ })
38
44
  ```
39
45
 
40
46
  ## **⚙️ Features**
41
47
 
42
48
  ### **1. Configuration**
43
- The plugin needs to know where your Foundry VTT instance is running to proxy and serve assets correctly. If you want to change anything from the defaults `http://localhost:30000`, create a `.env.foundryvtt.local` file in your project.
49
+
50
+ The plugin needs to know where your Foundry VTT instance is running to proxy and serve assets
51
+ correctly. If you want to change anything from the defaults `http://localhost:30000`, create a
52
+ `.env.foundryvtt.local` file in your project.
53
+
44
54
  ```ini
45
55
  FOUNDRY_URL=localhost
46
56
  FOUNDRY_PORT=30000
47
57
  ```
48
58
 
49
- The Vite dev server will run on `FOUNDRY_PORT + 1`, where you will need to open your browser manually to.
59
+ The Vite dev server will run on `FOUNDRY_PORT + 1`, where you will need to open your browser
60
+ manually to.
50
61
 
51
62
  ### **2. Manifest & Asset Resolution**
52
63
 
53
- The plugin automatically detects your manifest file (`module.json` or `system.json`) in the project **root** or `public/` folder.
64
+ The plugin automatically detects your manifest file (`module.json` or `system.json`) in the project
65
+ **root** or `public/` folder.
54
66
 
55
- This plugin shapes the output depending on your manifest; it tries to automatically discover the relevant files in the `root`, `source`, and `public` folders to build the output files. The `public` folder is defined by the Vite config file. The plugin determines the `source` directory based on your `lib.entry` path. For example, if your `lib.entry` is './mysource/package/main.js', the `mysource/` directory is considered your source directory.
67
+ This plugin shapes the output depending on your manifest; it tries to automatically discover the
68
+ relevant files in the `root`, `source`, and `public` folders to build the output files. The `public`
69
+ folder is defined by the Vite config file. The plugin determines the `source` directory based on
70
+ your `lib.entry` path. For example, if your `lib.entry` is './mysource/package/main.js', the
71
+ `mysource/` directory is considered your source directory.
56
72
 
57
- 💡 Your entry file should always import your main stylesheet; the manifest dictates how everything is named and output.
73
+ 💡 Your entry file should always import your main stylesheet; the manifest dictates how everything
74
+ is named and output.
58
75
 
59
76
  ### **3. ESModules, Scripts & Styles**
60
77
 
61
- `esmodules` and `scripts` declared in your manifest are automatically created from your `lib.entry`. Since Vite compiles the module, the plugin expects the `esmodules` or `scripts` entry in your manifest to only point to a single JavaScript file.
78
+ `esmodules` and `scripts` declared in your manifest are automatically created from your `lib.entry`.
79
+ Since Vite compiles the module, the plugin expects the `esmodules` or `scripts` entry in your
80
+ manifest to only point to a single JavaScript file.
62
81
 
63
- Stylesheets (CSS/SCSS/LESS) should be imported in your entry file; the plugin ensures they are outputted as the correct file.
82
+ Stylesheets (CSS/SCSS/LESS) should be imported in your entry file; the plugin ensures they are
83
+ outputted as the correct file.
64
84
 
65
85
  ### **4. Template Handling**
66
86
 
67
- Templates work in HMR properly on the development server; they are autodiscovered as discussed in [2. Manifest & Asset Resolution](#2-manifest--asset-resolution). The development server intercepts the websocket traffic and sends the local templates instead of Foundry VTT's, if present. e.g., a template request to `/systems/mysystem/tpl/character-header.hbs` might be rerouted to `public/tpl/character-header.hbs`. Folder structure inside your project is mirrored, apart from the `system`/`module` specific prefix.
87
+ Templates work in HMR properly on the development server; they are autodiscovered as discussed in
88
+ [2. Manifest & Asset Resolution](#2-manifest--asset-resolution). The development server intercepts
89
+ the websocket traffic and sends the local templates instead of Foundry VTT's, if present. e.g., a
90
+ template request to `/systems/mysystem/tpl/character-header.hbs` might be rerouted to
91
+ `public/tpl/character-header.hbs`. Folder structure inside your project is mirrored, apart from the
92
+ `system`/`module` specific prefix.
68
93
 
69
94
  ### **5. Language File Merging**
70
95
 
71
96
  Supports both complete and partial translation workflows:
72
97
 
73
- * **Complete files:** Place a complete JSON file (e.g., `public/lang/en.json`) and the plugin will copy it as-is.
74
- * **Partial files:** Place multiple JSONs inside `src/lang/en/` and the plugin merges them into one `lang/en.json` at build.
98
+ - **Complete files:** Place a complete JSON file (e.g., `public/lang/en.json`) and the plugin will
99
+ copy it as-is.
100
+ - **Partial files:** Place multiple JSONs inside `src/lang/en/` and the plugin merges them into one
101
+ `lang/en.json` at build.
75
102
 
76
103
  Merging follows your manifest’s declared language paths, searching in root or source directories.
77
104
 
78
- ⚠️ **Note:** HMR works for language files, but non-English locales may not reload as expected.
105
+ ### **6. Packs**
106
+
107
+ Packs are tried to be auto-discovered in the source directory. If the paths match, they are automatically compiled.
108
+
109
+ **Note:** Packs are currently not watched for changes.
79
110
 
80
111
  ### **Example Project Structure**
112
+
81
113
  ```
82
114
  my-module/
83
115
  ├─ src/
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { Plugin } from "vite";
2
2
 
3
3
  //#region src/index.d.ts
4
- declare function foundryVTTPlugin(): Plugin;
4
+ declare function foundryVTTPlugin(options?: {
5
+ buildPacks: boolean;
6
+ }): Plugin;
5
7
  //#endregion
6
8
  export { foundryVTTPlugin as default };
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import fs from "fs-extra";
2
2
  import posix from "path/posix";
3
3
  import dotenv from "dotenv";
4
4
  import { globSync } from "tinyglobby";
5
+ import { compilePack } from "@foundryvtt/foundryvtt-cli";
5
6
  import { Server } from "socket.io";
6
7
  import { io } from "socket.io-client";
7
8
 
@@ -390,6 +391,31 @@ function validator() {
390
391
  }
391
392
  }
392
393
 
394
+ //#endregion
395
+ //#region src/packs/compile-packs.ts
396
+ async function compileManifestPacks() {
397
+ if (!context.manifest?.packs) return;
398
+ for (const pack of context.manifest.packs) {
399
+ const srcCandidates = [posix.resolve(path_utils_default.getSourceDirectory(), pack.path), posix.resolve(path_utils_default.getRoot(), pack.path)];
400
+ const dest = posix.resolve(path_utils_default.getOutDir(), pack.path);
401
+ const chosenSrc = srcCandidates.find((candidate) => fs.existsSync(candidate) && fs.statSync(candidate).isDirectory());
402
+ if (!chosenSrc) {
403
+ logger_default.warn(`Pack path not found for ${pack.path}, skipped.`);
404
+ continue;
405
+ }
406
+ const entries = fs.readdirSync(chosenSrc, {
407
+ recursive: true,
408
+ encoding: "utf8"
409
+ });
410
+ const hasYaml = entries.some((entry) => entry.endsWith(".yaml") || entry.endsWith(".yml"));
411
+ await compilePack(chosenSrc, dest, {
412
+ yaml: hasYaml,
413
+ recursive: true
414
+ });
415
+ logger_default.info(`Compiled pack ${pack.path} (${hasYaml ? "YAML" : "JSON"}) from ${chosenSrc}`);
416
+ }
417
+ }
418
+
393
419
  //#endregion
394
420
  //#region src/server/trackers/handlebars-tracker.ts
395
421
  var HandlebarsTracker = class extends AbstractFileTracker {
@@ -561,7 +587,7 @@ if (import.meta.hot) {
561
587
 
562
588
  //#endregion
563
589
  //#region src/index.ts
564
- function foundryVTTPlugin() {
590
+ function foundryVTTPlugin(options = { buildPacks: true }) {
565
591
  context.env = loadEnv();
566
592
  return {
567
593
  name: "vite-plugin-fvtt",
@@ -572,28 +598,36 @@ function foundryVTTPlugin() {
572
598
  configResolved(config) {
573
599
  context.config = config;
574
600
  },
575
- async writeBundle() {
576
- if (!context.config) return;
577
- const outDir = path_utils_default.getOutDir();
578
- const candidates = ["system.json", "module.json"];
579
- for (const file of candidates) {
601
+ async generateBundle() {
602
+ const manifestCandidates = ["system.json", "module.json"];
603
+ for (const file of manifestCandidates) {
580
604
  const src = posix.resolve(file);
581
- if (!path_utils_default.getOutDirFile(file) && fs.existsSync(src)) {
605
+ if (!path_utils_default.getPublicDirFile(file) && fs.existsSync(src)) {
582
606
  this.addWatchFile(src);
583
- const dest = posix.join(outDir, file);
584
- await fs.copy(src, dest);
585
- logger_default.info(`Copied ${file} >>> ${dest}`);
607
+ const manifest = fs.readJsonSync(src);
608
+ this.emitFile({
609
+ type: "asset",
610
+ fileName: file,
611
+ source: JSON.stringify(manifest, null, 2)
612
+ });
586
613
  }
587
614
  }
588
615
  const languages = context.manifest?.languages ?? [];
589
616
  if (languages.length > 0) for (const language of languages) {
590
- if (path_utils_default.getOutDirFile(language.path)) continue;
617
+ if (path_utils_default.getPublicDirFile(language.path)) continue;
591
618
  getLocalLanguageFiles(language.lang).forEach((langFile) => this.addWatchFile(langFile));
592
619
  const languageDataRaw = loadLanguage(language.lang);
593
620
  const languageData = transform(languageDataRaw);
594
- fs.writeJSONSync(posix.join(outDir, language.path), languageData);
621
+ this.emitFile({
622
+ type: "asset",
623
+ fileName: posix.join(language.path),
624
+ source: JSON.stringify(languageData, null, 2)
625
+ });
595
626
  }
596
627
  },
628
+ async writeBundle() {
629
+ if (options.buildPacks) await compileManifestPacks();
630
+ },
597
631
  closeBundle() {
598
632
  const languages = context.manifest?.languages ?? [];
599
633
  if (languages.length > 0) validator();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-fvtt",
3
- "version": "0.1.4",
3
+ "version": "0.2.1",
4
4
  "description": "A Vite plugin for module and system development for Foundry VTT",
5
5
  "keywords": [
6
6
  "vite",
@@ -22,6 +22,7 @@
22
22
  "types": "dist/index.d.ts",
23
23
  "files": [
24
24
  "dist",
25
+ "CHANGELOG.md",
25
26
  "LICENSE",
26
27
  "README.md"
27
28
  ],
@@ -41,6 +42,7 @@
41
42
  "vite": "*"
42
43
  },
43
44
  "dependencies": {
45
+ "@foundryvtt/foundryvtt-cli": "^3.0.0",
44
46
  "dotenv": "^17.2.1",
45
47
  "fs-extra": "^11.3.1",
46
48
  "socket.io": "^4.8.1",