deepify
Version:
DEEP Development Tools
265 lines (230 loc) • 9.73 kB
JavaScript
const CUSTOM_WEBPACK_CONFIG = 'deep.bundle.json';
const ENTRY_POINT = 'bootstrap.js';
const R_DEEP_DYN_MODULES = '__deep_dyn_modules__';
const LAMBDA_ROOT = '/var/task';
const PLUGINS_PLACEHOLDER = '~~~DEEP_WEBPACK_PLUGINS~~~';
const EXTERNALS = [
/aws-sdk/i, // @preloaded (by AWS Lambda container)
];
const NULL_MODULES = [
'mv', // @junk (bunyan shim)
'safe-json-stringify', // @junk (bunyan shim)
'dtrace-provider', // @junk (bunyan shim)
'source-map-support', // @junk (bunyan shim)
'vertx', // @junk (es6-promise uses native implementation)
'ioredis', // @junk (deep-cache not implemented)
'store', // @browser
'formidable', // @browser
'relative-fs', // @local
'dynalite', // @local
'local-dynamo', // @local
'leveldb', // @junk (leveldb)
];
const glob = require('glob');
const path = require('path');
const fse = require('fs-extra');
const fs = require('fs');
const webpackMerge = require('webpack-merge');
const Bin = require('../../../../lib.compiled/NodeJS/Bin').Bin;
const Core = require('deep-core');
const pify = require('pify');
const helpers = require('./compile-prod');
// @todo Resolve webpack dynamically (maybe link it?)
const GLOBAL_NODE_LIBS = path.resolve(Bin.resolve('webpack', true), '../../lib/node_modules/');
const WEBPACK_LIB = path.join(GLOBAL_NODE_LIBS, 'webpack/lib/webpack.js');
const WEBPACK_CONST_DEP_LIB = path.join(GLOBAL_NODE_LIBS, 'webpack/lib/dependencies/ConstDependency.js');
const UGLIFYJS_PLUGIN = path.join(GLOBAL_NODE_LIBS, 'uglifyjs-webpack-plugin/dist/index.js');
console.debug('GLOBAL_NODE_LIBS', GLOBAL_NODE_LIBS);
console.debug('WEBPACK_LIB', WEBPACK_LIB);
console.debug('WEBPACK_CONST_DEP_LIB', WEBPACK_CONST_DEP_LIB);
console.debug('UGLIFYJS_PLUGIN', UGLIFYJS_PLUGIN);
function plainify (config, debug, optimize) {
config.plugins = [ PLUGINS_PLACEHOLDER ];
const regexpExternals = config.externals
.filter(external => external instanceof RegExp)
.map(external => {
return `webpackConfig.externals.push(${external})`;
});
config.externals = config.externals
.filter(external => typeof external === 'string');
const plainConfig = `/* Generated by Deepify on ${Date()} */
const webpack = require('${WEBPACK_LIB}');
const UglifyJSPlugin = require('${UGLIFYJS_PLUGIN}');
const ConstDependency = require('${WEBPACK_CONST_DEP_LIB}');
const DeepResolver = require('${path.join(__dirname, 'webpack.resolver.js')}');
const resolver = new DeepResolver('${R_DEEP_DYN_MODULES}', webpack, ConstDependency);
const webpackConfig = ${JSON.stringify(config, null, ' ')};
${regexpExternals.join(';\n')};
module.exports = resolver.extend(webpackConfig);
`;
let plugins = `
new webpack.ContextReplacementPlugin(/moment[\\\/\\\\]locale$/, /en/),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.LoaderOptionsPlugin({
minimize: ${debug ? 'false' : 'true'},
debug: ${debug ? 'true' : 'false'},
}),
resolver,
`;
// @todo enable mangle when stable
if (!debug && optimize) {
plugins += `new UglifyJSPlugin({
comments: false,
mangle: false,
}),`;
}
return plainConfig.replace(`"${PLUGINS_PLACEHOLDER}"`, plugins);
}
function processDeepConfig(lambdaPath, outputPath, deepConfig) {
if (deepConfig.hasOwnProperty('include_files')) {
let includeFiles = deepConfig.include_files || [];
if (!Array.isArray(includeFiles)) {
includeFiles = [ includeFiles.toString() ];
}
return Promise.all(includeFiles.map(includePattern => {
const globOptions = {
cwd: lambdaPath,
nosort: true,
realpath: false,
absolute: true,
nodir: true,
};
console.debug(`Include additional assets to ${lambdaPath} build using pattern ${includePattern}`);
return pify(glob)(includePattern, globOptions)
.then(files => {
if ((files || []).length <= 0) {
return Promise.resolve();
}
return Promise.all(files.map(file => {
const relativePath = file.substr(lambdaPath.length + 1);
const destination = path.join(outputPath, relativePath);
console.debug(`Copy additional asset ${file} to ${destination}`);
return pify(fse.copy)(file, destination);
}));
});
}));
}
return Promise.resolve();
}
function preprocessCustomConfig(lambdaPath, outputPath, customConfig) {
customConfig.deep = customConfig.deep || {};
return processDeepConfig(lambdaPath, outputPath, customConfig.deep)
.then(() => {
delete customConfig.deep;
return Promise.resolve(customConfig);
});
}
module.exports = function (lambdaPath, outputPath, linkedLibs, debug, optimize) {
const schemasPath = path.join(lambdaPath, Core.AWS.Lambda.Runtime.VALIDATION_SCHEMAS_DIR);
const customWebpackConfigPath = path.join(lambdaPath, CUSTOM_WEBPACK_CONFIG);
const tmpBootstrapName = `.deep-tmp-${Date.now()}-${ENTRY_POINT}`;
const tmpBootstrapJs = path.join(lambdaPath, tmpBootstrapName);
const nullModulePath = path.join(__dirname, 'webpack.null-module.js');
const defaultConfig = {
entry: tmpBootstrapName,
context: lambdaPath,
output: {
path: outputPath,
filename: ENTRY_POINT,
libraryTarget: 'commonjs2', // @see https://github.com/webpack/webpack/issues/1114
},
resolve: {
unsafeCache: /mode_modules\//,
symlinks: true,
modules: [ lambdaPath, 'node_modules' ],
extensions: [ '.js', '.json' ],
alias: {
'deep-framework$': 'deep-framework/lib.es6/bootstrap.js',
'deep-core$': 'deep-core/lib.es6/bootstrap.js',
'deep-kernel$': 'deep-kernel/lib.es6/bootstrap.js',
'deep-asset$': 'deep-asset/lib.es6/bootstrap.js',
'deep-cache$': 'deep-cache/lib.es6/bootstrap.js',
'deep-security$': 'deep-security/lib.es6/bootstrap.js',
'deep-resource$': 'deep-resource/lib.es6/bootstrap.js',
'deep-log$': 'deep-log/lib.es6/bootstrap.js',
'deep-event$': 'deep-event/lib.es6/bootstrap.js',
'deep-validation$': 'deep-validation/lib.es6/bootstrap.js',
'deep-search$': 'deep-search/lib.es6/bootstrap.js',
'deep-db$': 'deep-db/lib.es6/bootstrap.js',
'deep-fs$': 'deep-fs/lib.es6/bootstrap.js',
},
},
watch: false,
target: 'node',
externals: EXTERNALS,
devtool: false,
stats: 'errors-only',
node: { // avoid polyfill node libraries and internals
console: false, process: false, global: false, __filename: true,
__dirname: true, buffer: false, setImmediate: false, assert: false,
constants: false, crypto: false, domain: false, events: false,
http: false, https: false, os: false, path: false, punycode: false,
querystring: false, stream: false, string_decoder: false, sys: false,
timers: false, tty: false, url: false, util: false, vm: false, zlib: false,
},
cache: true,
};
const deepDeps = {};
linkedLibs.forEach(linkedLib => {
const modulePath = path.resolve(lambdaPath, 'node_modules', linkedLib, 'node_modules');
defaultConfig.resolve.modules.push(modulePath);
});
NULL_MODULES.forEach(nullModule => {
defaultConfig.resolve.alias[nullModule] = nullModulePath;
});
return pify(fse.copy)(path.join(lambdaPath, ENTRY_POINT), tmpBootstrapJs)
.then(() => {
return helpers.fileExists(schemasPath)
.then(hasSchemas => {
if (!hasSchemas) {
return Promise.resolve();
}
return pify(fs.readdir)(schemasPath)
.then(files => {
files
.filter(file => /\.js(on)?$/i)
.forEach(file => {
const schemasDir = Core.AWS.Lambda.Runtime.VALIDATION_SCHEMAS_DIR;
const schemaInclude = `${LAMBDA_ROOT}/${schemasDir}/${file}`;
deepDeps[schemaInclude] = `./${schemasDir}/${file}`;
});
return Promise.resolve();
});
});
})
.then(() => {
console.debug(`Generate "global.${R_DEEP_DYN_MODULES}" in "${lambdaPath}" (${Object.keys(deepDeps).join(', ')})`);
const deepDepsInject = [
`global.${R_DEEP_DYN_MODULES} = global.${R_DEEP_DYN_MODULES} || {};`,
].concat(Object.keys(deepDeps).map(depKey => {
return `global.${R_DEEP_DYN_MODULES}['${depKey}'] = require('${deepDeps[depKey]}');`;
})).join('\n') + '\n';
return pify(fs.readFile)(tmpBootstrapJs)
.then(bootstrapContent => {
return pify(fs.writeFile)(tmpBootstrapJs, deepDepsInject + bootstrapContent);
});
})
.then(() => helpers.fileExists(customWebpackConfigPath))
.then(hasCustomWebpackConfig => {
if (!hasCustomWebpackConfig) {
const rawConfig = plainify(defaultConfig, debug, optimize);
return Promise.resolve({ rawConfig, tmpBootstrapJs });
}
return pify(fse.readJson)(customWebpackConfigPath)
.then(customWebpackConfig => {
return preprocessCustomConfig(
lambdaPath,
outputPath,
customWebpackConfig || {}
);
})
.then(customWebpackConfig => {
const rawConfig = plainify(webpackMerge.smart(
defaultConfig,
customWebpackConfig
), debug, optimize);
return Promise.resolve({ rawConfig, tmpBootstrapJs });
});
});
};
;