vite-plugin-fvtt 0.1.4 → 0.2.0
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 +70 -0
- package/README.md +50 -22
- package/dist/index.d.ts +3 -1
- package/dist/index.js +29 -2
- package/package.json +3 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Automatic compiling of packs for watch and build mode, when discovered.
|
|
8
|
+
- Option to skip the automatic compilation of packs `{ buildPacks: false }`.
|
|
9
|
+
- Documenting the changes in a `CHANGELOG.md` for the plugin.
|
|
10
|
+
|
|
11
|
+
## [0.1.4] - 2025-09-06
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- In watch mode, the plugin now automatically avoids cleaning the output directory, if `emptyOutDir`
|
|
16
|
+
is not set.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- By using rollupOptions, the output files are now correctly named as specified by the foundry vtt
|
|
21
|
+
manifest, even in case `{ "type": "module" }` is not set in the `package.json`.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Defaults in case of unspecified `esmodules`, `scripts`, or `styles` in the foundry vtt manifest
|
|
26
|
+
now default to the folder structure suggested by foundry vtt.
|
|
27
|
+
|
|
28
|
+
## [0.1.3] - 2025-09-04
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Manifest and language files not in the public directory are now watched during `--watch`.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Updated the documentation.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- HMR for language files only manually reloads all active translations for the current module.
|
|
41
|
+
- HMR for templates now manually reassigns them on successful compilation instead of using
|
|
42
|
+
`getTemplate`. This prevents an missing template from appearing after a failed HMR compilation.
|
|
43
|
+
|
|
44
|
+
## [0.1.2] - 2025-09-03
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- Automatic npm deployment on tag push.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- Replaced glob with tinyglobby to match vite's dependencies and not add more unnecessary modules.
|
|
53
|
+
- Default to `bundle.css` if no style file is specified in the manifest, but one was found during
|
|
54
|
+
compilation as an asset.
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- Add typechecks to guard against missing manifest entries.
|
|
59
|
+
|
|
60
|
+
## [0.1.1] - 2025-09-02
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- Initial Release
|
|
65
|
+
|
|
66
|
+
[unreleased]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.1.4...HEAD
|
|
67
|
+
[0.1.4]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.1.3...v0.1.4
|
|
68
|
+
[0.1.3]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.1.2...v0.1.3
|
|
69
|
+
[0.1.2]: https://github.com/MatyeusM/vite-plugin-fvtt/compare/v0.1.1...v0.1.2
|
|
70
|
+
[0.1.1]: https://github.com/MatyeusM/vite-plugin-fvtt/releases/tag/v0.1.1
|
package/README.md
CHANGED
|
@@ -1,83 +1,111 @@
|
|
|
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
|
⚠️ **Note:** HMR works for language files, but non-English locales may not reload as expected.
|
|
79
106
|
|
|
80
107
|
### **Example Project Structure**
|
|
108
|
+
|
|
81
109
|
```
|
|
82
110
|
my-module/
|
|
83
111
|
├─ 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",
|
|
@@ -587,12 +613,13 @@ function foundryVTTPlugin() {
|
|
|
587
613
|
}
|
|
588
614
|
const languages = context.manifest?.languages ?? [];
|
|
589
615
|
if (languages.length > 0) for (const language of languages) {
|
|
590
|
-
if (path_utils_default.
|
|
616
|
+
if (path_utils_default.getPublicDirFile(language.path)) continue;
|
|
591
617
|
getLocalLanguageFiles(language.lang).forEach((langFile) => this.addWatchFile(langFile));
|
|
592
618
|
const languageDataRaw = loadLanguage(language.lang);
|
|
593
619
|
const languageData = transform(languageDataRaw);
|
|
594
620
|
fs.writeJSONSync(posix.join(outDir, language.path), languageData);
|
|
595
621
|
}
|
|
622
|
+
if (options.buildPacks) await compileManifestPacks();
|
|
596
623
|
},
|
|
597
624
|
closeBundle() {
|
|
598
625
|
const languages = context.manifest?.languages ?? [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-fvtt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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",
|