twreporter-react
Version:
React-Redux site for The Reporter Foundation in Taiwan
472 lines (363 loc) • 15.8 kB
JavaScript
;
exports.__esModule = true;
exports['default'] = write_assets;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _fsExtra = require('fs-extra');
var _fsExtra2 = _interopRequireDefault(_fsExtra);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _requireHacker = require('require-hacker');
var _requireHacker2 = _interopRequireDefault(_requireHacker);
var _toolsSerializeJavascript = require('../tools/serialize-javascript');
var _toolsSerializeJavascript2 = _interopRequireDefault(_toolsSerializeJavascript);
var _helpers = require('../helpers');
var _common = require('../common');
// writes webpack-assets.json file, which contains assets' file paths
function write_assets(json, options, log) {
// take the passed in options
options = _helpers.clone(options);
log.debug('running write assets webpack plugin v' + require('../../package.json').version + ' with options', options);
// make webpack stats accessible for asset functions (parser, path, filter)
options.webpack_stats = json;
var development = options.development;
if (development) {
log.debug(' (development mode is on)');
}
// write webpack stats json for debugging purpose
if (options.debug) {
// write webpack stats file
log.debug('writing webpack stats to ' + options.webpack_stats_path);
// write the file
// (format the JSON for better readability)
_fsExtra2['default'].outputFileSync(options.webpack_stats_path, JSON.stringify(json, null, 2));
}
// the output object with assets
var output = options.output;
// populate the output object with assets
populate_assets(output, json, options, log);
// write webpack assets info file
log.debug('writing webpack assets info to ' + options.webpack_assets_path);
// format the JSON for better readability if in debug mode
var assets_info = development ? JSON.stringify(output, null, 2) : JSON.stringify(output);
// write the file
_fsExtra2['default'].outputFileSync(options.webpack_assets_path, assets_info);
}
// populates the output object with assets
function populate_assets(output, json, options, log) {
// for each chunk name ("main", "common", ...)
Object.keys(json.assetsByChunkName).forEach(function (name) {
log.debug('getting javascript and styles for chunk "' + name + '"');
// get javascript chunk real file path
var javascript = get_assets(name, 'js')[0];
// the second asset is usually a source map
if (javascript) {
log.debug(' (got javascript)');
output.javascript[name] = javascript;
}
// get style chunk real file path
var style = get_assets(name, 'css')[0];
// the second asset is usually a source map
if (style) {
log.debug(' (got style)');
output.styles[name] = style;
}
});
// gets asset paths by name and extension of their chunk
function get_assets(name) {
var extension = arguments.length <= 1 || arguments[1] === undefined ? 'js' : arguments[1];
var chunk = json.assetsByChunkName[name];
// a chunk could be a string or an array, so make sure it is an array
if (!Array.isArray(chunk)) {
chunk = [chunk];
}
return chunk
// filter by extension
.filter(function (name) {
return _path2['default'].extname(name) === '.' + extension;
})
// adjust the real path (can be http, filesystem)
.map(function (name) {
return options.assets_base_url + name;
});
}
// one can supply a custom filter
var default_filter = function default_filter(module, regular_expression) {
return regular_expression.test(module.name);
};
// one can supply a custom namer
var default_asset_path = function default_asset_path(module) {
return module.name;
};
// one can supply a custom parser
var default_parser = function default_parser(module) {
return module.source;
};
// 1st pass
var parsed_assets = {};
// global paths to parsed asset paths
var global_paths_to_parsed_asset_paths = {};
// define __webpack_public_path__ webpack variable
// (resolves "ReferenceError: __webpack_public_path__ is not defined")
var define_webpack_public_path = 'var __webpack_public_path__ = ' + JSON.stringify(options.assets_base_url) + ';\n';
var _loop = function () {
if (_isArray) {
if (_i >= _iterator.length) return 'break';
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) return 'break';
_ref = _i.value;
}
var asset_type = _ref;
// asset type settings
var asset_type_settings = options.assets[asset_type];
// one can supply his own filter
var filter = asset_type_settings.filter || default_filter; //.bind(this)
// one can supply his own path parser
var extract_asset_path = asset_type_settings.path || default_asset_path; //.bind(this)
// one can supply his own parser
var parser = asset_type_settings.parser || default_parser; //.bind(this)
// guard agains typos, etc
// for filter
if (!asset_type_settings.filter) {
log.debug('No filter specified for "' + asset_type + '" assets. Using a default one.');
}
// for path parser
if (!asset_type_settings.path) {
log.debug('No path parser specified for "' + asset_type + '" assets. Using a default one.');
}
// for parser
if (!asset_type_settings.parser) {
log.debug('No parser specified for "' + asset_type + '" assets. Using a default one.');
}
log.debug('parsing assets of type "' + asset_type + '"');
// timer start
var began_at = new Date().getTime();
// get real paths for all the files from this asset type
json.modules
// take just modules of this asset type
.filter(function (module) {
// check that this asset is of the asset type
if (!filter(module, options.regular_expressions[asset_type], options, log)) {
return false;
}
// guard against an empty source.
if (!module.source) {
log.error('Module "' + module.name + '" has no source. Maybe Webpack compilation of this module failed. Skipping this asset.');
return false;
}
// include this asset
return true;
}).reduce(function (set, module) {
// determine asset real path
var asset_path = extract_asset_path(module, options, log);
// asset module source, or asset content (or whatever else)
var parsed_asset = parser(module, options, log);
log.trace('Adding asset "' + asset_path + '", module id ' + module.id + ' (in webpack-stats.json)');
// check for naming collisions (just in case)
if (_helpers.exists(set[asset_path])) {
log.error('-----------------------------------------------------------------');
log.error('Asset with path "' + asset_path + '" was overwritten because of path collision.');
log.error('Use the "filter" function of this asset type to narrow the results.');
log.error('Previous asset with this path:');
log.error(set[asset_path]);
log.error('New asset with this path:');
log.error(parsed_asset);
log.error('-----------------------------------------------------------------');
}
// add this asset to the list
//
// also resolve "ReferenceError: __webpack_public_path__ is not defined".
// because it may be a url-loaded resource (e.g. a font inside a style).
set[asset_path] = define_webpack_public_path + _requireHacker2['default'].to_javascript_module_source(parsed_asset);
// add path mapping
global_paths_to_parsed_asset_paths[_path2['default'].resolve(options.project_path, asset_path)] = asset_path;
// continue
return set;
}, parsed_assets);
// timer stop
log.debug(' time taken: ' + (new Date().getTime() - began_at) + ' ms');
};
// for each user specified asset type
for (var _iterator = Object.keys(options.assets), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
var _ret = _loop();
if (_ret === 'break') break;
}
// register a special require() hook for requiring() raw webpack modules
var require_hook = _requireHacker2['default'].global_hook('webpack-module', function (required_path, module) {
log.debug('require()ing "' + required_path + '"');
// if Webpack aliases are supplied
if (options.alias) {
// possibly alias the path
var aliased_global_path = _common.alias_hook(required_path, module, options.project_path, options.alias, log);
// if an alias is found
if (aliased_global_path) {
return _requireHacker2['default'].to_javascript_module_source(require(aliased_global_path));
}
}
// find an asset with this path
//
// the require()d path will be global path in case of the for..of require() loop
// for the assets (the code a couple of screens below).
//
// (it can be anything in other cases (e.g. nested require() calls from the assets))
//
if (_helpers.exists(global_paths_to_parsed_asset_paths[required_path])) {
log.debug(' found in parsed assets');
return parsed_assets[global_paths_to_parsed_asset_paths[required_path]];
}
log.debug(' not found in parsed assets, searching in webpack stats');
// find a webpack module which has a reason with this path
var candidates = [];
for (var _iterator2 = json.modules, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref2;
if (_isArray2) {
if (_i2 >= _iterator2.length) break;
_ref2 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) break;
_ref2 = _i2.value;
}
var _module2 = _ref2;
for (var _iterator3 = _module2.reasons, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
var _ref3;
if (_isArray3) {
if (_i3 >= _iterator3.length) break;
_ref3 = _iterator3[_i3++];
} else {
_i3 = _iterator3.next();
if (_i3.done) break;
_ref3 = _i3.value;
}
var reason = _ref3;
if (reason.userRequest === required_path) {
candidates.push(_module2);
break;
}
}
}
// guard against ambiguity
if (candidates.length === 1) {
log.debug(' found in webpack stats, module id ' + candidates[0].id);
// also resolve "ReferenceError: __webpack_public_path__ is not defined".
// because it may be a url-loaded resource (e.g. a font inside a style).
return define_webpack_public_path + candidates[0].source;
}
// if there are more than one candidate for this require()d path,
// then try to guess which one is the one require()d
if (candidates.length > 1) {
log.debug(' More than a single candidate module was found in webpack stats for require()d path "' + required_path + '"');
for (var _iterator4 = candidates, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
var _ref4;
if (_isArray4) {
if (_i4 >= _iterator4.length) break;
_ref4 = _iterator4[_i4++];
} else {
_i4 = _iterator4.next();
if (_i4.done) break;
_ref4 = _i4.value;
}
var candidate = _ref4;
log.debug(' ', candidate);
}
// (loaders matter so the program can't simply throw them away from the required path)
//
// // tries to normalize a cryptic Webpack loader path
// // into a regular relative file path
// // https://webpack.github.io/docs/loaders.html
// let filesystem_required_path = last(required_path
// .replace(/^!!/, '')
// .replace(/^!/, '')
// .replace(/^-!/, '')
// .split('!'))
var fail = function fail() {
throw new Error('More than a single candidate module was found in webpack stats for require()d path "' + required_path + '". Enable "debug: true" flag in webpack-isomorphic-tools configuration for more info.');
};
// https://webpack.github.io/docs/loaders.html
var is_webpack_loader_path = required_path.indexOf('!') >= 0;
// if it's a Webpack loader-powered path, the code gives up
if (is_webpack_loader_path) {
fail();
}
// from here on it's either a filesystem path or an npm module path
var is_a_global_path = function is_a_global_path(path) {
return _helpers.starts_with(path, '/') || path.indexOf(':') > 0;
};
var is_a_relative_path = function is_a_relative_path(path) {
return _helpers.starts_with(path, './') || _helpers.starts_with(path, '../');
};
var is_relative_path = is_a_relative_path(required_path);
var is_global_path = is_a_global_path(required_path);
var is_npm_module_path = !is_relative_path && !is_global_path;
// if it's a global path it can be resolved right away
if (is_global_path) {
return _requireHacker2['default'].to_javascript_module_source(require(required_path));
}
// from here on it's either a relative filesystem path or an npm module path,
// so it can be resolved against the require()ing file path (if it can be recovered).
// `module.filename` here can be anything, not just a filesystem absolute path,
// since some advanced require() hook trickery is involved.
// therefore it will be parsed.
//
var requiring_file_path = module.filename.replace(/\.webpack-module$/, '');
// if it's a webpack loader-powered path, then extract the filesystem path from it
if (requiring_file_path.indexOf('!') >= 0) {
requiring_file_path = requiring_file_path.substring(requiring_file_path.lastIndexOf('!') + 1);
}
// make relative path global
if (is_a_relative_path(requiring_file_path)) {
requiring_file_path = _path2['default'].resolve(options.project_path, requiring_file_path);
}
// if `requiring_file_path` is a filesystem path (not an npm module path),
// then the require()d path can possibly be resolved
if (is_a_global_path(requiring_file_path)) {
log.debug(' The module is being require()d from "' + requiring_file_path + '", so resolving the path against this file');
// if it's a relative path, can try to resolve it
if (is_relative_path) {
return _requireHacker2['default'].to_javascript_module_source(require(_path2['default'].resolve(requiring_file_path, '..', required_path)));
}
// if it's an npm module path (e.g. 'babel-runtime/core-js/object/assign'),
// can try to require() it from the requiring asset path
if (is_npm_module_path && is_a_global_path(module.filename)) {
return _requireHacker2['default'].to_javascript_module_source(require(_requireHacker2['default'].resolve(required_path, module)));
}
}
// if it's still here then it means it's either a
fail();
}
});
log.debug('compiling assets');
// timer start
var began_at = new Date().getTime();
// evaluate parsed assets source code
for (var _iterator5 = Object.keys(parsed_assets), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
var _ref5;
if (_isArray5) {
if (_i5 >= _iterator5.length) break;
_ref5 = _iterator5[_i5++];
} else {
_i5 = _iterator5.next();
if (_i5.done) break;
_ref5 = _i5.value;
}
var asset_path = _ref5;
// set asset value
log.debug('compiling asset "' + asset_path + '"');
output.assets[asset_path] = require(_path2['default'].resolve(options.project_path, asset_path))
// inside that require() call above
// all the assets are resolved relative to this `module`,
// which is irrelevant because they are all absolute filesystem paths.
//
// if in some of those assets a nested require() call is present
// then it will be resolved relative to that asset folder.
;
}
// unmount the previously installed require() hook
require_hook.unmount();
// timer stop
log.debug(' time taken: ' + (new Date().getTime() - began_at) + ' ms');
}
module.exports = exports['default'];
//# sourceMappingURL=write assets.js.map