Concepts

Imports

Understanding how imports work in a Joystick app.

Due to Joystick's dependency on Node.js v20+, imports are designed to work in-step with the default behavior of the runtime.

Joystick prior to RC1 implemented the experimental Node.js --experimental-specifier-resolution=node flag when running your server. This enabled the ability for file paths like these to function:

  • /path/to/index where index was a file called index.js. We could omit the .js and Node would still resolve it.
  • /path/to/folder where it was assumed an index.js file would be located at /path/to/folder/index.js and Node would still resolve it.

After the move to Node.js v20+, this functionality no longer works. Instead, paths that are not pointed at a package in the /node_modules directory are assumed to be relative to the current file in your app.

So for example, if we have a file like /lib/node/parse_markdown.js and wanted to import that into our index.server.js file, we'd do something like this:

index.server.js

import joystick from "@joystick.js/node-canary";
import api from "./api/index.js";
import parse_markdown from "./lib/node/parse_markdown.js";

joystick.app({
  api,
  routes: {
    "/": (req = {}, res = {}) => {
      res.render("ui/pages/index/index.js", {
        layout: "ui/layouts/app/index.js",
      });
    },
    "*": (req = {}, res = {}) => {
      res.render("ui/pages/error/index.js", {
        layout: "ui/layouts/app/index.js",
        props: {
          status_code: 404,
        },
      });
    },
  },
}).then(() => {
  const markdown_test = parse_markdown(`## Testing 123`);
  console.log(markdown_test);
});

Here, notice the path for the parse_markdown.js file is both:

  • The relative path (again, relative to the index.server.js file) to the file.
  • Uses the full file path, including the .js suffix on the file path.

If we were to omit the .js, Joystick would still be able to resolve the path, however, it would not trigger any hot module reloading (HMR) behavior in Joystick. If we were to omit the /index.js part entirely, Joystick would be unable to resolve the path.