Skip to content

Commit

Permalink
Allow custom global/local webpack config
Browse files Browse the repository at this point in the history
  • Loading branch information
Rex Scaria committed Mar 12, 2019
1 parent 76f347b commit 7635642
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 84 deletions.
18 changes: 16 additions & 2 deletions README.md
Expand Up @@ -10,13 +10,27 @@ https://serverless.com/framework/docs/providers/cloudflare/guide/quick-start/

You can have the plugin automatically bundle your code into one file using [webpack](https://webpack.js.org/). This is a great solution if you are fine with a no frills bundling.

Simply add `webpack: true` to your config block.
You can use a single global webpack config to bundle your assets. And this webpack config will be built during the packaging time, before individual functions are prepared. To use this, add `webpackConfig` to your service section in serverless config, with value as the path to the webpack config.

```yaml
service:
name: service-name
webpackConfig: webpack.config #webpack config path without js extension from root folder.
config:
accountId: ${env:CLOUDFLARE_ACCOUNT_ID}
zoneId: ${env:CLOUDFLARE_ZONE_ID}

```

You can also add a function level webpack configuration in addition to a global webpack configuration. This helps you to process bundling different for an individual function than the global webpack config explained earlier. To use this, set the webpack config path to the function level `webpack` variable. Setting function level `webpack` variable to `true` will force webpack to bundle the function script with a default web pack configuration. Setting `webpack` key to `false` will turn off webpack for the function. (i.e the function script will not be fetched from dist folder)

Simply add `webpack: true | <config path>` to your config block.

```yaml
functions:
myfunction:
name: myfunction
webpack: true
webpack: true #or the web pack config path for this function
script: handlers/myfunctionhandler
events:
- http:
Expand Down
9 changes: 7 additions & 2 deletions deploy/cloudflareDeploy.js
Expand Up @@ -34,21 +34,24 @@ class CloudflareDeploy {

Object.assign(this, accountType, ms, utils, ss, logs, validate);

const startTime = Date.now();

this.hooks = {
"deploy:deploy": () =>
BB.bind(this)
.then(this.checkAccountType)
.then(async isMultiScript => {
this.serverless.cli.log('Starting Serverless Cloudflare-Worker deployment.');
if (isMultiScript && await duplicate.checkIfDuplicateRoutes(this.serverless, this.provider)) {
return BB.reject("Duplicate routes pointing to different script");
}

if (this.getInvalidScriptNames()) {
return BB.reject(
"Worker names can contain lowercase letters, numbers, underscores, and dashes. They cannot start with dashes."
);
}

if (isMultiScript) {
return this.multiScriptDeployAll()
} else {
Expand All @@ -57,6 +60,8 @@ class CloudflareDeploy {
}
})
.then(this.logDeployResponse)
.then(k => this.serverless.cli.log(`Finished deployment in ${(Date.now() - startTime) / 1000} seconds.`))
.then(k => this.serverless.cli.log('Finished Serverless Cloudflare-Worker deployment.'))
};
}
}
Expand Down
76 changes: 44 additions & 32 deletions deploy/lib/multiscript.js
Expand Up @@ -21,25 +21,41 @@ const webpack = require("../../utils/webpack");
const ms = require("../../shared/multiscript");

module.exports = {
async multiScriptDeploy(functionObject) {
async deployScriptToCloudflare(functionObject) {
return BB.bind(this)
.then(async () => {

if (functionObject.webpack) {
await webpack.pack(this.serverless, functionObject);
}

// deploy script, routes, and namespaces
const namespaceResponse = await ms.deployNamespaces(this.provider.config.accountId, functionObject);
const workerScriptResponse = await ms.deployWorker(this.provider.config.accountId, this.serverless.service, functionObject);
const routesResponse = await ms.deployRoutes(this.provider.config.zoneId, functionObject);

return {
workerScriptResponse,
routesResponse,
namespaceResponse
};
});
.then(async () => {

if (functionObject.webpack) {
await webpack.pack(this.serverless, functionObject);
}

// deploy script, routes, and namespaces
const namespaceResponse = await ms.deployNamespaces(this.provider.config.accountId, functionObject);
const workerScriptResponse = await ms.deployWorker(this.provider.config.accountId, this.serverless, functionObject);
const routesResponse = await ms.deployRoutes(this.provider.config.zoneId, functionObject);

return {
workerScriptResponse,
routesResponse,
namespaceResponse
};
});
},


async deployScript(scriptName) {
const startScriptTime = Date.now();
const functionObject = this.getFunctionObject(scriptName);

this.serverless.cli.log(`deploying script: ${scriptName}`);
const {
workerScriptResponse,
routesResponse: rResponse,
namespaceResponse,
} = await this.deployScriptToCloudflare(functionObject, scriptName);

this.serverless.cli.log(`Finished deployment ${scriptName} in ${(Date.now() - startScriptTime) / 1000} seconds`);
return { workerResponse: workerScriptResponse, routesResponse: rResponse, namespaceResponse }
},

/**
Expand All @@ -51,29 +67,25 @@ module.exports = {

functions = functions || this.serverless.service.getAllFunctions();

if (typeof(functions) === 'undefined' || functions === null) {
if (typeof (functions) === 'undefined' || functions === null) {
throw new Error("Incorrect template being used for a MultiScript user ");
}

let workerResponse = [];
let routesResponse = [];
let namespaceResponses = [];

// scriptName is really the key of the function map
for (const scriptName of functions) {
const functionObject = this.getFunctionObject(scriptName);
// Build global webpack if available
await webpack.packGlobalWebpack(this.serverless)

this.serverless.cli.log(`deploying script: ${scriptName}`);
this.serverless.cli.log('Starting deployment');

const {
workerScriptResponse,
routesResponse: rResponse,
namespaceResponse,
} = await this.multiScriptDeploy(functionObject);

workerResponse.push(workerScriptResponse);
routesResponse.push(rResponse);
namespaceResponses.push(namespaceResponse);
// scriptName is really the key of the function map
for (const name of functions) {
const result = await this.deployScript(name);
workerResponse.push(result.workerResponse)
routesResponse.push(result.routesResponse)
namespaceResponses.push(result.namespaceResponse)
}

return {
Expand Down
8 changes: 6 additions & 2 deletions deploy/lib/singlescript.js
Expand Up @@ -64,11 +64,15 @@ module.exports = {
let workerScriptResponse;
let routesResponse = [];

// Build global webpack if available
await webpack.packGlobalWebpack(this.serverless)

// If a local webpack config defined, do that too
if (functionObject.webpack) {
await webpack.pack(this.serverless, functionObject);
}

const scriptContents = generateCode(functionObject);
const scriptContents = generateCode(this.serverless, functionObject);

cf.setAccountId(this.provider.config.accountId);
let bindings = await ms.getBindings(this.provider, functionObject)
Expand All @@ -79,7 +83,7 @@ module.exports = {
script: scriptContents,
bindings
});

workerScriptResponse = response;

for (const pattern of singleScriptRoutes) {
Expand Down
12 changes: 8 additions & 4 deletions deploy/lib/workerScript.js
Expand Up @@ -18,13 +18,17 @@
*/
const path = require("path");
const fs = require("fs");
const generateCode = thefunctionObject => {
let { script } = thefunctionObject;
const webpack = require("../../utils/webpack");

const generateCode = (serverless, functionObject) => {
let { script } = functionObject;

const rootPath = webpack.getAssetPathPrefix(serverless, functionObject)

if (path.extname(script) != ".js") {
script = script.concat(".js");
script = `${rootPath}${script}.js`
}

return fs.readFileSync(script).toString();
};

Expand Down
4 changes: 2 additions & 2 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "serverless-cloudflare-workers",
"version": "1.0.10",
"version": "1.1.0",
"description": "serverless cloudflare workers ",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -41,4 +41,4 @@
"nyc": "^13.3.0",
"proxyquire": "^2.1.0"
}
}
}
23 changes: 12 additions & 11 deletions shared/multiscript.js
Expand Up @@ -21,7 +21,7 @@ const { generateCode } = require("../deploy/lib/workerScript");

module.exports = {
getRoutes(events) {
return events.map(function(event) {
return events.map(function (event) {
if (event.http) {
return event.http.url;
}
Expand All @@ -34,19 +34,19 @@ module.exports = {
* @param {*} functionObject
*/
async getBindings(provider, functionObject) {

let bindings = [];

let resources = functionObject.resources;

if (resources && resources.kv) { // do nothing if there is no kv config
const namespaces = await cf.storage.getNamespaces();

let namespaceBindings = resources.kv.map(function(store) {
let namespaceBindings = resources.kv.map(function (store) {
return {
name: store.variable,
type: 'kv_namespace',
namespace_id: namespaces.find(function(ns) {
namespace_id: namespaces.find(function (ns) {
return ns.title === store.namespace;
}).id
}
Expand Down Expand Up @@ -76,10 +76,11 @@ module.exports = {
* @param {*} service
* @param {*} functionObject
*/
async deployWorker(accountId, service, functionObject) {
async deployWorker(accountId, serverless, functionObject) {
const { service } = serverless;
cf.setAccountId(accountId);

const contents = generateCode(functionObject);
const contents = generateCode(serverless, functionObject);
let bindings = await this.getBindings(service.provider, functionObject);

let t = await cf.workers.deploy({
Expand All @@ -88,7 +89,7 @@ module.exports = {
script: contents,
bindings
})

return t;
},

Expand All @@ -99,7 +100,7 @@ module.exports = {
*/
async deployNamespaces(accountId, functionObject) {
let responses = [];

if (functionObject.resources && functionObject.resources.kv) {
for (const store of functionObject.resources.kv) {
let result = await cf.storage.createNamespace({
Expand All @@ -112,7 +113,7 @@ module.exports = {
responses.push(result);
}
}

return responses;
},

Expand All @@ -125,7 +126,7 @@ module.exports = {
const allRoutes = this.getRoutes(functionObject.events);
let routeResponses = [];
for (const pattern of allRoutes) {
const response = await cf.routes.deploy({path: pattern, scriptName: functionObject.name, zoneId});
const response = await cf.routes.deploy({ path: pattern, scriptName: functionObject.name, zoneId });
routeResponses.push(response)
}

Expand Down
10 changes: 7 additions & 3 deletions utils/index.js
Expand Up @@ -19,7 +19,7 @@
module.exports = {
getFunctionObject(paramName) {
let funParam = paramName || this.options.function;
if (typeof(funParam) === 'undefined') {
if (typeof funParam === "undefined") {
funParam = this.options.f;
}
if (funParam) {
Expand All @@ -37,10 +37,14 @@ module.exports = {
errors: workerErrors
} = apiResponse;

const { id, size } = workerResult || {};

if (workerDeploySuccess) {
serverlessConsole.log(`✅ Script Deployed `);
serverlessConsole.log(
`✅ Script Deployed. Name: ${id}, Size: ${(size / 1024).toFixed(2)}K`
);
} else {
serverlessConsole.log(`❌ Fatal Error, Script Not Deployed!`);
serverlessConsole.log(`❌ Fatal Error, Script Not Deployed!`);
workerErrors.forEach(err => {
let { code, message } = err;
serverlessConsole.log(
Expand Down

0 comments on commit 7635642

Please sign in to comment.