Repository: serverless-heaven/serverless-webpack (js)

Issue:
Provide a simple way to differentiate between build types
-Probably a simple one.

I do not see a simple way to differentiate during the build process between a local build (for example with `serverless-offline`), and a build to be executed on AWS.

Would it be possible to include some type of environment variable to distinguish local and AWS builds?

Best option I dound so far is `process.argv.indexOf('offline') === -1`, which works but doesn't look optimal to me.

--

Less importantly, serverless options are not passed to the build process (notably the stage). This one is less critical – as it is possible to point from `serverless.yml` to different configuration files, but still. It would be nice :)

Pull request description:
Make plugin state available in lib object
<!--
1. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the PR
2. Please follow the template, otherwise we'll have to ask you to update it and it will take longer until your PR is merged
-->

## What did you implement:

Closes #232

<!--
Briefly describe the feature if no issue exists for this PR. If possible only
submit PRs for existing issues. If the PR is trivial (like doc changes or simple
code fixes) it can be submitted without a related issue, but as soon as it adds
or changes functionality, a related issue should be present.
-->

The lib object (`slsw.lib`) now exposes a `webpack` map object that will contain important state information for the webpack config.

Right now, I added a new `isLocal` property there, that will be true, if the plugin is invoked by one of these methods: `invoke local`, `offline` and `step-functions-offline`.
This is very useful, to enable development build mode on local runs, but build for production otherwise together with Webpack 4.

```js
// webpack.config.js
const slsw=require('serverless-webpack');

module.exports = {
  ...
  mode: slsw.lib.webpack.isLocal ? "development" : "production"
  ...
};
```

## How did you implement it:

<!--
If this is a nontrivial change please briefly describe your implementation so its easy for us to understand and review your code.
-->

Added a webpack object to the library and let isLocal default to false. Immediately after invocation of one of the local hooks, the flag is set to true, before resolving the webpack configuration file. This way, the flag is available in the configuration and can be used there.

## How can we verify it:

<!--
Add any applicable config, commands, screenshots or other resources
to make it easy for us to verify this works. The easier you make it for us
to review a PR, the faster we can review and merge it.

Examples:
* Step by step description, how to verify
* Screenshots - Showing the difference between your output and the master
* Other - Anything else that comes to mind to help us evaluate
-->

Add a mode configuration as above (or anything else that switches on the flag) to the webpack configuration. Then try to run `package` and `invoke local`. The first should have the flag set to `false`, the latter should have it set to `true`.

## Todos:

- [x] Write tests
- [x] Write documentation
- [x] Fix linting errors
- [x] Make sure code coverage hasn't dropped
- [x] Provide verification config / commands / resources
- [x] Enable "Allow edits from maintainers" for this PR
- [x] Update the messages below

***Is this ready for review?:*** YES
***Is it a breaking change?:*** NO


Patch:
diff --git a/README.md b/README.md
index d4e19a8..8cfa4ce 100644
--- a/README.md
+++ b/README.md
@@ -126,6 +126,24 @@ as that will modify the running framework and leads to unpredictable behavior!
 If you have cool use cases with the full customization, we might add your solution
 to the plugin examples as showcase.
 
+#### Invocation state
+
+`lib.webpack` contains state variables that can be used to configure the build
+dynamically on a specific plugin state.
+
+##### isLocal
+
+`lib.webpack.isLocal` is a boolean property that is set to true, if any known
+mechanism is used in the current Serverless invocation that runs code locally.
+
+This allows to set properties in the webpack configuration differently depending
+if the lambda code is run on the local machine or deployed.
+
+A sample is to set the compile mode with Webpack 4:
+```
+mode: slsw.lib.webpack.isLocal ? "development" : "production"
+```
+
 ### Output
 
 Note that, if the `output` configuration is not set, it will automatically be
diff --git a/index.js b/index.js
index 3664e8c..3f98aaa 100644
--- a/index.js
+++ b/index.js
@@ -2,7 +2,6 @@
 
 const BbPromise = require('bluebird');
 const _ = require('lodash');
-const path = require('path');
 
 const validate = require('./lib/validate');
 const compile = require('./lib/compile');
@@ -108,7 +107,10 @@ class ServerlessWebpack {
         .then(() => this.serverless.pluginManager.spawn('webpack:package')),
 
       'before:invoke:local:invoke': () => BbPromise.bind(this)
-        .then(() => this.serverless.pluginManager.spawn('webpack:validate'))
+        .then(() => {
+          lib.webpack.isLocal = true;
+          return this.serverless.pluginManager.spawn('webpack:validate');
+        })
         .then(() => this.serverless.pluginManager.spawn('webpack:compile'))
         .then(this.prepareLocalInvoke),
 
@@ -158,16 +160,25 @@ class ServerlessWebpack {
         .then(this.packageModules),
 
       'before:offline:start': () => BbPromise.bind(this)
+        .tap(() => {
+          lib.webpack.isLocal = true;
+        })
         .then(this.prepareOfflineInvoke)
         .then(this.wpwatch),
 
       'before:offline:start:init': () => BbPromise.bind(this)
+        .tap(() => {
+          lib.webpack.isLocal = true;
+        })
         .then(this.prepareOfflineInvoke)
         .then(this.wpwatch),
 
       'before:step-functions-offline:start': () => BbPromise.bind(this)
-         .then(this.prepareStepOfflineInvoke)
-         .then(this.compile)
+        .tap(() => {
+          lib.webpack.isLocal = true;
+        })
+        .then(this.prepareStepOfflineInvoke)
+        .then(this.compile)
     };
   }
 }
diff --git a/lib/index.js b/lib/index.js
index bd7186c..e85ebbe 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,5 +1,8 @@
 'use strict';
 
 module.exports = {
-  entries: {}
+  entries: {},
+  webpack: {
+    isLocal: false
+  }
 };


Test patch:
diff --git a/tests/validate.test.js b/tests/validate.test.js
index 3ce2488..42c6de5 100644
--- a/tests/validate.test.js
+++ b/tests/validate.test.js
@@ -712,5 +712,26 @@ describe('validate', () => {
         }).to.throw(new RegExp(`^Function "${testFunction}" doesn't exist`));
       });
     });
+
+    describe('webpack', () => {
+      it('should default isLocal to false', () => {
+        const testOutPath = 'test';
+        const testConfig = {
+          entry: 'test',
+          context: 'testcontext',
+          output: {
+            path: testOutPath,
+          },
+        };
+        module.serverless.service.custom.webpack = testConfig;
+        return expect(module.validate()).to.be.fulfilled
+        .then(() => {
+          const lib = require('../lib/index');
+          expect(lib.webpack.isLocal).to.be.false;
+          return null;
+        });
+      });
+    });
+
   });
 });