-
Notifications
You must be signed in to change notification settings - Fork 417
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
Support skipping webpack on a per function basis #256
Conversation
@johnf Thanks for the PR 👍 . One question: Normally all functions with runtimes other than node should not be webpacked in a mixed project. So wouldn't it be better to disable webpack for all these runtimes rather than having the user to add a flag where the plugin actually knows that it would not work? |
@HyperBrain That is an excellent point. I was so focussed on making my problem go away I didn't think of that! |
index.js
Outdated
.then(this.packageModules), | ||
'before:deploy:function:packageFunction': () => { | ||
if (this.options.functionObj.webpack === false) { | ||
return; |
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.
All hooks must return promises. We cannot guarantee that the caller is aware that a non-promise can be returned that cannot be awaited. As we are a plugin we must make no assumptions about our host.
return BbPromise.resolve();
index.js
Outdated
.then(this.compile) | ||
.then(this.wpwatch), | ||
'before:offline:start': () => { | ||
if (this.options.functionObj.webpack === false) { |
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.
Offline is used to simulate the service, not a single function (and will recompile in case of a file changed).
So imo the checks on offline:start
and offline:start:init
must be removed, as this would be never called.
lib/validate.js
Outdated
@@ -83,6 +83,10 @@ module.exports = { | |||
_.merge(entries, entry); | |||
} else { | |||
_.forEach(functions, (func, index) => { | |||
const data = this.serverless.service.getFunction(func); | |||
if (data.webpack === false) { |
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.
Check for the runtime here - not the manually set flag, as discussed in my comment.
Additionally you create an entries array here that is shorter than the actual number of functions in the service.
This might fail in the compile and deploy steps with individual packaging when the entries have to be mapped back to the actual functions by index. A better way would be to only iterate over the supported functions (i.e. node.js) in all places then, instead of doing the check within the for loop. That would catch all possible combinations.
const supportedFunctions = _.filter(functions, func => !func.runtime || _.includes([ 'nodejs6.10', ... ] func.runtime);
_.forEach(supportedFunctions, (func, index) => {
@johnf We also should check that the changes do not affect other providers like Google and OpenWhisk that currently work with the plugin. Not sure yet, how to do that - maybe we have to to some tests with the PR there. |
So If we want to be 100% correct and support all the providers then I've come up with this.nodeRuntime = () => {
const provider = this.serverless.service.provider.name;
const runtime = this.options.functionObj.runtime || this.serverless.service.provider.runtime;
const jsOnlyProviders = [ 'azure', 'google', 'webtasks' ];
if (jsOnlyProviders.include(provider)) {
return true;
}
if (provider === 'openwhisk' && runtime === null) {
return true;
}
return /^nodejs/.test(runtime);
}; I think this might be a bit tedious and will be prone to errors if things change in the future. I think instead we assume that the top level runtime is a javascript runtime and then we just check if a specific provider has been set on the function. (I could document this in the readme). this.nodeRuntime = () => {
const runtime = this.options.functionObj.runtime;
return !runtime || /^nodejs/.test(runtime);
}; Thoughts? |
lib/validate.js
Outdated
} else { | ||
_.forEach(functions, (func, index) => { | ||
const entry = getEntryForFunction.call(this, functions[index], this.serverless.service.getFunction(func)); | ||
if (this.hasNodeRuntime(serverlessFunction)) { |
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.
@johnf Did you check if this works with serverless invoke local
in case you invoke a non-node function?
The entries object will end up empty in this case (because the single function is skipped - which is ok), but what will webpack do in this case?
If that works, I'll give it a go and it will be part of 4.1.0
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've done a bunch of testing of different scenarios. Amended the code to skip running webpack in the right places.
One caveat though, in a mixed project you have to package individually. This is because if you just do an sls deploy
the serverless-webpack code takes over and only packages up the js files. It will ignore the rest of the project.
I've added a note to the README. Feel free to edit or move it somewhere else in there.
except I've broken the tests because of the way I added in |
@HyperBrain Any thoughts on preferred approach here. |
Imo, the helper functions should be put into a separate file that exports them (to keep the same semantics throughout the project). I have one question to the empty config check - I don't completely understand the reason for that. Wouldn't it mean in this case, that there are no node functions at all in the project, or it is misconfigured? Is having a project with the plugin enabled but only Python methods defined valid? Can you please shed come ligt onto that? |
@HyperBrain With regards to the empty check it depends on the call path. For things like packModules an earlier hook will have gone through validate but I don't think I was able to pull the runtime info anymore. So it was easier to check if a webpack config had been generated and skip on that basis. It usually happens when something is called with |
Looks good now. I'll do some tests with our projects and fix the unit tests to test for the newly introduced code branches, so that Coveralls is happy again. |
Hi, is there anything I can do to help get this integrated? Just ran into this issue today and was excited to find that there might already be a solution, but then heard the sad trombone when I saw that it's not landed yet... |
@mjmac Oh sorry, I lost this entirely from my sight. If someone could add the unit tests, so that code coverage stays up again, I'll merge it (just do a PR on top of this one). |
I have tried to add test but found that it's not easy because of mutations and mocks. Is there another way to skip Webpack for certain functions, perhaps, in https://github.com/serverless-heaven/serverless-webpack/blob/master/index.js so that the lib does not need to be changed a lot? |
I have tried to do something myself over here https://github.com/serverless-heaven/serverless-webpack/compare/master...OrKoN:skip-non-node-functions?expand=1 It seems to work but the non-node functions get packaged weirdly: it looks like every file from the project is added to the archive and include/exclude settings are ignored.
|
@OrKoN Sorry for the huge delay. I think the issue with packaging everything is, that with the conditional package property on the functions, Serverless' own packaging is triggered when it inspects these functions. This leads to the fact that Serverless starts its complete packaging for the service and just overwrites webpacks package output (and Serverless will just include everything). I think we must be a bit more experimental and sophisticated here and tune the in-memory service definition in a way that we hide any triggering parts from serverless or just call the very specific Serverless function packaging from our own packager, instead of having it act as fallback (and thus destroying all our outputs) |
@HyperBrain no problems. It seems like it's a very hacky workaround :-) For now, I decided that I am not going to mix different languages in one project. But the feature seems to be very useful, eventually. |
@HyperBrain is there any progress on this? I'm also coming up against this problem using a serverless configuration with multiple environments. This is a real deal breaker |
Hi @liam-betsworth , I agree that this issue gets more pressing as more runtimes appear (at least on AWS). As this implementation is somehow hacky, I'm still thinking about a proper solution. |
Are there any updates on this? I am also trying to mix nodejs and python functions in one serverless project. |
Since this PR hasn't been merged yet; Do you have suggestions on forcing this behavior without changing the plugin? Is there a way to use webpack.config.js to skip over functions? |
Facing the same issue. I have both python2.7 and JS functions in my project. I'm currently I'm using lerna and have 2 packages: one with the JS functions and serverless-webpack, and one with the python without serverless-webpack. It's somewhat hacky and necessitate some cross-packages ${cf:}, but it's doing the trick. I'm not sure it's the most elegant way but since I was already using Lerna to separate lambda resources and database/vpc resources it felt the easiest way to implement |
Any update on this? What does it need to get integrated? This feature would be of much help 😄 . |
Any update on this? I'm currently maintaining a forked version of serverless-webpack for this functionality. It's not ideal. |
Any updates on this? Very desired functionality. |
@HyperBrain can someone review #530? It appears to be a competing for this functionality. |
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.
Hi, may you please address the merge conflicts? Thanks.
See #579 available since 5.3.3 |
I almost started working on resolving the conflicts yesterday lol. @j0k3r you can use me as a human merge conflict resolution bot. Which PR should I rebase so you merge it and I work on next one? |
What did you implement:
Closes #255
How did you implement it:
We add
webpack: false
to functions where we want to skip webpack.In
index.js
in the relevant hooks we check if this is set and just return. This will run the original hook.How can we verify it:
Examples:
In serverless.yml add a function similar to
run
sls deploy -f get_oai
and the .serverless/get_oai.zip should contain everything in the project. Webpack will not runTodos:
Is this ready for review?: YES
Is it a breaking change?: NO