@flamework-experimental/core 2.0.0-alpha.3 → 2.0.0-alpha.4

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/README.md CHANGED
@@ -12,8 +12,13 @@ material:
12
12
  | | |
13
13
  |---|---|
14
14
  | [Guide](docs/README.md#guide) | Getting started, modules, providers, lifecycle events, components, networking, macros, plugins, project structure, migrating from v1, scopes, testing in the place. |
15
- | [Internals](docs/reference/internals.md) | What the transformer does to your code and what the runtime does with the result. |
16
- | [Transformer plugins](docs/reference/transformer-plugins.md) | Adding macro types of your own. |
15
+ | [Internals](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/docs/reference/internals.md) | What the transformer does to your code and what the runtime does with the result. |
16
+ | [Transformer plugins](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/docs/reference/transformer-plugins.md) | Adding macro types of your own. |
17
+
18
+ The guide also ships inside the core package, for the version you installed:
19
+ `node_modules/@flamework-experimental/core/docs/README.md` is its index, and the pages are in
20
+ `node_modules/@flamework-experimental/core/docs/guide/`. Instructions for a coding assistant can
21
+ point there, so that it reads the docs for your version.
17
22
 
18
23
  The Flamework website documents v1, most of which no longer applies:
19
24
 
@@ -51,7 +56,7 @@ bun run test:place # the in-place suite in Roblox Studio (tests/place); need
51
56
  - **Transformer tests** (`bun run test:unit`) build a fixture project with the real `rbxtsc` and
52
57
  check the Luau it emits: guard generation, identifiers, nested macros and the plugin system.
53
58
  - **Runtime specs** (`bun run test:runtime`) run the built `@flamework-experimental/core`,
54
- `components` and `networking` packages under Lune. The harness in [`tests/runtime`](tests/runtime)
59
+ `components` and `networking` packages under Lune. The harness in [`tests/runtime`](https://github.com/Velover/ExperimentalFlameworkV2/tree/HEAD/tests/runtime)
55
60
  models roblox-ts's `TS.import` tree over the filesystem. It also stubs the parts of the Roblox API
56
61
  that Flamework uses: Instances, attributes, CollectionService, RemoteEvents, Players, signals,
57
62
  `task`, `Enum`, and a `Heartbeat` pump so that `Promise.delay` runs (and with it, request
@@ -65,10 +70,10 @@ bun run test:place # the in-place suite in Roblox Studio (tests/place); need
65
70
  example, from the server a function receives on `$name` and sends on `@name`, and from the client
66
71
  it does the reverse, so the two runs pin down the wire format from both ends.
67
72
 
68
- Specs live in [`packages/specs`](packages/specs). `rbxtsc` builds them like any other project that
73
+ Specs live in [`packages/specs`](https://github.com/Velover/ExperimentalFlameworkV2/tree/HEAD/packages/specs). `rbxtsc` builds them like any other project that
69
74
  uses Flamework, so they test the transformer and the runtime together.
70
75
 
71
76
  A third suite runs against the real engine, and `bun run test` leaves it out. It lives in the
72
- [test place](tests/place/README.md), a small game linked to the packages' builds.
77
+ [test place](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/tests/place/README.md), a small game linked to the packages' builds.
73
78
  `bun run test:place` runs its `@flamework-experimental/testing` sections in Roblox Studio, on both
74
- realms, under four Rojo projects (see [Testing in Roblox Studio](docs/testing/studio.md)).
79
+ realms, under four Rojo projects (see [Testing in Roblox Studio](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/docs/testing/studio.md)).
package/docs/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Flamework documentation
2
+
3
+ Flamework is a framework for roblox-ts built around **modules**. A module is a dependency-injection
4
+ container that you create and start yourself; starting it is called *igniting* it. Everything else
5
+ is a plugin or a package built on top of modules: lifecycle events, components and networking.
6
+
7
+ > These docs cover **v2**, which is still in alpha: its packages are published as `2.0.0-alpha`
8
+ > prereleases. The
9
+ > [Flamework website](https://flamework.fireboltofdeath.dev/docs/introduction) documents v1, and
10
+ > most of it no longer applies. See [migrating from v1](guide/10-migrating-from-v1.md).
11
+
12
+ ## Guide
13
+
14
+ Read the pages in order the first time. Most pages have a **Caveats** section for their topic, near
15
+ the end.
16
+
17
+ | | Page | Covers |
18
+ |---|---|---|
19
+ | 1 | [Getting started](guide/01-getting-started.md) | Install, `tsconfig`, Rojo, your first working module on both realms. |
20
+ | 2 | [Modules](guide/02-modules.md) | What a module is, igniting and extinguishing it, `Dependency<T>()`, importing one module into another. |
21
+ | 3 | [Providers](guide/03-providers.md) | `@Provider`, automatic registration, dependency injection, `@Injectable`. |
22
+ | 4 | [Lifecycle events](guide/04-lifecycle-events.md) | `OnStart`, `OnTick` and the other events, and listeners you attach by hand. |
23
+ | 5 | [Components](guide/05-components.md) | Classes attached to instances: attributes, guards, streaming, dependencies. |
24
+ | 6 | [Networking](guide/06-networking.md) | Events, functions, namespaces, unreliable channels, middleware. |
25
+ | 7 | [Macros](guide/07-macros.md) | What the transformer fills in, and writing macros of your own. |
26
+ | 8 | [Plugins](guide/08-plugins.md) | Extending Flamework itself with hooks and interfaces. |
27
+ | 9 | [Project structure](guide/09-project-structure.md) | Folder layout, one module or several, testing. |
28
+ | 10 | [Migrating from v1](guide/10-migrating-from-v1.md) | What changed, and what to do about it. |
29
+ | 11 | [Scopes](guide/11-scopes.md) | Build scopes from `.env`: test scenarios, debug tools and stand-ins that exist only in the builds that ask for them. |
30
+ | 12 | [Testing in the place](guide/12-testing.md) | Sections of tests that run inside a real place through a bindable, a remote or a cloud task, with cleanup that always runs. |
31
+
32
+ ## Reference
33
+
34
+ - [Internals](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/docs/reference/internals.md) -- what the transformer does to your code, and what the
35
+ runtime does with the result. Read this to change Flamework, or to debug something that only fails
36
+ at runtime.
37
+ - [Transformer plugins](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/docs/reference/transformer-plugins.md) -- adding macro types of your own.
38
+ - [Future considerations](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/docs/future-considerations.md) -- possible future directions, and the known
39
+ limits that were left alone. It covers the estimated cost of each feature, why Immediate signal
40
+ behaviour stays supported, and simpler rules for rare features.
41
+
42
+ ## Testing
43
+
44
+ - [Testing in Roblox Studio](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/docs/testing/studio.md) -- the battletest, which runs a real place on the
45
+ packages. It covers setup, the automated matrix, the manual scenarios, and what the first run
46
+ found.
47
+ - [Running the tests](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/docs/testing/place.md) -- `flamework-test`, run from a terminal. It opens the build
48
+ in Roblox Studio and runs it on both realms, or publishes it and runs it in a real server through
49
+ Open Cloud.
50
+ - [The test place](https://github.com/Velover/ExperimentalFlameworkV2/blob/HEAD/tests/place/README.md) -- the place that this repository's in-place suite runs
51
+ in. It is linked to the packages' own builds. `bun run test:place` builds the packages and runs the
52
+ suite in Studio under four Rojo projects (default, immediate, deferred, streaming).
53
+
54
+ ## I just want to…
55
+
56
+ | | |
57
+ |---|---|
58
+ | …get a provider (a v1 service) running | [Getting started](guide/01-getting-started.md), then [Providers](guide/03-providers.md) |
59
+ | …run code every frame | [Lifecycle events](guide/04-lifecycle-events.md) |
60
+ | …attach a class to an Instance | [Components](guide/05-components.md) |
61
+ | …send something to the server | [Networking](guide/06-networking.md) |
62
+ | …understand why an argument is `nil` | [Macros › when a macro does not fire](guide/07-macros.md#when-a-macro-does-not-fire) |
63
+ | …know what an error means | the **Caveats** section of the guide page for that topic lists them (pages 1–9 and 11 have one) |
@@ -0,0 +1,334 @@
1
+ # 1. Getting started
2
+
3
+ By the end of this page you will have a provider (what v1 called a service or a controller) running
4
+ on the server and on the client. Flamework finds and registers it for you, so there is no wiring to
5
+ write by hand.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @flamework-experimental/core
11
+ npm install -D @flamework-experimental/transformer
12
+ ```
13
+
14
+ The commands in these guides use npm. bun (`bun add`, `bun add -d`) and pnpm (`pnpm add`,
15
+ `pnpm add -D`) work the same way.
16
+
17
+ **Pin TypeScript to the version roblox-ts compiles with.** roblox-ts depends on one exact
18
+ TypeScript (roblox-ts 3.0.0 on 5.5.3), but `create-roblox-ts` installs `typescript` unpinned, which
19
+ gives the latest release (7.x at the time of writing). The build still works, since Flamework
20
+ switches to roblox-ts's TypeScript, but every build prints `TypeScript version differs`, and your
21
+ editor checks the code with another compiler than the build. So install the same version:
22
+
23
+ ```sh
24
+ npm install -D --save-exact typescript@5.5.3
25
+ ```
26
+
27
+ With another roblox-ts, take the version from the `typescript` entry of the `dependencies` in
28
+ `node_modules/roblox-ts/package.json`.
29
+
30
+ Add the transformer to `tsconfig.json`. **Nothing in these docs works without it.** Most of
31
+ Flamework's API is made of *macros*: functions with some arguments that the transformer fills in
32
+ when you build. Without the transformer, those arguments are missing at runtime.
33
+
34
+ ```jsonc
35
+ {
36
+ "compilerOptions": {
37
+ "plugins": [
38
+ {
39
+ "transform": "@flamework-experimental/transformer"
40
+ }
41
+ ]
42
+ }
43
+ }
44
+ ```
45
+
46
+ Also add the `@flamework-experimental` npm scope to `typeRoots`, next to `@rbxts`. roblox-ts only
47
+ accepts imports from the scopes listed there:
48
+
49
+ ```jsonc
50
+ "typeRoots": ["node_modules/@rbxts", "node_modules/@flamework-experimental"]
51
+ ```
52
+
53
+ (TypeScript treats every package under a `typeRoots` directory as a type library. That is why the
54
+ transformer and the CLI ship an empty declaration file.)
55
+
56
+ That is all the configuration you need. Optional settings go in a `flamework.config.json` next to
57
+ `tsconfig.json`, with one section per package. They never go on the tsconfig entry: the build fails
58
+ if the entry sets one. See [Project structure](09-project-structure.md#configuration).
59
+
60
+ You don't have to write that file to see what you can set. With `tsconfig.json` at the root of your
61
+ package, as here, your first build creates it, holding just a `$schema` line. It also adds the line
62
+ to a file that lacks it. With that line, your editor lists every option with its description and
63
+ its default. Commit the file. The build also writes `flamework.build` and `include/flamework/`,
64
+ which you do not commit; see [Project structure › What to commit](09-project-structure.md#what-to-commit).
65
+
66
+ ### Incremental builds and upgrades
67
+
68
+ The `create-roblox-ts` template turns on `"incremental": true`, with
69
+ `"tsBuildInfoFile": "out/tsconfig.tsbuildinfo"`. An incremental build recompiles only the files
70
+ that changed since the last one. After you upgrade Flamework, the other files would keep what the
71
+ old version emitted, so the first build stops:
72
+
73
+ ```
74
+ [Flamework]: Project was compiled on different version of Flamework.
75
+ [Flamework]: This is an incremental build, which recompiles only the files that changed. Delete out/tsconfig.tsbuildinfo and build again: the next build compiles every file.
76
+ [Flamework]: Current Flamework Version: 2.0.0-alpha.5
77
+ [Flamework]: Previous Flamework Version: 2.0.0-alpha.4
78
+ ```
79
+
80
+ Delete the file it names and build again. roblox-ts chooses the files to compile before it loads the
81
+ transformer, so the build cannot start over by itself. `incremental` without a `tsBuildInfoFile`
82
+ builds incrementally too, into TypeScript's default tsbuildinfo, and behaves the same. Where that
83
+ file goes depends on `rootDir`: with the template's `"rootDir": "src"` it is `tsconfig.tsbuildinfo`
84
+ beside `tsconfig.json`, and the message names it either way. To avoid this step on every upgrade,
85
+ remove the two options from `tsconfig.json`: every build is then a full one.
86
+
87
+ ## Rojo
88
+
89
+ Your Rojo project file has to map two things: the folders you register from, and the packages.
90
+
91
+ When you build, Flamework turns each source folder you register from into a **Rojo path**: the
92
+ instance path the folder ends up at, such as `ServerScriptService/TS/services`. So the folders you
93
+ register from have to be in the project file. A default roblox-ts project maps all of `out/`, which
94
+ covers them.
95
+
96
+ The packages are ModuleScripts like any `@rbxts` package. They live next to the `@rbxts` packages,
97
+ under `ReplicatedStorage.rbxts_include.node_modules`. Map the whole `@flamework-experimental` folder
98
+ there, in one line:
99
+
100
+ ```json
101
+ {
102
+ "name": "my-game",
103
+ "globIgnorePaths": ["**/package.json", "**/tsconfig.json"],
104
+ "tree": {
105
+ "$className": "DataModel",
106
+ "ServerScriptService": {
107
+ "TS": { "$path": "out/server" }
108
+ },
109
+ "ReplicatedStorage": {
110
+ "rbxts_include": {
111
+ "$path": "include",
112
+ "node_modules": {
113
+ "$className": "Folder",
114
+ "@rbxts": { "$path": "node_modules/@rbxts" },
115
+ "@flamework-experimental": { "$path": "node_modules/@flamework-experimental" }
116
+ }
117
+ },
118
+ "TS": { "$path": "out/shared" }
119
+ },
120
+ "StarterPlayer": {
121
+ "StarterPlayerScripts": {
122
+ "TS": { "$path": "out/client" }
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ Each package you install arrives in the place with its `out` folder: `core`, and `components`,
130
+ `networking` and `testing` when you install them. `core` also ships this guide, as Markdown, which
131
+ Rojo skips; its two folders arrive as empty Folders, `core.docs` and `core.docs.guide`. `testing`
132
+ also ships the sources of its CLI, and a `default.project.json` that maps its `out` folder alone, so
133
+ they stay out of the place (from 2.0.0-alpha.4; an older one brings three empty Folders,
134
+ `testing.cli`, `cli.src` and `cli.tasks`). Rojo uses a package's `default.project.json` in place of
135
+ its folder. The transformer is installed in the same folder, and it arrives as one empty Folder: it
136
+ ships a `default.project.json` too. Two entries are the same as in the roblox-ts template:
137
+
138
+ - `include` holds the roblox-ts runtime and the files Flamework generates when you build
139
+ (`include/flamework`).
140
+ - `globIgnorePaths` stops each package's `package.json` from becoming a ModuleScript.
141
+
142
+ **The one line needs `@flamework-experimental/transformer` 2.0.0-alpha.5 or later.** An older
143
+ transformer ships no `default.project.json`, so Rojo would copy it into `ReplicatedStorage`, which
144
+ replicates to every client. Rojo skips its JavaScript, but its folders arrive as empty Folders and
145
+ its three JSON schemas arrive as ModuleScripts (`flamework-schema`, `flamework.config.schema`,
146
+ `rojo-schema`). With an older transformer, map each runtime package by name instead. This form works
147
+ with every version:
148
+
149
+ ```json
150
+ "@flamework-experimental": {
151
+ "$className": "Folder",
152
+ "core": { "$path": "node_modules/@flamework-experimental/core" },
153
+ "components": { "$path": "node_modules/@flamework-experimental/components" },
154
+ "networking": { "$path": "node_modules/@flamework-experimental/networking" }
155
+ }
156
+ ```
157
+
158
+ `core` is always needed. Add `components`, `networking` and `testing` when you install them, and
159
+ leave out the ones you do not use.
160
+
161
+ If a folder you register from is not in the project file, the build fails with `Could not find Rojo
162
+ data for 'src/...'`. If a package your code imports is not mapped, roblox-ts fails the build with
163
+ `Could not find Rojo data. There is no $path in your Rojo config that covers ...`, naming a file of
164
+ that package.
165
+
166
+ A folder you register from also has to exist, spelled exactly as it is on disk, case included, and
167
+ hold at least one module:
168
+
169
+ - **A path that names nothing** (a missing folder, a typo, a name that differs in case from the one
170
+ on disk, which is the name the place gets) is not in the place, and the call that names it waits
171
+ for it at runtime. `requireModules` raises instead, once it has waited five seconds.
172
+ - **A folder with no module** (an empty one, or one of declarations only) is still copied into
173
+ `out/`, so the place gets it empty, and the call registers or finds nothing there. Git keeps no
174
+ empty folder, though: in a fresh clone an empty folder is not in the place at all, and the call
175
+ waits for it.
176
+
177
+ The build warns about each such path where it is written, naming the call and the path:
178
+
179
+ ```
180
+ [Flamework]: src/server/runtime.server.ts:6:3 - registerProviders("src/shared/nothing-here"): there is no such file or folder, so the place will not have it, and the call waits for it at runtime
181
+ [Flamework]: src/server/runtime.server.ts:7:3 - registerProviders("src/server/Services"): there is no such file or folder; on disk it is 'src/server/services', and the place names it as the disk does, so the call waits at runtime for a name the place does not have
182
+ [Flamework]: src/client/runtime.client.ts:5:44 - ComponentPlugin.fromPath("src/shared/components"): nothing in that folder compiles to a module, so the call finds nothing there, and in a place without the folder (git keeps no empty folder) it waits for it at runtime
183
+ ```
184
+
185
+ The check follows your Rojo project, as the place does: a folder that a `$path` of its own maps
186
+ inside an `out` folder counts, and so do Luau, JSON, TOML and YAML modules. It covers every path
187
+ macro: `registerProviders`, `ComponentPlugin.fromPath`, `registerComponents`, `requireModules`,
188
+ and a macro of your own. At runtime, a registration keeps waiting for its folder, since a client may
189
+ still be receiving the place. After five seconds it warns once, naming itself:
190
+ `registerProviders("src/shared/nothing-here") is still waiting for its folder: the build put it at
191
+ ReplicatedStorage/TS/nothing-here, and ReplicatedStorage.TS has no child named 'nothing-here' after
192
+ 5 seconds. ...`. So register only the folders you have: in the layout of
193
+ [Project structure](09-project-structure.md#a-layout-that-scales), leave out
194
+ `src/shared/components` until it holds a component.
195
+
196
+ ## Your first provider
197
+
198
+ A **provider** is usually a class that Flamework creates once per module: a singleton. Mark it with
199
+ `@Provider()` and export it:
200
+
201
+ ```ts
202
+ // src/server/services/greeter.ts
203
+ import { OnStart, Provider } from "@flamework-experimental/core";
204
+
205
+ @Provider()
206
+ export class Greeter implements OnStart {
207
+ public onStart() {
208
+ print("hello from the server");
209
+ }
210
+ }
211
+ ```
212
+
213
+ ## Igniting
214
+
215
+ Your entry point creates a **module**, registers your providers in it, and **ignites** it, which
216
+ starts everything:
217
+
218
+ ```ts
219
+ // src/server/runtime.server.ts
220
+ import { Flamework } from "@flamework-experimental/core";
221
+
222
+ Flamework.createModule()
223
+ .registerProviders("src/server/services")
224
+ .ignite();
225
+ ```
226
+
227
+ Two calls do the work:
228
+
229
+ 1. **`registerProviders("src/server/services")`** finds every `@Provider()` class defined in the
230
+ files under that folder, exported or not. You do not list them by hand. See
231
+ [Providers](03-providers.md#registration) for how this works and when it does not.
232
+ 2. **`ignite()`** constructs every provider, injects their dependencies, runs every `onInit` in
233
+ dependency order, and then runs `onStart`.
234
+
235
+ `onStart` runs because every module includes `LifecyclePlugin` from the start. A **plugin** adds
236
+ features to a module. `LifecyclePlugin` is an ordinary one: `disableDefaultLifecycle()` on the
237
+ builder leaves it out, and including one built with `createLifecyclePlugin({ … })` replaces it. See
238
+ [Lifecycle events](04-lifecycle-events.md).
239
+
240
+ The client entry point looks the same:
241
+
242
+ ```ts
243
+ // src/client/runtime.client.ts
244
+ import { Flamework } from "@flamework-experimental/core";
245
+
246
+ Flamework.createModule()
247
+ .registerProviders("src/client/controllers")
248
+ .ignite();
249
+ ```
250
+
251
+ There is no `@Service` / `@Controller` split in v2. The module that registers a provider decides
252
+ which realm gets it. That is why the two entry points register different folders.
253
+
254
+ ## Adding a dependency
255
+
256
+ Flamework resolves constructor parameters by their type: each parameter gets what the module
257
+ provides for that type, usually another provider. There are no tokens, no strings and no decorators
258
+ on the parameters:
259
+
260
+ ```ts
261
+ // src/server/services/economy.ts
262
+ @Provider()
263
+ export class Economy {
264
+ public balance = 0;
265
+ }
266
+
267
+ // src/server/services/shop.ts
268
+ @Provider()
269
+ export class Shop implements OnStart {
270
+ constructor(private economy: Economy) {}
271
+
272
+ public onStart() {
273
+ print(this.economy.balance);
274
+ }
275
+ }
276
+ ```
277
+
278
+ Both files are under `src/server/services`, so the same `registerProviders` call registers both.
279
+ `Shop` gets the module's single `Economy` instance.
280
+
281
+ ## Sharing code between realms
282
+
283
+ Put anything both realms need in a shared folder, and register that folder from both entry points.
284
+ Or wrap it in a plugin that both include; see [Plugins](08-plugins.md).
285
+
286
+ ## Caveats
287
+
288
+ - **`disableDefaultLifecycle()` is silent.** With it, `onStart` never runs, and nothing warns you.
289
+ - **The path must be a string literal.** `registerProviders(SOME_CONSTANT)` fails to compile with
290
+ `Path is invalid, expected string literal`.
291
+ - **The path is a source path, not a Rojo path.** Write `"src/server/services"`, not
292
+ `"ServerScriptService/TS/services"`.
293
+ - **The folder has to hold a module, under its exact name.** A missing or misspelled folder still
294
+ compiles, with a build warning, and the call then waits for it at runtime. An empty folder
295
+ registers nothing, and waits in a fresh clone, which has no such folder. See [Rojo](#rojo).
296
+ - **The path is resolved in the project that compiles the call**, with that project's Rojo file. So
297
+ a published package cannot register its own folders: its `registerProviders("src/...")` gets a path
298
+ in the package's project, which a game's place does not have, and fails at runtime. In a package,
299
+ register classes one by one with `registerClassProvider`.
300
+ - **Providers are found where they are defined.** Registration requires each ModuleScript under the
301
+ folder. It takes every class the ModuleScript defines at its top level, exported or not, as v1
302
+ did. A class declared inside a function is found only if its file exports it.
303
+ - **`@Provider()` metadata must exist on both realms.** It is written when the decorator runs, and
304
+ none of it depends on the realm. So a class shared between realms behaves the same on both.
305
+
306
+ ### Errors you may hit
307
+
308
+ | Message | Cause |
309
+ |---|---|
310
+ | `Could not find Rojo data for 'src/...'` | The folder is not mapped in your Rojo project file. |
311
+ | `Could not find Rojo data. There is no $path in your Rojo config that covers ...` (roblox-ts) | The file it names belongs to a package your code imports, and your Rojo project file does not map that package. See [Rojo](#rojo). |
312
+ | `Path is invalid, expected string literal and got: string` | The path argument is not a literal. |
313
+ | `class 'X' is missing the @Provider() decorator` | `registerClassProvider`/`registerProvider` was given an undecorated class. |
314
+ | `class 'X' is missing the @Provider() decorator: it inherits one from a parent class` | The class extends a provider but is not decorated itself. |
315
+ | `Flamework has no paths for the glob '...'` | A glob registration (`registerProvidersGlob`, `ComponentPlugin.fromGlob`, ...) in a package, the include directory not in the Rojo project, a string passed to `getGlobPaths`/`getClassesInGlob` that no glob macro made, or a `globs.json` from another build. A glob that matches no files does not raise this. It registers nothing, and the build prints a warning where it is used. |
316
+ | `ServerScriptService.TS.services.X failed to load (Nms): ...` | A ModuleScript under a registered path, or under a folder given to `requireModules`, raised an error while being required. |
317
+ | `requireModules("..."): the folder is not in the place` | The path is misspelled, or differs in case from the folder on disk; or the folder is empty and this is a clone without it (git keeps no empty folder); or it was moved or renamed after the build; or the Rojo project the place was built from leaves it out. The message names the part of the path that is missing, and the build warned about the first two where the path is written. See [Macros › Paths](07-macros.md#paths). |
318
+ | `...: registerProviders("..."): there is no such file or folder, so the place will not have it` (build warning) | A path given to a path macro names nothing in the place your Rojo project builds. With `on disk it is '...'`, only the case differs, and the place keeps the case the disk has. See [Rojo](#rojo). |
319
+ | `...: registerProviders("..."): nothing in that folder compiles to a module` (build warning) | The folder holds no module (only declarations, say). It arrives in the place empty and registers nothing; in a clone without the folder, the call waits for it. |
320
+ | `registerProviders("...") is still waiting for its folder: ... has no child named '...' after 5 seconds` (runtime warning) | The registration's folder is not in the place, for one of the reasons in the `requireModules` row above. It keeps waiting, in case the folder is still arriving. `ComponentPlugin.fromPath`, `registerComponents` and a plugin's `registerProviders` name themselves the same way. |
321
+ | `module '...' has been extinguished, cannot ...` | Something resolved from, or created an instance on, a module after `extinguish()`. |
322
+ | `provider ID was registered more than once: ...` | The same class was registered twice, often by two overlapping `registerProviders` paths. Raised at ignition. |
323
+ | `could not resolve dependency '...': it is registered but inactive` | The class is tied to a [scope](11-scopes.md) that this build does not have active. |
324
+ | `could not resolve dependency 'X': 'X' (...) is under registerProviders("..."), which is left out by its scope` | The class is under a folder whose registration has a [scope](11-scopes.md) condition this build does not meet, so the folder was never loaded. `getComponent` gives the same reason, starting `component '...' could not be found:`. |
325
+ | `could not resolve dependency '...': nothing registers it. Left out by their scope, without loading their folders: ...` | The module found nothing for the id, and some folder registrations were left out by their scope. If the class is under one of them, change the build's scopes or stop depending on it. |
326
+ | `could not resolve dependency 'X': 'X' (...) is a component (@Component), not a provider` | `Dependency<X>()`, `resolveDependency` or a constructor asked for a component. Components are built by `Components`: get one with `getComponent`, or make the class a `@Provider()`. The transformer refuses the plain `Dependency<X>()` and a provider's constructor parameter when you build. |
327
+ | `could not resolve dependency 'X': 'X' (...) is a @Provider() that nothing in this module registers or provides` | The class has loaded, but no path, registration, plugin or import of this module brings it in. |
328
+ | `module could not resolve dependency 'X'` | A constructor parameter's type is not registered in this module or any module it includes. |
329
+ | `'X' is a component (@Component), not a provider` (compile error) | `Dependency<X>()`, `resolveDependency<X>()` or a provider's constructor names a component. |
330
+ | `@Provider() on 'X': loadOrder must be a finite number` | `loadOrder` is `math.huge`, NaN or not a number. Raised when the ModuleScript that defines the class loads. |
331
+
332
+ ---
333
+
334
+ Next: [Modules](02-modules.md)