Conversation
|
Just a quick heads up. I investigated futher into this issue today and found out that we can use a solution which won't introduce an additional temp file. It looks like using I'll update this PR the upcoming days with a solution for this. |
c1a9e7e to
38aec17
Compare
|
@ryanmurakami @cjelger @arabold @sbstjn @ajkerr I just pushed a fix for the issues with the current dev dependency exclusion. The changes which were applied can be found in the PR description. Would be nice if you could take this for a test drive and see if it resolves all the issues you brought up. This way we can get this PR in a mergeable state and publish it in a patch release the upcoming days. Thanks in advance 👍 |
38aec17 to
195f283
Compare
|
@pmuens The PR fixes the issues we were seeing with our project. Thanks! |
| // after that re-include the production relevant modules | ||
| exclude = _.union(exclude, [`${pathToDep}node_modules/**`]); | ||
| include = _.union(include, includePatterns); | ||
| childProc.stdout.on('error', () => resolve(result)); |
There was a problem hiding this comment.
Wouldn't it be reasonable to abort in case of error and leave the exclude and includes untouched?
There was a problem hiding this comment.
Yes, that sounds like good idea @arabold 👍
| let include = []; | ||
| const exAndIn = { | ||
| include: [], | ||
| exlucde: [], |
|
@pmuens Same result but worse. :-/ Since you changed to looking at dev dependencies, the output stops and one of the lines ends up excluding the entire |
|
I'm going to mess around with using a temp file, see if I can make any progress on that. |
|
@pmuens Didn't you have a temp file version before? Maybe reverting to that would fix @ryanmurakami 's issue. |
|
@pmuens @HyperBrain So, it looks like using a tempfile fixes the issue. I can push that code, but there are a couple of concerns. The Anyways, I pushed my changes to my repo in this commit: ryanmurakami@f137fbc I can clean this up if you guys think it's a good approach. |
|
🤔 thanks for taking another deep dive into this @ryanmurakami 👍 @HyperBrain yes, we had this file based approach (originally brought up by @arabold 🥇). It would be nice if we could replace the file creation and rely on streams (since IO could be unreliable and slow). We switched from Isn't there any way to stream the data from I'll take a look into your commit @ryanmurakami tomorrow. Would be really nice if we could fix this issue w/o introducing an external file. |
|
@pmuens I did a little more work and refactored the code so it's a little easier to riff on different approaches: https://github.com/ryanmurakami/serverless/tree/fix-dev-dependency-exclusion-bug You can modify the It appears this is some type of buffer paging that macOS is doing on the stdout stream. I don't see any differences when using I haven't been able to think of another approach except for a temp file. The only other thing is if there was some way we could emulate a file but actually write it directly in memory. I'm not even sure that's possible though. |
|
Also, thanks so much for working hard on this @pmuens 🙏🙏🙏 |
|
The reason both Long story short: From what I understand only a temp file will fully solve this problem for all platforms. |
|
I believe that npm has purged most of their open GitHub bugs (for better or worse), and are only working on npm5+. Given that Node's current LTS is 6.x with npm 3.x, I don't think waiting for an npm fix is a great option. |
|
Thanks for the in-depth discussion about this 👍 I found @arabold research comment and will link it here: #3737 (comment) (thanks for looking into this @arabold 👍). Seems like there's no way around a file-based approach. Next up I'll take a look @ryanmurakami implementation (thanks for the deep dive!) and update this PR so that we can hopefully fix this soon (and release a patch). Again. Thanks for all the work and discussions on this here 💯! Edit: This issue might be especially interesting: nodejs/node#6456 |
195f283 to
9a3d9eb
Compare
|
I just looked through @ryanmurakami branch (thanks for putting this together!) and pushed an update and switched back to the tmp file approach. I kept all the operations async. Works on my machine. Would be nice if you could try it and see if it fixes the problem. Another question: Is the exec command ( |
| }) | ||
| .then(() => fs.readFileAsync(nodeDevDepFile)) | ||
| .then((fileContent) => { | ||
| const dependencies = fileContent.toString('utf8').split('\n'); |
There was a problem hiding this comment.
Shouldn't this be deduplicated (as it might be a combination of multiple package.json files and could contain duplicates)?
const dependencies = _.uniq(_.split(fileContent.toString('utf8'), '\n'));
I also suggest to use lodash, as otherwise you have to test here that fileContent is not nil, before using toString().
There was a problem hiding this comment.
Good catch @HyperBrain 👍 I'll update it so that it uses Lodash.
| // after that re-include the production relevant modules | ||
| exclude = _.union(exclude, [`${pathToDep}node_modules/**`]); | ||
| include = _.union(include, includePatterns); | ||
| if (dependencies.length) { |
There was a problem hiding this comment.
if (!_.isEmpty(dependencies))
...
|
|
||
| /* eslint-disable no-use-before-define */ | ||
| /* eslint-disable no-param-reassign */ | ||
| /* eslint-disable consistent-return */ |
There was a problem hiding this comment.
Which lines are affected by this? Can the implementation be changed to comply to the rule, or is there a specific reason, why this cannot be done?
There was a problem hiding this comment.
Addition: Imo it's generally bad to disable linter checks per file. It would be better to put an elslint-disable-line consistent-return at the specific location and comment why this rule override is needed there.
There was a problem hiding this comment.
Thanks @HyperBrain 👍 Yes, that's a good suggestion. I'll add the comments to the lines.
| const childProc = childProcess.spawn('npm', | ||
| ['ls', '--dev=true', '--parseable=true', '--silent'], | ||
| return childProcess.execAsync( | ||
| `npm ls --dev=true --parseable=true --silent >> ${nodeDevDepFile}`, |
There was a problem hiding this comment.
If you append to ${nodeDevDepFile} then you should make sure to delete it before the BbPromise.mapSeries() above . Otherwise it might have some surprises in store for you. Why not put it in the artifacts folder (i.e. .serverless or whatever is provided in the --package command line) though? I think that folder is cleaned and recreated on every packaging?
There was a problem hiding this comment.
🤔 I thought mapSeries runs sequential so there shouldn't be any race conditions while appending to the file.
Right now the name of the nodeDevDepFile is generated with a hash in the name and stored in the OS tempDir. Putting it in .serverless could also be an option though.
There was a problem hiding this comment.
My concern is if there's a leftover from a previous run. Thus the file already exists before serverless is started.
There was a problem hiding this comment.
The random number you're using does certainly help though. Didn't notice this before.
There was a problem hiding this comment.
Alright gotcha. Yes, that's a good catch 👍 .
I re-thought about keeping it in .serverless however IMHO keeping it in a tmpdir which is cleaned up by the OS is slightly better since the .serverless dir could change (although we have utils to get the path) and is used to store deployment artifacts.
bb28001 to
ed029a3
Compare
|
Here's a test service which can be used to verify that the package exclusion works correctly. It consists of 3 different directory levels where each level has a respective You can also e.g. only run |
|
@pmuens Thanks again for your continued work on this! I'm encountering something different, but I think it has to do with how I'm testing and not the actual code. I'm testing the PR by doing an |
|
Okay, I used On a side note, it takes almost 3x longer to package my large project with this fix. I noticed the time is mostly spent after the dependencies are all resolved, most likely when |
Nice! Thanks for testing it out @ryanmurakami 👍 Great to hear that it finally works on your machine!
🤔 That's definitely smth. we should look into next up. Thanks for bringing this to our attention! 👍 I pushed some minor changes and fixed / add a couple of tests. This PR is GTM from my side. /cc @eahefnawy |
| }) | ||
| .then(() => fs.readFileAsync(nodeDevDepFile)) | ||
| .then((fileContent) => { | ||
| const dependencies = _.filter( |
There was a problem hiding this comment.
Could you use _.compact here instead of _.filter?
https://lodash.com/docs/4.17.4#compact
There was a problem hiding this comment.
Thanks. That's a good idea @ryanmurakami 👍
|
@pmuens following your instructions, I was able to validate that exclusion works as expected! 👍 G2M! 😊 |
|
I deployed https://github.com/react-boilerplate/react-boilerplate.git over lambda in AWS by cloudformation and I wanted to test this app now by lambda function , any ideas on how to test its localhost |
|
@sasidharkanumuri thanks for commenting 👍 I think the best place to get help for such problems would be the Serverless Gitter of our Forum. Let us know if you need any help with that 👍 |
|
Thanks @pmuens I just posted my question in the Serverless Gitter forum |
Great! Thanks for that 👍 Hopefully your problem can be resolved soon! |
|
I'm still getting the dev dependencies, or at least most of them using serverless v1.23.0 and serverless-plugin-typescript v1.1.3 Do I need a later version to get this branch? Or it seems packages are being linked / reused or peer dependency more now than nesting under the same package in npm 5 and yarn, could this be part of the issue? Sorry i'm kind of a noob. |
|
I'm facing a few issues related to this. I've created a sample repo here: https://github.com/tommedema/serverless-mono-example Steps to reproduce
Note that the package now has a few dev dependencies which shouldn't be there:
I think this may be because serverless is hardcoding calls to |
|
On a new project using the latest NPM vs. yarn and node 8 vs. typescript I didn't see this issue like I was with typescript/yarn/node 6. Not sure if any of those factors made the difference. What I ended up doing was using gulp to copy my package.json and lock file over to the output directory then running yarn with the --prod flag so it wouldn't install any of the dev dependencies |
|
@andythecoderman I upgraded yarn, npm etc. but still face the same issue. Re your workaround: when I copy package.json to an output directory, yarn will fail to install packages from the workspace: error An unexpected error occurred: "https://registry.yarnpkg.com/@org%2frandom: Not found" |
What did you implement:
Closes #3827
Closes #3874
Closes #3869
Fixes a bug where the dev dependency exclusion errors out due to a large number of dependencies (and string capacity limitations).
Also fixes the error where exclusion is not working anymore.
Speed is increased due to async operations ran concurrently.
How did you implement it:
Bluebird Promise.mapexecSynctospawnto get a stream (mitigates the buffer limitexecSyncintroduces where the packages for exclusion are capped)npm ls --prod=truetonpm ls --dev=trueso that we exclude only thedevdependencies rather than excluding allnode_modulesand then re-including the prod dependencies. This should avoid side-effects when the exclusion of dev dependencies fails.How can we verify it:
Take the steps described here: #3737 (comment)
Todos:
Is this ready for review?: YES
Is it a breaking change?: NO