use embark's webpack config, or a dapp's webpack config if it exists

This commit is contained in:
Michael Bradley, Jr 2018-08-16 15:53:23 -05:00
parent c60d26e258
commit 2f2f007d5c

View File

@ -1,12 +1,8 @@
const async = require('async');
const webpack = require('webpack');
const utils = require('../utils/utils');
const fs = require('../core/fs');
const constants = require('../constants');
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
const fs = require('../core/fs');
const ProcessWrapper = require('../core/processes/processWrapper');
const path = require('path');
const glob = require('glob');
const webpack = require('webpack');
const writeFile = require('util').promisify(require('fs').writeFile);
let webpackProcess;
@ -14,195 +10,120 @@ class WebpackProcess extends ProcessWrapper {
constructor(options) {
super(options);
this.webpackConfigName = options.webpackConfigName;
if (!process.env.DAPP_PATH) {
process.env.DAPP_PATH = fs.dappPath();
}
if (!process.env.EMBARK_PATH) {
process.env.EMBARK_PATH = fs.embarkPath();
}
}
build(file, importsList, callback) {
async build(assets, importsList, callback) {
try {
await this.webpackRun(assets, importsList, callback);
} catch (e) {
console.error(e.message);
callback(e);
// ?? should return e or e.message
}
}
async webpackRun(assets, importsList, callback) {
const self = this;
let realCwd;
try {
await writeFile(
fs.dappPath('.embark/embark-aliases.json'),
JSON.stringify(importsList)
);
await writeFile(
fs.dappPath('.embark/embark-assets.json'),
JSON.stringify(assets)
);
} catch (e) {
console.error(e.message);
return callback(e);
// ?? should return e or e.message
}
async.waterfall([
function changeCwd(next) {
realCwd = utils.pwd();
process.chdir(fs.embarkPath(''));
next();
},
const dappConfigPath = fs.dappPath('webpack.config.js');
const defaultConfigPath = fs.embarkPath('webpack.config.js');
function runWebpack(next) {
self.webpackRun(file.filename, {}, true, importsList, true, realCwd, next);
},
function changeCwdBack(next) {
process.chdir(realCwd);
next();
let config, configPath;
try {
if (fs.existsSync(dappConfigPath)) {
delete require.cache[dappConfigPath];
configPath = dappConfigPath;
config = require(dappConfigPath);
} else {
configPath = defaultConfigPath;
config = require(defaultConfigPath);
}
], (err) => {
process.chdir(realCwd);
callback(err);
});
}
// valid config types: https://webpack.js.org/configuration/configuration-types/
// + function that returns a config object
// + function that returns a promise for a config object
// + array of named config objects
// + config object
if (typeof config === 'function') {
config = await config(self.webpackConfigName);
} else if (Array.isArray(config)) {
config = config.filter(cfg => cfg.name === self.webpackConfigName);
if (!config.length) {
const errMsg = `no webpack config has the name '${self.webpackConfigName}'`;
console.error(errMsg);
return callback(errMsg);
// ?? should the message be wrapped in new Error()
}
if (config.length > 1) {
console.warn(
`detected ${config.length} webpack configs having the name '${self.webpackConfigName}', using the first one`
);
}
config = config[0];
} else {
// proceed with the value obtained from require(dapp/default/Config)
}
} catch (e) {
console.error(`error while loading webpack config ${configPath}`);
console.error(e.message);
callback(e);
// ?? should return e or e.message
}
webpackRun(filename, options, includeModules, importsList, detectErrors, realCwd, callback) {
const self = this;
glob(fs.dappPath('.embark/versions/*/*'), (err, files) => {
let versions;
if (typeof config !== 'object' || config === null) {
const errMsg = 'bad webpack config, the resolved config was null or not an object';
console.error(errMsg);
return callback(errMsg);
// ?? should the message be wrapped in new Error()
}
webpack(config).run(async (err, stats) => {
if (err) {
console.error(err);
versions = [];
} else {
versions = files;
return callback(err);
}
let defaultOptions = {
mode: self.env === 'production' ? 'production' : 'none',
// devtool: self.env === 'development' ? 'source-map' : false,
// pipeline would need to copy .map files to dist/ target dir
// note: generating full source maps ('source-map') roughly doubles build time
entry: fs.dappPath(filename),
output: {
globalObject: 'typeof self !== \'undefined\' ? self : this',
libraryExport: 'default',
libraryTarget: 'umd',
path: fs.dappPath('.embark'),
filename: filename,
umdNamedDefine: true
},
// profile: true,
// stats: 'verbose',
// note: generating and writing to disk verbose stats increases build time
resolve: {
alias: importsList,
modules: [
fs.dappPath('node_modules'),
...versions,
fs.embarkPath('node_modules')
]
},
plugins: [
new HardSourceWebpackPlugin({
cacheDirectory: fs.dappPath('node_modules/.cache/hard-source'),
// ufglify (wp mode: production) will still save its cache in embark's node_modules/.cache/
environmentHash: {
root: fs.dappPath()
}
}),
new HardSourceWebpackPlugin.ExcludeModulePlugin(
[{test: /app[\\/]|contracts[\\/]/}]
)
]
};
let webpackOptions = utils.recursiveMerge(defaultOptions, options);
if (includeModules) {
webpackOptions.module = {
rules: [
{
test: /\.css$/,
use: [{loader: "style-loader"}, {loader: "css-loader"}]
},
{
test: /\.scss$/,
use: [{loader: "style-loader"}, {loader: "css-loader"}]
},
{
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000'
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: /(node_modules|bower_components|\.embark[\\/]versions)/,
options: {
presets: [
[
"@babel/preset-env", {
modules: false,
targets: {
browsers: ["last 1 version", "not dead", "> 0.2%"]
}
}
],
"@babel/preset-react"
].map(pkg => {
if (Array.isArray(pkg)) {
let _pkg = pkg[0];
pkg[0] = require.resolve(_pkg);
return pkg;
} else {
return require.resolve(pkg);
}
}),
plugins: [
"babel-plugin-webpack-aliases",
[
"@babel/plugin-transform-runtime", {
corejs: 2,
useESModules: true
}
]
].map(pkg => {
if (Array.isArray(pkg)) {
let _pkg = pkg[0];
pkg[0] = require.resolve(_pkg);
return pkg;
} else {
return require.resolve(pkg);
}
}),
compact: false
}
}
]
};
let dappBabelrc = path.join(realCwd, '.babelrc');
if (fs.existsSync(dappBabelrc)) {
webpackOptions.module.rules[3].options.extends = dappBabelrc;
try {
if (config.stats && config.stats !== 'none') {
self._log('info', 'writing file '+ ('.embark/stats.report').bold.dim);
await writeFile(
fs.dappPath('.embark/stats.report'),
stats.toString(config.stats)
);
self._log('info','writing file '+ ('.embark/stats.json').bold.dim);
await writeFile(
fs.dappPath('.embark/stats.json'),
JSON.stringify(stats.toJson(config.stats))
);
}
} catch (e) {
console.error(e.message);
return callback(err);
}
webpack(webpackOptions).run((err, stats) => {
async.waterfall([
function checkStatsError(next) {
if (err) {
console.error(err);
return next(err);
}
if (!detectErrors) {
return next();
}
if (stats.hasErrors()) {
return next(
stats.toJson(webpackOptions.stats).errors.join("\n")
);
}
next();
}//,
// function writeStatsReport(next) {
// if (detectErrors) {
// self._log('info', 'writing file '+ ('.embark/stats.report').bold.dim);
// }
// fs.writeFile(
// path.join(fs.dappPath('.embark'), 'stats.report'),
// stats.toString(webpackOptions.stats),
// next
// );
// },
// function writeStatsJSON(next) {
// if (detectErrors) {
// self._log('info','writing file '+ ('.embark/stats.json').bold.dim);
// }
// fs.writeFile(
// path.join(fs.dappPath('.embark'), 'stats.json'),
// JSON.stringify(stats.toJson(webpackOptions.stats)),
// next
// );
// }
// note: to visualize the stats info in a browser, do...
// `npx webpack-bundle-analyzer <dapp_dir>/.embark/stats.json`
], (err) => {
callback(err);
});
});
if (config.stats && stats.hasErrors()) {
const errors = stats.toJson(config.stats).errors.join('\n');
console.error(errors);
return callback(errors);
}
callback();
});
}
}
@ -214,7 +135,7 @@ process.on('message', (msg) => {
}
if (msg.action === constants.pipeline.build) {
return webpackProcess.build(msg.file, msg.importsList, (err) => {
return webpackProcess.build(msg.assets, msg.importsList, (err) => {
process.send({result: constants.pipeline.built, error: err});
});
}