Skip to content

Read bs-dev-dependencies if --dev was passed. #7650

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

nojaf
Copy link
Collaborator

@nojaf nojaf commented Jul 15, 2025

Fixes #7638, I believe.

I tested https://github.com/dsiu/rewatch-dev-deps-build-test locally.

I will add a test later, but please feel free to take a look and let me know if this logic is correct.

Copy link

pkg-pr-new bot commented Jul 15, 2025

Open in StackBlitz

rescript

npm i https://pkg.pr.new/rescript-lang/rescript@7650

@rescript/darwin-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-arm64@7650

@rescript/darwin-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/darwin-x64@7650

@rescript/linux-arm64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-arm64@7650

@rescript/linux-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/linux-x64@7650

@rescript/win32-x64

npm i https://pkg.pr.new/rescript-lang/rescript/@rescript/win32-x64@7650

commit: 5bf5fc2

@nojaf
Copy link
Collaborator Author

nojaf commented Jul 15, 2025

Okay, I discovered something interesting here.

The rules of https://rescript-lang.org/docs/manual/v12.0.0/build-configuration#bs-dependencies-bs-dev-dependencies are not respected in Rewatch right now.

I can have something like:

{
  "name": "dev-dep-sample",
  "sources": [
    {
      "dir": "src",
      "subdirs": true
    },
    {
    "dir": "test",
    "subdirs": true,
    "type": "dev"
  }],
  "package-specs": {
    "module": "esmodule",
    "in-source": true
  },
  "suffix": ".res.mjs",
  "bs-dependencies": [],
  "bs-dev-dependencies": [
    "@rescript/webapi"
  ],
  "bsc-flags": []
}

And src/Demo.res with:

open WebAPI

Console.log(Global.window)

where rescript --dev will build fine and rescript legacy build will hit:

bunx rescript legacy build                                                                                                     
>>>> Start compiling
Dependency on @rescript/webapi
rescript: [625/625] src/UIEventsAPI/WheelEvent-WebAPI.cmj
rescript: [603/603] install.stamp
Dependency Finished
rescript: [5/6] src/Demo.cmj
FAILED: src/Demo.cmj

  We've found a bug for you!
  /Users/nojaf/Projects/dev-dep-sample/src/Demo.res:1:6-11

  1 │ open WebAPI
  2 │ 
  3 │ Console.log(Global.window)

  The module or file WebAPI can't be found.
  - If it's a third-party dependency:
    - Did you add it to the "bs-dependencies" or "bs-dev-dependencies" in rescript.json?
  - Did you include the file's directory to the "sources" in rescript.json?
  

rescript: [6/6] test/Foo.cmj
FAILED: cannot make progress due to previous errors.
>>>> Finish compiling (exit: 1)

build_dev_deps is the value of --dev in

pub fn compiler_args(
config: &config::Config,
root_config: &config::Config,
ast_path: &Path,
file_path: &Path,
is_interface: bool,
has_interface: bool,
project_root: &Path,
workspace_root: &Option<PathBuf>,
// if packages are known, we pass a reference here
// this saves us a scan to find their paths
packages: &Option<&AHashMap<String, packages::Package>>,
build_dev_deps: bool,
is_local_dep: bool,
and does not reflect whether the source file is type: dev and can thus use bs-dev-dependencies.

@nojaf
Copy link
Collaborator Author

nojaf commented Jul 16, 2025

Hmm, this is proving to be somewhat difficult.
For build, we have the package information, and we could do a lookup if the file is type:dev or not. We can store this when we call extend_with_children.

However, for compiler-args, we don't construct this information and this is None:

// if packages are known, we pass a reference here
// this saves us a scan to find their paths
packages: &Option<&AHashMap<String, packages::Package>>,

packages_map.insert(package_name.clone(), package);
// We need to populate the source_files meta data.
// TODO: filter with current file
let packages_map = packages::extend_with_children(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very expensive, this would scan all the files in the package. I think it would be better to see if the current file matches any of the dev paths.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of this command that it's a very low-latency for the editor tooling to know the compile arguments. Reading all the files would create a lot of overhead.

@@ -583,6 +581,7 @@ fn compile_file(
}?;
let module_name = helpers::file_path_to_module_name(implementation_file_path, &package.namespace);
let has_interface = module.get_interface().is_some();
let is_type_dev = package.is_source_file_type_dev(implementation_file_path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a semi slow lookup, if we compile a file we usually construct it from the module struct, that module struct has a field if it's a local dep. Looking up the module again from the package is unneeded, we can just pass the module attribute to this function instead.

@@ -19,6 +19,7 @@ use std::time::SystemTime;
#[derive(Debug, Clone)]
pub struct SourceFileMeta {
pub modified: SystemTime,
pub is_type_dev: bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's relevant to put here, I would put it on the Module struct

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would still need it here if we want to put it in Module struct.
packages::parse_packages will loop over all the source_files and by that time, we no longer know what "type" they had.

@@ -186,9 +186,6 @@ pub enum Command {
/// Path to a rescript file (.res or .resi)
#[command()]
path: String,

#[command(flatten)]
dev: DevArg,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't have the explicit command to build the dev deps anymore?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do, that is part of BuildArgs.
Here this is about the compile-args which the tooling calls to figure out the arguments. Tooling does not know if a file is type:dev or not.

@nojaf
Copy link
Collaborator Author

nojaf commented Jul 17, 2025

@jfrolich I added some code to traverse the rescript.json in case of compiler-arguments command.

I'm unsure how to proceed with the Module suggestion you have. Could use a technical pointer there.

@nojaf nojaf requested a review from jfrolich July 17, 2025 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

v12.beta1 - Rewatch doesn't build dev sources
2 participants