How to deal with modules?

i want to have module structure like this

module Customers {
  module Profile {}
  module Settings {}
}
module Administrators {
  module Profile {}
  module Settings {}
}

with file structure like this

Customers/Profile.res
Customers/Settings.res
Administrators/Profile.res
Administrators/Settings.res

EDIT: See answer from @johnj, it’s much better :smiley:

Hey! In ReScript/ReasonML/OCaml file names are always modules and folders do not mean anything from namespacing point of view.

If you want the module structure you described, you need to have exactly these two files

Customers.res
Administrators.res

Both files then contain two modules, Profile and Settings.

On the other hand, if you (will) have huge amount of files and wish to create a folder structure, you still need to namespace each individual file as they were all in the root. A popular strategy is to do something like this:

Customers/Customers_Profile.res
Customers/Customers_Settings.res
Administrators/Administrators_Profile.res
Administrators/Administrators_Settings.res

The modules are accessed as there were no folders at all, e.g. Customers_Profile etc…
Here’s a nice in-depth article about the latter strategy: https://dev.to/yawaramin/a-modular-ocaml-project-structure-1ikd

5 Likes

This is covered in the article @TomiS linked, but just to fully illustrate how you may want to implement your example:

File structure

.
├── Administrators
│   ├── Administrators.res
│   ├── Administrators_Profile.res
│   └── Administrators_Settings.res
└── Customers
    ├── Customers.res
    ├── Customers_Profile.res
    └── Customers_Settings.res

Inside Administrators/Administrators.res

module Profile = Administrators_Profile
module Settings = Administrators_Settings

Inside Customers/Customers.res

module Profile = Customers_Profile
module Settings = Customers_Settings

You can now access Administrators.Profile, Customers.Settings, etc.

2 Likes

Ah, my bad. It is indeed possible by using the “proxy” modules. I’ve even used that approach, so that makes it even more embarrassing :smiley: (I’ll edit my answer)

is there a way to rename files as part of transpilation for example to have Customers/Profile.res that is visible to compiler as Customers_Profile.res

i don’t mind writing proxy modules and/or using modules with underscore instead of dot (Customers_Profile vs Customers.Profile)

but prepending file path in file name defeats purpose of creating folder structure

Exactly! Since all file names in the project are unique and globally available, it doesn’t really make sense to impose an arbitrarily nested directory hierarchy, and as long as you are not running with hundreds of modules, just keep it simple and put everything e.g. in a single components / bindings folder etc.

Advantage of this is that you don’t need to follow around module aliases and it’s extremely easy to find files (e.g. you are using somewhere, just fuzzy search for ArticleCard and the first hit is your file).

It’s really relieving to not think about logical units such as folders every time and it will spare you a lot of time refactoring your code later when you suddenly realize that those components should be called differently etc.

2 Likes

Also being able to later move files freely around in the source folder or making a nested module its own file without the need to update references on it is very nice. One of the features I really miss in other languages.

3 Likes

Hey, old topic but I just came across this - what’s the deal with double vs single underscores. I see some using double underscores and some using a single. Is that just preference or is it convention for something?

I believe the convention comes from OCaml where modules are named In_Pascal_Case_with_Underscores. So the double underscore clearly separates two modules having such names.

In ReScript it’s more conventional to has just RegularPascalCase, so a single underscore is enough.

I saw no explicit recommendation to use one or two underscores for module nesting in ReScript.

1 Like