Skip to content
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

Integration with deploy package function #130

Merged

Conversation

franciscocpg
Copy link
Member

Fixes issue #107.
Also PR #110 seems incomplete and it looks like the author is not working on it anymore.
Here is a working webpack.config.js

const yaml = require('js-yaml');
const fs = require('fs');
const path = require('path');
const nodeExternals = require('webpack-node-externals');

const handlerRegex = /\.[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/;
const include = './_webpack/include.js';
const entries = {};

const doc = yaml.safeLoad(fs.readFileSync('serverless.yml', 'utf8'));

// If we pass a function, package just it 
// not all the functions listed on serverless.yml
const serverlessFunction = process.env.serverlessFunction;
const functions = serverlessFunction ?
  { serverlessFunction: doc.functions[serverlessFunction] }
  : doc.functions;
for (const key in functions) { // eslint-disable-line guard-for-in
  const handler = functions[key].handler;
  const entryKey = handler.replace(handlerRegex, '');
  entries[entryKey] = [include, `./${entryKey}.js`];
}

module.exports = {
  entry: entries,
  target: 'node',
  // Generate sourcemaps for proper error messages
  devtool: 'source-map',
  // Since 'aws-sdk' is not compatible with webpack,
  // we exclude all node dependencies
  externals: [nodeExternals()],
  // Run babel on all .js files and skip those in node_modules
  module: {
    loaders: [{
      test: /\.js$/,
      loaders: ['babel-loader'],
      include: __dirname,
      exclude: /node_modules/,
    }]
  },
  output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, '.webpack'),
    filename: '[name].js'
  }
};

@afhammad
Copy link

afhammad commented Jun 8, 2017

Installed and tested this PR

Although Lambda shows this when opening the function on AWS console:

Your Lambda function "fnName" cannot be edited inline since the file name specified in the handler does not match a file name in your deployment package.

The function does get packaged correctly and work.

sbkn added a commit to sbkn/serverless-webpack that referenced this pull request Jun 20, 2017
@HyperBrain HyperBrain mentioned this pull request Jun 30, 2017
@franciscocpg
Copy link
Member Author

@HyperBrain
Related to #134
This PR replaces your PR #110.
I have used it in some of my projects for about 1 month now without any problems.

@HyperBrain
Copy link
Member

@franciscocpg Ok. Then I will close my PR.

@HyperBrain
Copy link
Member

Regarding the new label please check my comment #134 (comment)

@HyperBrain
Copy link
Member

@franciscocpg Can you check if #91 is also replaced, as it also about hooking package function and on the first sight does something quite similar?

@franciscocpg
Copy link
Member Author

franciscocpg commented Jun 30, 2017

@HyperBrain. Yes it replaces.
In fact I've tested the branch from #91 and it's not working because the zip file is not being copied to .serverless folder.

lib/validate.js Outdated
@@ -18,6 +18,9 @@ module.exports = {
throw new this.serverless.classes
.Error('The webpack plugin could not find the configuration file at: ' + webpackConfigFilePath);
}
if (this.options.function) {
process.env.serverlessFunction = this.options.function;
Copy link
Member

Choose a reason for hiding this comment

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

Is there any reason why an additional environment variable is set here? I would not set anything in the process' environment as it is global. Better would be to set it as member of the plugin object with this.XXX = ... in case it is needed by the plugin itself.
If it is meant to be used in the vars of serverless.yml, you can reference it via options as ${opt:function} there, even with specifying a default in case it is not set (${opt:function, 'none'}).

Copy link
Member Author

Choose a reason for hiding this comment

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

@HyperBrain I'm using this env var with webpack.config.js. But reading further comments I realized that you guys have suggested a better approach.

resolve();
});

readStream.pipe(fs.createWriteStream(artifactFilePath));
Copy link
Member

Choose a reason for hiding this comment

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

Can this call itself throw, or does it delegate any errors to the 'error' event in any case?
Otherwise the pipe call itself should be wrapped into a try/catch and call reject() in the catch block.

Copy link
Member Author

@franciscocpg franciscocpg Jul 3, 2017

Choose a reason for hiding this comment

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

@HyperBrain pipe emits an error event so the better approach would be:

readStream.pipe(fs.createWriteStream(artifactFilePath)).on('error', (err) => {
  reject(err);
});

Copy link
Member

Choose a reason for hiding this comment

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

Sounds reasonable 👍

@johnf
Copy link

johnf commented Jul 1, 2017

I like this approach. I wonder though if we should provide a utility function. Something like

const slsw = require('serverless-webpack');

module.exports = {
  entry: slsw.entries(),
  // other bits
  output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, '.webpack'),
    filename: '[name].js'
  }
};

@HyperBrain
Copy link
Member

HyperBrain commented Jul 3, 2017

@johnf Interesting idea 🙌 . As this is out of scope for this particular PR, would you mind creating a separate issue for the "library extension" of the plugin with a detailed description what problem it addresses? Thanks.
Sorry, my fault ;-) Yes, this would eliminate the transfer of the function entry point via environment variables and keep the implementation isolated within the plugin. The plugin could expose a lib export instead of entries() where we can integrate other library functions as soon as we need others.
Then it would be: entry: slsw.lib.entries - makes more sense as property getter for me.

@hassankhan Any thoughts on this? If we agree to have this extended in that way, we might delay the "deploy function" support to version 2.1.0, so that we can get the other things out in the meantime.

@hassankhan
Copy link
Contributor

hassankhan commented Jul 3, 2017

I think having exported entries is a pretty cool idea 👍 .

We (at work) don't really do single function deploys, so my experience is a bit limited 😅 . My only worry would be to inadvertently affect whole package deploys. That said, it would save a lot of trouble having to manually sync serverless.yml and webpack.config.js and I'd be up for pushing to v2.1 so we can test it properly.

@HyperBrain
Copy link
Member

Ok. I'll tag it accordingly... we will do function deploys as soon as this is done 😄

@HyperBrain
Copy link
Member

HyperBrain commented Jul 5, 2017

@franciscocpg Do you need any help or more information with the entries fix? I could create a separate branch in the repository to consolidate the feature, so that we can add this with a separate PR before it finds its way to master.

@franciscocpg
Copy link
Member Author

franciscocpg commented Jul 5, 2017

Hi @HyperBrain
So if I don't misunderstood anything we are going to move this logic (with some modifications) from webpack.config.js

const entries = {};

const doc = yaml.safeLoad(fs.readFileSync('serverless.yml', 'utf8'));

// If we pass a function, package just it 
// not all the functions listed on serverless.yml
const serverlessFunction = process.env.serverlessFunction;
const functions = serverlessFunction ?
  { serverlessFunction: doc.functions[serverlessFunction] }
  : doc.functions;
for (const key in functions) { // eslint-disable-line guard-for-in
  const handler = functions[key].handler;
  const entryKey = handler.replace(handlerRegex, '');
  entries[entryKey] = [include, `./${entryKey}.js`];
}

to our plugin (a new file called index.js or lib.js) and then export entries (through lib expose) so one could use like this at webpack.config.js:

const slsw = require('serverless-webpack');
module.exports = {
  entry: slsw.lib.entries,
  // other bits
  output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, '.webpack'),
    filename: '[name].js'
  }
};

Did I understand correctly?

@HyperBrain
Copy link
Member

I understood it that way 😄 . The webpack config should have no knowledge of Serverless internals, so everything that interacts directly with the plugin or Serverless should be in the plugin.

After a solution is finsihed we also should test the behavior with all possible configurations (may it be the entries retrieved from the plugin or statically set entries).

@franciscocpg
Copy link
Member Author

Sorry for the late, guys. I was very busy these days.
I made the changes we've discussed here and also I've updated examples folder.
IMO babel-dynamically-entries (entries retrieved from the plugin) and babel-multiple-statically-entries (statically set entries) examples are a good place to do some manual tests for this PR (sls deploy, sls deploy function -f first, sls deploy function -f second, sls webpack invoke -f first, sls webpack invoke -f second).
I think this PR is still a WIP because I didn't add any specs to tests (hope to do this ASAP) but it looks like everything is working as expected.

@HyperBrain
Copy link
Member

@franciscocpg Great stuff and a big thank you 🙌 . I will test it over the weekend and review the PR again.

@HyperBrain
Copy link
Member

Yes, given that your fork's master is up-to-date with the webpack's master 👍 .
But first remove the merge commit with "reset"

@HyperBrain
Copy link
Member

HyperBrain commented Jul 24, 2017

According to the git docs (https://git-scm.com/docs/git-rebase) it should be git rebase --onto master or as you said git rebase master

@HyperBrain
Copy link
Member

I managed to rebase the commits locally. If you agree, I can commit them back to your branch into the PR.

@franciscocpg
Copy link
Member Author

Ok @HyperBrain

@HyperBrain
Copy link
Member

Can you check if "enable edits by maintainers" is checked in the PR?

@franciscocpg
Copy link
Member Author

I've just checked Allow edits from maintainers now

@HyperBrain
Copy link
Member

It worked 💯

You can now pull the branch again locally. It is now rebased onto the current master.

"babel-polyfill": "6.13.0",
"babel-preset-env": "^1.6.0",
"serverless-webpack": "file:../../",
"webpack": "^1.13.1"
Copy link
Member

@HyperBrain HyperBrain Jul 24, 2017

Choose a reason for hiding this comment

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

As we support any webpack version now, maybe using webpack 2 in the examples would be good. What do you think?

... or at least in some examples.

Copy link
Member Author

Choose a reason for hiding this comment

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

👍
I'm going to update it

Copy link
Member Author

@franciscocpg franciscocpg Jul 25, 2017

Choose a reason for hiding this comment

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

I've updated all examples dependencies and tested all folders.
It looks like everything is working as expected.
Also I've added yarn to examples.

- Adding yarn to examples
- Fix typescript example
@franciscocpg
Copy link
Member Author

@HyperBrain
I've added tests (file validate.test.js).

@HyperBrain
Copy link
Member

I found an issue with handlers in arbitrary paths when testing with one of our bigger production projects.
I fixed it and added the commits. All my tests now worked properly.
Additionally I added lodash and used the serverless framework to retrieve the service functions which is the proposed way to do that.
This should be good to go now :)

@franciscocpg
Copy link
Member Author

franciscocpg commented Jul 26, 2017

Nice @HyperBrain!
Just a note about this commit

  • b4a9e1c Removed yarn lock file. yarn should use package-lock.json

It looks like yarn isn't using package-lock.json right now: yarnpkg/yarn#3614
So if I ran yarn at the root of this repository, it's going to generate a yarn.lock.
According to the issue above right now we should choose to support package-lock.json (npm) OR yarn.lock (yarn).
Maybe in the future we could use yarn with package-lock.json.
This thread also may be helpful: https://stackoverflow.com/a/44904494

@HyperBrain
Copy link
Member

@franciscocpg Yeah, at the moment it seems to be quite a mess with the different package lock mechanisms. Maybe we should remove the lock files completely for now, and use it as soon as the tools (npm and yarn) can work with the same one.

@franciscocpg
Copy link
Member Author

@HyperBrain
IMO we should remove package-lock.json and add yarn.lock. Of course this means that we are "officially" migrating our node package manager to yarn (maybe we should open another issue for this discussion?).
But I don't think is a good ideia to remove lock files for now. I think we should decide if we migrate to yarn (adding yarn.lock and removing package-lock.json) or keep with npm as our official node package manager (keeping package-lock.json).

@franciscocpg
Copy link
Member Author

For this PR maybe we should keep npm and create a new issue about migration to yarn so community could contribute with opinions.
What do you think @HyperBrain ?

@HyperBrain
Copy link
Member

That sounds good to me. This PR should not invent or change things other than the problem solved ;-)
I will open a separate issue for the yarn/npm discussion.

@HyperBrain HyperBrain merged commit 22a460d into serverless-heaven:master Jul 26, 2017
@franciscocpg franciscocpg deleted the deploy-package-function branch July 26, 2017 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants