-
Notifications
You must be signed in to change notification settings - Fork 32
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
Handle file: dependencies #18
base: master
Are you sure you want to change the base?
Conversation
Why does the test fail? |
Because I'm using |
@zhenyavinogradov please review again, tests work now |
default.nix
Outdated
echo 'building npm cache' | ||
chmod u+w ./package-lock.json | ||
NODE_PATH=${npmModules} node ${./mknpmcache.js} ${cacheInput "npm-cache-input.json" lock} | ||
|
||
echo 'building node_modules' | ||
npm $npmFlags ci | ||
patchShebangs ./node_modules/ | ||
${concatMapStringsSep "\n" (dep: "cp -r ${dep}/node_modules/* node_modules") peerDependencies} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand the logic for doing this. AFAIU this adds dependencies of local packages to node_modules
, but I think that we should respect the behavior of npm install
, and if it does not include these dependencies, we should not include them either
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if we don't include those dependencies, the resulting package won't work.
This is a good question: should we mimic the behaviour of npm
even if it means more work needs to be done manually, or do we go for "least effort" approach (as I have done here)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does that mean the package won't work if it's built with pure npm
? I think we don't have to support a case like this then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it will require additional commands if built with pure npm
(npm install
complains about peer dependencies and tells you how to install them manually). I don't know what's the reasoning for this. If there is a compelling reason not to automatically resolve peer dependencies this way, I'd be happy to remove this logic. However, if this npm behaviour is for historic reasons only, I think we should keep it the way it currently is becuase this is simply more user-friendly and simplifies the nix expressions needed to build the package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s not for historic reasons, it’s actually the opposite, npm < 3 used to install peer dependencies automatically, now it doesn’t. See npm/npm#6565.
What I’m somewhat confused about is that peer dependencies seem to be some special weird thing meant for plugins or something like this (I have no idea). These are not the same as local (file:
) dependencies, are they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Peer dependencies are transitive dependencies of local dependencies IIUC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference on peer dependencies that gets me confused: https://nodejs.org/en/blog/npm/peer-dependencies/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, ok, so I need to RTFM before writing code as it turns out.
So the peer dependency change doesn't have to do anything with the main premise of this PR -- handling file:
dependencies. It just so happens that one of the local
dependencies of LIGO's website has peer dependencies that aren't a dependency of the website itself.
Whether my logic of automatically installing peer deps is correct or not is a complex question, because it appears that the issues you've mentioned is to do with npm link
and other development-time commands that don't interest us much because nix-npm-buildpackage
is targeting CIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, IIUC, in this specific case the best solution would be to revert the peer dependency logic you added, and then... um... fix the build by either fixing the dependency that needs a peer for some reason, or adding the peer dependency to package.yaml
of the repo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I’m really with Zhenya on not doing what npm doesn’t do. I don’t really understand peer dependencies, but it kinda sounds like one’s project should declare peer dependencies of its dependencies explicitly?)
@@ -117,44 +124,53 @@ with stdenv.lib; let | |||
in rec { | |||
mkNodeModules = { src, extraEnvVars ? {} }: | |||
let | |||
localDeps = map dirOfLocal (builtins.filter isLocal (builtins.attrValues (lock.dependencies))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s not very... functional? Instead of matching, filtering, matching, mapping, you could just mapMaybe
once (drop isLocal
, make dirOfLocal
return a “maybe”).
(I’m not sure if there is mapMaybe
or catMaybes
in the nixpkgs library, but it should be there... in the meantime you can just return a list of 0/1-length and concatMap
.)
@@ -90,6 +95,8 @@ with stdenv.lib; let | |||
|
|||
commonBuildInputs = [ _nodejs makeWrapper ]; # TODO: git? | |||
|
|||
normalizeName = builtins.replaceStrings [ "@" "." "/" ] [ "_" "_" "_" ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to have some documentation (or comment) for this. Or maybe a library function.
Anyway, this set of symbols looks somewhat arbitrary to me. According to this you might need to escape way more chars than this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those are the characters that can appear in javascript package name, but can't appear in nix path name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still would be nice to have some documentation.
I found this and it says that the package name can only contain “url-safe” characters. I’m not sure what this means, but I suppose, they refer to the “unreserved characters” from the URL RFC, namely:
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
which means that the only problematic one is ~
(which you did not include in your list). (Note that both Nix and npm allow .
, but not as the first char.) @
and /
in your list, I suppose, come from the scoped packages that have the form @<scope>/<package>
and, according to the doc the restrictions for scope names are the same.
tldr; basically, it looks like you need to replace your list with just [~
, /
] and remove leading @
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also, tbh, I would probably replace both ~
and /
with -
rather than _
for readability reasons.)
default.nix
Outdated
|
||
mkdir $out | ||
mv ./node_modules $out/ | ||
cp -r ./node_modules $out/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because node_modules
can contain read-only peer dependencies now, and in that case it can't be moved.
Can you please also add a simple test case for this, so we can be sure that we don't break it in the future? |
default.nix
Outdated
packageLockJson = filteredSrc + "/package-lock.json"; | ||
|
||
packageJson = src + "/package.json"; | ||
packageLockJson = src + "/package-lock.json"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This path will change every time anything in src
changes, causing everything to rebuild. As I understand the problem is that now filteredSrc
depends on the contents of package-lock.json
, causing infinite recursion. In that case we can create another filter expression which contains only package.json
and package-lock.json
, read package-lock.json
from there, and then use it to construct a filter which will include local dependencies
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, good point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@balsoft Do you plan to address this in this PR or would you like to create a separate issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's a separate issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not do it in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe fixed it here, please take a look
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not do it in this PR?
Because it has the potential for postponing the merging of this PR forever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion caching node_modules is more important than file:
dependency support. @balsoft I can help you with finishing this PR if you want
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There're only minor fixes left as I see
f2107f6
to
9fd293f
Compare
default.nix
Outdated
metaSrc = cleanSourceWith { | ||
src = src; | ||
filter = path: type: elem (getRelativePath path) [ "package.json" "package-lock.json" ]; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filteredSrc
also has a check for canCleanSource
to support the situation when src
is a nix store path not produced by cleanSourceWith
, it should be done here as well. Also, to avoid repetition, you can make filteredSrc
a function which accepts localDeps
as a parameter and use filteredSrc []
for metaSrc
cleanedSource = cleanSourceWith { | ||
src = src; | ||
filter = path: type: elem (getRelativePath path) usedPaths; | ||
filter = path: type: any (x: elem x usedPathsRec) (dirOfRec (getRelativePath path)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed this, but I think any
should not be used here, because it will include all parent directories of a dependency, while we only want the exact directory of the dependency to be included. For example, if we have dependency file:./deps/foo
, and there also exists ./deps/extra-stuff
directory which is not used as a dependency, it will still be included in the filtered source
9fd293f
to
c4d5cf3
Compare
Just ran into this issue; are we still planning on merging this feature? |
Ligo's website uses a
file:
dependency syntax inpackage.json
. We need to handle that. It turned out to be pretty simple really.