Skip to content

Pitfalls

Web vs Node.js

Node.js code cannot be imported directly from the web side. You must use moonlight.getNatives. See the cookbook for how to access Node.js exports.

Webpack require is not Node.js require

The require function used in Webpack modules and patches is not the same as the function in Node.js. Instead, it lets you require other Webpack modules by their IDs.

If you have a Webpack module you want to load, you can require it by its ID.

The web entrypoint is not a Webpack module

You cannot use Webpack modules inside of index.ts, because it is loaded before Webpack is initialized. Instead, create your own Webpack module and use that.

Webpack modules only load when required

By default, Webpack modules will not load unless they are required by another module or the entrypoint flag is set. If you need a module to run as soon as possible, set the entrypoint flag.

Spacepack findByCode matching itself

When using the findByCode function in Spacepack while inside of a Webpack module, you can sometimes accidentally match yourself. It is suggested to split a string in half and concatenante it, such that the string is fragmented in source but will evaluate to the same string:

const { something } = spacepack.findByCode("__SECRET_INTERNALS_DO_NOT" + "_USE_OR_YOU_WILL_BE_FIRED")[0].exports;

Using JSX

JSX (and its TypeScript version, TSX) is an extension of JavaScript that allows you to write HTML-like syntax in your code. The default configuration of the sample extension is to convert the JSX to React.createElement calls:

const myElement = <span>Hi!</span>;
// becomes
const myElement = React.createElement("span", null, "Hi!");

Because of this, you need to make sure the React variable is in scope. react is automatically populated as a Webpack module name with mappings:

import React from "@moonlight-mod/wp/react";
const myElement = <span>Hi!</span>;

Remember to add React to your extension dependencies.

Using the wrong moonlight global

What moonlight global exists depends on the entrypoint. See the API documentation for more details.

Each Webpack module is an entrypoint

Say you were writing a Webpack module that shared some state:

someModule.ts
export const someState = 1;

and you wanted to use it in another Webpack module. Do not directly import the Webpack module as a file:

someOtherModule.ts
import { someState } from "./someModule";

as it will make a copy of the module, duplicating your state and causing issues. Each Webpack module is treated as its own entrypoint, and all imports will be duplicated between them. Instead, require it at runtime:

otherWebpackModule.ts
import { someState } from "@moonlight-mod/wp/yourExtension_someModule";
// or
const { someState } = require("yourExtension_someModule");

Remember to type your module when using import statements.

Restarting dev mode is required in some scenarios

You must restart the pnpm run dev command if you make changes to certain files:

If you delete anything, it is suggested to run pnpm run clean so that they don’t stick around in the dist folder.