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

[WIP] Webpack support #1117

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions dist-tools/service-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
var fs = require('fs');
var util = require('util');
var path = require('path');

var AWS = require('../');
var apis = require('../lib/api_loader');
var metadata = require('../apis/metadata');

var defaultServices = 'acm,apigateway,applicationautoscaling,autoscaling,cloudformation,cloudfront,cloudhsm,cloudtrail,cloudwatch,cloudwatchlogs,cloudwatchevents,codecommit,codedeploy,codepipeline,cognitoidentity,cognitoidentityserviceprovider,cognitosync,configservice,devicefarm,directconnect,dynamodb,dynamodbstreams,ec2,ecr,ecs,elasticache,elasticbeanstalk,elastictranscoder,elb,emr,firehose,gamelift,inspector,iotdata,kinesis,kms,lambda,marketplacecommerceanalytics,mobileanalytics,machinelearning,opsworks,rds,redshift,route53,route53domains,s3,ses,sns,sqs,ssm,storagegateway,sts,waf';
var sanitizeRegex = /[^a-zA-Z0-9,-]/;

var serviceClasses = {};
Object.keys(AWS).forEach(function(name) {
if (AWS[name].serviceIdentifier) {
serviceClasses[AWS[name].serviceIdentifier] = AWS[name];
}
});

function getServiceHeader(service) {
if (service === 'all') {
return Object.keys(serviceClasses).map(function(name) {
return getServiceHeader(name);
}).join('\n');
}

if (!serviceClasses[service]) return null;
var versions = serviceClasses[service].apiVersions.map(function(version) {
return version.indexOf('*') >= 0 ? null : version;
}).filter(function(c) { return c !== null; });

var file = util.format(
'AWS.apiLoader.services[\'%s\'] = {};\n' +
'AWS.%s = AWS.Service.defineService(\'%s\', %s);\n',
service, apis.serviceName(service), service, util.inspect(versions));
var svcPath = path.join(__dirname, '..', 'lib', 'services', service + '.js');
if (fs.existsSync(svcPath)) {
file += 'require(\'./services/' + service + '\');\n';
}

return file;
}

function getService(service, version) {
if (service === 'all') {
return Object.keys(serviceClasses).map(function(name) {
var out = serviceClasses[name].apiVersions.map(function(svcVersion) {
if (svcVersion.indexOf('*') >= 0) return null;
return getService(name, svcVersion);
}).filter(function(c) { return c !== null; }).join('\n');

return out;
}).join('\n');
}

var svc, api;
if (!serviceClasses[service]) {
return null;
}

try {
var ClassName = serviceClasses[service];
svc = new ClassName({apiVersion: version, endpoint: 'localhost'});
api = apis.load(service, svc.api.apiVersion);
} catch (e) {
return null;
}

var serviceFileName = metadata[service].prefix || service;
var lines = [];
var line = util.format(
'AWS.apiLoader.services[\'%s\'][\'%s\'] = %s;\n',
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious why we can't just rely on browserify pulling in deps?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm working on rewriting this script to better support custom builds, so a lot will probably change here.

I'm not quite sure what you mean. Are you asking why we can't rely on browserify to pull in the service clients, or all the node.js module deps as well? Part of my motivation was so that webpack users wouldn't need browserify as well to customize their build.

service, svc.api.apiVersion, 'require(\'../apis/' + serviceFileName + '-' + svc.api.apiVersion + '.min\')');
lines.push(line);
if (Object.prototype.hasOwnProperty.call(api, 'paginators')) {
line = util.format(
'AWS.apiLoader.services[\'%s\'][\'%s\'].paginators = %s;\n',
service, svc.api.apiVersion, 'require(\'../apis/' + serviceFileName + '-' + svc.api.apiVersion + '.paginators\').pagination');
lines.push(line);
}
if (Object.prototype.hasOwnProperty.call(api, 'waiters')) {
line = util.format(
'AWS.apiLoader.services[\'%s\'][\'%s\'].waiters = %s;\n',
service, svc.api.apiVersion, 'require(\'../apis/' + serviceFileName + '-' + svc.api.apiVersion + '.waiters2\').waiters');
lines.push(line);
}

return lines.join('');
}

function ServiceCollector(services) {
var builtServices = {};

function buildService(name, usingDefaultServices) {
var match = name.match(/^(.+?)(?:-(.+?))?$/);
var service = match[1], version = match[2] || 'latest';
var contents = [];
var lines, err;

if (!builtServices[service]) {
builtServices[service] = {};

lines = getServiceHeader(service);
if (lines === null) {
if (!usingDefaultServices) {
err = new Error('Invalid module: ' + service);
err.name = 'InvalidModuleError';
throw err;
}
} else {
contents.push(lines);
}
}

if (!builtServices[service][version]) {
builtServices[service][version] = true;

lines = getService(service, version);
if (lines === null) {
if (!usingDefaultServices) {
err = new Error('Invalid module: ' + service + '-' + version);
err.name = 'InvalidModuleError';
throw err;
}
} else {
contents.push(lines);
}
}

return contents.join('');
}

var serviceCode = '';
var usingDefaultServicesToggle = false;
if (!services) {
usingDefaultServicesToggle = true;
services = defaultServices;
}
if (services.match(sanitizeRegex)) {
throw new Error('Incorrectly formatted service names');
}

var invalidModules = [];
var stsIncluded = false;
services.split(',').sort().forEach(function(name) {
if (name.match(/^sts\b/) || name === 'all') stsIncluded = true;
try {
serviceCode += buildService(name, usingDefaultServicesToggle) + '\n';
} catch (e) {
if (e.name === 'InvalidModuleError') invalidModules.push(name);
else throw e;
}
});

if (!stsIncluded) {
serviceCode += buildService('sts') + '\n';
}

if (invalidModules.length > 0) {
throw new Error('Missing modules: ' + invalidModules.join(', '));
}

return serviceCode;
}

module.exports = ServiceCollector;

//var source = ServiceCollector(defaultServices);
var source = ServiceCollector(process.env.AWS_SERVICES);
fs.writeFile(path.join(__dirname, '..', 'lib', 'browser_services.js'), source);
10 changes: 10 additions & 0 deletions lib/aws.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
var util = require('./util');

// node.js specific modules
util.crypto.lib = require('crypto');

// node.js stubs
util.nodeRequire = function nodeRequire(mod) {
if (util.isNode()) return require(mod);
};

var AWS = require('./core');
module.exports = AWS;

Expand Down
17 changes: 17 additions & 0 deletions lib/browser.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
var util = require('./util');
Copy link
Contributor

Choose a reason for hiding this comment

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

@chrisradek Do you think it might be worthwhile adding a buffer polyfill as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Absolutely. Webpack actually does polyfill buffer, but I like taking control of which buffer polyfill to use back to us (makes updating when bugs are fixed easier), and to make supporting other tools easier.


// browser specific modules
util.crypto.lib = require('crypto-browserify');

// browser stubs
util.nodeRequire = function nodeRequire(mod) {};

var AWS = require('./core');

// Load browser API loader
Expand All @@ -16,6 +24,15 @@ AWS.XML.Parser = require('./xml/browser_parser');
// Load the XHR HttpClient
require('./http/xhr');

if (typeof process === 'undefined') {
process = {
browser: true
};

Choose a reason for hiding this comment

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

Should be this.process = ...?

}

if (typeof window !== 'undefined') window.AWS = AWS;
if (typeof module !== 'undefined') module.exports = AWS;
if (typeof self !== 'undefined') self.AWS = AWS;

// Load services
require('./browser_services');
Loading