lib/webpack/webpack.common.js
const fs = require('fs');
const path = require('path');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const rxPaths = require('rxjs/_esm5/path-mapping');
const autoprefixer = require('autoprefixer');
const postcssUrl = require('postcss-url');
const cssnano = require('cssnano');
const postcssImports = require('postcss-import');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const config = require('./config.js');
const {NoEmitOnErrorsPlugin, SourceMapDevToolPlugin, NamedModulesPlugin} = require('webpack');
const {NamedLazyChunksWebpackPlugin, BaseHrefWebpackPlugin} = require('@angular/cli/plugins/webpack');
const {CommonsChunkPlugin} = require('webpack').optimize;
const {AngularCompilerPlugin} = require('@ngtools/webpack');
const nodeModules = path.join(process.cwd(), 'node_modules');
const realNodeModules = fs.realpathSync(nodeModules);
const genDirNodeModules = path.join(process.cwd(), 'src', '$$_gendir', 'node_modules');
const entryPoints = ["inline", "polyfills", "sw-register", "styles", "vendor", "main"];
const minimizeCss = false;
const baseHref = "";
const deployUrl = "";
const maximumInlineSize = 10;
const postcssPlugins = function (loader) {
// safe settings based on: https://github.com/ben-eb/cssnano/issues/358#issuecomment-283696193
const importantCommentRe = /@preserve|@licen[cs]e|[@#]\s*source(?:Mapping)?URL|^!/i;
const minimizeOptions = {
autoprefixer: false,
safe: true,
mergeLonghand: false,
discardComments: {remove: (comment) => !importantCommentRe.test(comment)}
};
return [
postcssImports({
resolve: (url, context) => {
return new Promise((resolve, reject) => {
if (url && url.startsWith('~')) {
url = url.substr(1);
}
loader.resolve(context, url, (err, result) => {
if (err) {
reject(err);
return;
}
resolve(result);
});
});
},
load: (filename) => {
return new Promise((resolve, reject) => {
loader.fs.readFile(filename, (err, data) => {
if (err) {
reject(err);
return;
}
const content = data.toString();
resolve(content);
});
});
}
}),
postcssUrl({
filter: ({url}) => url.startsWith('~'),
url: ({url}) => {
const fullPath = path.join(config.folders.nodeModules, url.substr(1));
return path.relative(loader.context, fullPath).replace(/\\/g, '/');
}
}),
postcssUrl([
{
// Only convert root relative URLs, which CSS-Loader won't process into require().
filter: ({url}) => url.startsWith('/') && !url.startsWith('//'),
url: ({url}) => {
if (deployUrl.match(/:\/\//) || deployUrl.startsWith('/')) {
// If deployUrl is absolute or root relative, ignore baseHref & use deployUrl as is.
return `${deployUrl.replace(/\/$/, '')}${url}`;
}
else if (baseHref.match(/:\/\//)) {
// If baseHref contains a scheme, include it as is.
return baseHref.replace(/\/$/, '') +
`/${deployUrl}/${url}`.replace(/\/\/+/g, '/');
}
else {
// Join together base-href, deploy-url and the original URL.
// Also dedupe multiple slashes into single ones.
return `/${baseHref}/${deployUrl}/${url}`.replace(/\/\/+/g, '/');
}
}
},
{
// TODO: inline .cur if not supporting IE (use browserslist to check)
filter: (asset) => {
return maximumInlineSize > 0 && !asset.hash && !asset.absolutePath.endsWith('.cur');
},
url: 'inline',
// NOTE: maxSize is in KB
maxSize: maximumInlineSize,
fallback: 'rebase',
},
{url: 'rebase'},
]),
autoprefixer(),
].concat(minimizeCss ? [cssnano(minimizeOptions)] : []);
};
module.exports = {
"resolve": {
"extensions": [
".ts",
".js"
],
"modules": [
"./node_modules",
"./node_modules"
],
"symlinks": true,
"alias": rxPaths(),
"mainFields": [
"browser",
"module",
"main"
]
},
"resolveLoader": {
"modules": [
"./node_modules",
"./node_modules"
],
"alias": rxPaths()
},
"entry": {
"main": [
config.files.main
],
"polyfills": [
config.files.polyfills
],
"styles": config.styles
},
"output": {
"path": config.folders.dist,
"filename": "[name].[hash].bundle.js",
"chunkFilename": "[id].[hash].chunk.js",
"crossOriginLoading": false
},
"module": {
"rules": [
{
"test": /\.html$/,
"loader": "raw-loader"
},
{
"test": /\.(eot|svg|cur)$/,
"loader": "file-loader",
"options": {
"name": "[name].[hash:20].[ext]",
"limit": 10000
}
},
{
"test": /\.(ico)$/,
"loader": "file-loader",
"options": {
"name": "[name].[ext]",
"limit": 10000
}
},
{
"test": /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/,
"loader": "url-loader",
"options": {
"name": "[name].[hash:20].[ext]",
"limit": 10000
}
},
{
"exclude": config.styles,
"test": /\.css$/,
"use": [
"exports-loader?module.exports.toString()",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"import": false
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins,
"sourceMap": false
}
}
]
},
{
"include": config.styles,
"test": /\.css$/,
"use": [
"style-loader",
{
"loader": "css-loader",
"options": {
"sourceMap": false,
"import": false
}
},
{
"loader": "postcss-loader",
"options": {
"ident": "postcss",
"plugins": postcssPlugins,
"sourceMap": false
}
}
]
},
{
"test": /\.ts$/,
"loader": "@ngtools/webpack"
}
]
},
"plugins": [
new CleanWebpackPlugin(
[config.clean.path],
{
root: config.clean.root,
exclude: config.clean.exclude
}
),
new NoEmitOnErrorsPlugin(),
new ProgressPlugin(),
new NamedLazyChunksWebpackPlugin(),
new HtmlWebpackPlugin({
"template": config.files.index,
"filename": "./index.html",
"hash": false,
"inject": true,
"compile": true,
"favicon": config.files.favicon,
"minify": false,
"cache": true,
"showErrors": true,
"chunks": "all",
"excludeChunks": [],
"title": "Webpack App",
"xhtml": true,
"chunksSortMode": function sort(left, right) {
let leftIndex = entryPoints.indexOf(left.names[0]);
let rightIndex = entryPoints.indexOf(right.names[0]);
if (leftIndex > rightIndex) {
return 1;
}
else if (leftIndex < rightIndex) {
return -1;
}
else {
return 0;
}
}
}),
new BaseHrefWebpackPlugin({}),
new CommonsChunkPlugin({
"name": [
"inline"
],
"minChunks": null
}),
new CommonsChunkPlugin({
"name": [
"vendor"
],
"minChunks": (module) => {
return module.resource
&& (module.resource.startsWith(nodeModules)
|| module.resource.startsWith(genDirNodeModules)
|| module.resource.startsWith(realNodeModules));
},
"chunks":
[
"main"
]
}),
new SourceMapDevToolPlugin({
"filename": "[file].map[query]",
"moduleFilenameTemplate": "[resource-path]",
"fallbackModuleFilenameTemplate": "[resource-path]?[hash]",
"sourceRoot": "webpack:///"
}),
new CommonsChunkPlugin({
"name": [
"main"
],
"minChunks": 2,
"async": "common"
}),
new NamedModulesPlugin({}),
new AngularCompilerPlugin({
"mainPath": "main.ts",
"platform": 0,
"hostReplacementPaths": {
"environments/environment.ts": "environments/environment.ts"
},
"sourceMap": true,
"tsConfigPath": config.files.tsConfigAppJson,
"skipCodeGeneration": true,
"compilerOptions": {}
})
],
"node":
{
"fs":
"empty",
"global":
true,
"crypto":
"empty",
"tls":
"empty",
"net":
"empty",
"process":
true,
"module":
false,
"clearImmediate":
false,
"setImmediate":
false
}
,
"devServer":
{
"historyApiFallback":
true
}
};