UNPKG

universal-webpack

Version:
336 lines (264 loc) 14.3 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } import path from 'path'; import util from 'util'; import webpack from 'webpack'; import validate_npm_package_path from 'validate-npm-package-name'; import { clone, starts_with, ends_with } from './helpers.js'; import { find_loader, get_style_rules, normalize_configuration_rule_loaders } from './loaders.js'; // Tunes the client-side Webpack configuration for server-side build export default function server_configuration(webpack_configuration, settings) { // if (!webpack_configuration.context) // { // throw new Error(`You must set "context" parameter in your Webpack configuration`) // } var configuration = clone(webpack_configuration); // By default, Webpack sets `context` to `process.cwd()` configuration.context = configuration.context || process.cwd(); // (without extension) var output_file_name = path.basename(settings.server.output, path.extname(settings.server.output)); configuration.entry = _defineProperty({}, output_file_name, settings.server.input); // https://webpack.github.io/docs/configuration.html#target configuration.target = 'node'; // Tell Webpack to leave `__dirname` and `__filename` unchanged // https://github.com/webpack/webpack/issues/1599#issuecomment-186841345 configuration.node = configuration.node || {}; configuration.node.__dirname = false; configuration.node.__filename = false; // https://webpack.js.org/configuration/output/#outputlibrarytarget configuration.output.libraryTarget = 'commonjs2'; // No need for browser cache management, so disable hashes in filenames configuration.output.filename = '[name].js'; configuration.output.chunkFilename = '[name].js'; // Include comments with information about the modules. // require(/* ./test */23). // What for is it here? I don't know. It's a copy & paste from the Webpack author's code. configuration.output.pathinfo = true; // Output server bundle into its own directory configuration.output.path = path.resolve(configuration.context, path.dirname(settings.server.output)); // Output "*.map" file for human-readable stack traces configuration.devtool = 'source-map'; // https://webpack.github.io/docs/configuration.html#externals // // `externals` allows you to specify dependencies for your library // that are not resolved by webpack, but become dependencies of the output. // This means they are imported from the environment during runtime. // // So that Webpack doesn't bundle "node_modules" into server.js. configuration.externals = configuration.externals || []; if (!Array.isArray(configuration.externals)) { configuration.externals = [configuration.externals]; } configuration.externals.push(function (context, request, callback) { if (is_external(request, configuration, settings)) { // Resolve dependency as external return callback(null, request); } // Resolve dependency as non-external return callback(); }); // Normalize `modules.rules` loaders. normalize_configuration_rule_loaders(configuration); // Replace `style-loader` and `css-loader` with `css-loader?exportOnlyLocals=true` // since it's no web browser and no files will be emitted. replace_style_loader(configuration); // Add `emit: false` flag to `file-loader` and `url-loader`, // since there's no need out emit files on the server side // (can just use the assets emitted on client build // since the filenames are the same) dont_emit_file_loader(configuration); configuration.plugins = configuration.plugins || []; // Remove HotModuleReplacementPlugin and CommonsChunkPlugin configuration.plugins = configuration.plugins.filter(function (plugin) { try { if (plugin.constructor === webpack.optimize.CommonsChunkPlugin) { return false; } } catch (error) {// Webpack 4 throws `RemovedPluginError`. } return plugin.constructor !== webpack.HotModuleReplacementPlugin; }); // Add a couple of utility plugins configuration.plugins = configuration.plugins.concat( // Resorted from using it here because // if the `build/server` folder is not there // when Nodemon starts then it simply won't detect // updates of the server-side bundle // and therefore won't restart on code changes. // // `build/server` folder needs to be present // by the time Nodemon starts, // and that's accomplished with a separate npm script. // // Cleans the output folder // new clean_plugin([path.dirname(settings.server.output)], // { // root: configuration.context // }), // Put the resulting Webpack compiled code into a sigle javascript file // (doesn't disable CommonsChunkPlugin) new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 })); // Done return configuration; } // Checks if a require()d dependency is external. // Could also use https://www.npmjs.com/package/webpack-node-externals. // Still the self-made alias-aware solution works ok. export function is_external(request, webpack_configuration, settings) { // If someone finds a way to mark all assets (jpg, png, css, scss) // as not external then create a Pull Request on github. // Until then, all assets from `node_modules` have to be specified // inside `exclude_from_externals` configuration parameter. // Mark all files inside packages (e.g. `node_modules`) as external. var package_name = extract_package_name(request); // Skip webpack loader specific require()d paths // https://webpack.github.io/docs/loaders.html if (starts_with(package_name, '!') || starts_with(package_name, '-!')) { // The dependency is not external return false; } // If it's not a module require call, // then resolve it as non-external. // // https://github.com/npm/validate-npm-package-name // if (!validate_npm_package_path(package_name).validForNewPackages) { // The dependency is not external return false; } // If any aliases are specified, then resolve those aliases as non-external if (webpack_configuration.resolve && webpack_configuration.resolve.alias) { for (var _i = 0, _Object$keys = Object.keys(webpack_configuration.resolve.alias); _i < _Object$keys.length; _i++) { var alias = _Object$keys[_i]; // if (request === key || starts_with(request, key + '/')) if (package_name === alias) { // The module is not external return false; } } } // Allows camelCasing var exclude_from_externals_extensions = settings.load_external_module_file_extensions || settings.loadExternalModuleFileExtensions || ['css', 'png', 'jpg', 'svg', 'xml']; // Assets are being exluded from externals // because they need loaders in order to be `require()`d. var extname = path.extname(request); if (extname) { var extension = extname.slice(1); if (extension) { if (exclude_from_externals_extensions.indexOf(extension) >= 0) { // "The module is not external" // (which means "load this module with a special loader") return false; } } } // Allows camelCasing var exclude_from_externals = settings.exclude_from_externals || settings.excludeFromExternals; // Skip modules explicitly ignored by the user if (exclude_from_externals) { var _iterator = _createForOfIteratorHelper(exclude_from_externals), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var exclusion_pattern = _step.value; if (typeof exclusion_pattern === 'string') { if (request === exclusion_pattern || starts_with(request, exclusion_pattern + '/')) { // The module is not external return false; } } else if (exclusion_pattern instanceof RegExp) { if (exclusion_pattern.test(request)) { // The module is not external return false; } } else { throw new Error("Invalid exclusion pattern: ".concat(exclusion_pattern, ". Only strings and regular expressions are allowed.")); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } // The module is external return true; } // Adds `emitFile: false` flag to `file-loader` and `url-loader`, // since there's no need out emit files on the server side // (can just use the assets emitted on client build // since the filenames are the same) export function dont_emit_file_loader(configuration) { var _iterator2 = _createForOfIteratorHelper(configuration.module.rules), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var rule = _step2.value; if (rule.oneOf) { var _iterator3 = _createForOfIteratorHelper(rule.oneOf), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var subrule = _step3.value; _dont_emit_file_loader(subrule); } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } continue; } _dont_emit_file_loader(rule); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } // Adds `emitFile: false` flag to `file-loader` and `url-loader`, // since there's no need to emit files on the server side // (it can just use the assets emitted on client build // since the filenames are the same) function _dont_emit_file_loader(rule) { var file_loader = find_loader(rule, 'file-loader'); var url_loader = find_loader(rule, 'url-loader'); if (file_loader && url_loader) { throw new Error('You have both "url-loader" and "file-loader" defined for rule which makes no sense', util.inspect(rule)); } var loader = file_loader || url_loader; if (loader) { loader.options = _objectSpread(_objectSpread({}, loader.options), {}, { emitFile: false }); } } // Replaces `style-loader` and `css-loader` with `css-loader?exportOnlyLocals=true` // since it's no web browser and no files will be emitted. export function replace_style_loader(configuration) { var _iterator4 = _createForOfIteratorHelper(get_style_rules(configuration)), _step4; try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { var rule = _step4.value; var css_loader = find_loader(rule, 'css-loader'); if (css_loader) { var modules = css_loader.options && css_loader.options.modules; if (modules === undefined || modules === true) { modules = {}; } else if (typeof modules === 'string') { modules = { mode: modules }; } if (modules) { css_loader.options = _objectSpread(_objectSpread({}, css_loader.options), {}, { modules: _objectSpread(_objectSpread({}, modules), {}, { exportOnlyLocals: true }) }); } // Drop `style-loader`. rule.use = rule.use.filter(function (loader) { return loader.loader !== 'style-loader'; }); } } } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } } // Extracts npm package name. // Correctly handles "private" npm packages like `@namespace/package`. export function extract_package_name(path) { if (path.indexOf('/') === -1) { return path; } // For regular npm packages var package_name = path.slice(0, path.indexOf('/')); // Handle "private" npm packages if (package_name[0] === '@') { var start_from = package_name.length + '/'.length; var to = path.indexOf('/', start_from); if (to >= 0) { package_name += path.slice(start_from - '/'.length, to); } else { package_name = path; } } return package_name; } //# sourceMappingURL=serverConfiguration.js.map