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 +78 -0
- package/README.md +55 -23
- package/dist/index.d.ts +3 -1
- package/dist/index.js +46 -12
- package/package.json +3 -1
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
|
|
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
|
|
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
|
|
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
|
|
14
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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`.
|
|
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
|
|
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
|
|
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
|
-
|
|
74
|
-
|
|
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
|
-
|
|
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
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
|
|
576
|
-
|
|
577
|
-
const
|
|
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.
|
|
605
|
+
if (!path_utils_default.getPublicDirFile(file) && fs.existsSync(src)) {
|
|
582
606
|
this.addWatchFile(src);
|
|
583
|
-
const
|
|
584
|
-
|
|
585
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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",
|