Files
Igor Randjelovic cb91cd8a3f fix(webpack): angular component css handling (#9434)
* feat: use raw-loader for all css but app.s?css

* feat: use angular css rules for entire app dir

Co-authored-by: Eduardo Speroni <edusperoni@gmail.com>
2021-08-03 14:37:58 +02:00

237 lines
7.2 KiB
TypeScript

import { extname, resolve } from 'path';
import Config from 'webpack-chain';
import { existsSync } from 'fs';
import { getProjectFilePath } from '../helpers/project';
import { env as _env, IWebpackEnv } from '../index';
import {
getEntryDirPath,
getEntryPath,
getPlatformName,
} from '../helpers/platform';
import base from './base';
export default function (config: Config, env: IWebpackEnv = _env): Config {
base(config, env);
const platform = getPlatformName();
const tsConfigPath = [
getProjectFilePath('tsconfig.app.json'),
getProjectFilePath('tsconfig.json'),
].find((path) => existsSync(path));
// remove default ts rule
config.module.rules.delete('ts');
// remove fork ts checked as not needed
config.plugins.delete('ForkTsCheckerWebpackPlugin');
// explicitly define mainFields to make sure ngcc compiles as es2015 (module field)
// instead of umd (main field).
config.resolve.mainFields.add('module').add('main');
config.module
.rule('angular')
.test(/(?:\.ngfactory.js|\.ngstyle\.js|\.ts)$/)
.use('@ngtools/webpack')
.loader('@ngtools/webpack');
config.module
.rule('@angular/core')
.test(/[\/\\]@angular[\/\\]core[\/\\].+\.js$/)
.parser({ system: true });
// set up html
config.module
.rule('html')
.test(/\.html$/)
.use('raw-loader')
.loader('raw-loader');
// exclude component css files from the normal css rule
config.module
.rule('css')
.include.add(resolve(getEntryDirPath(), 'app.css'))
.add(resolve(getEntryDirPath(), `app.${platform}.css`))
.add(/node_modules/);
// and instead use raw-loader, since that's what angular expects
config.module
.rule('css|component')
.exclude.add(resolve(getEntryDirPath(), 'app.css'))
.add(resolve(getEntryDirPath(), `app.${platform}.css`))
.add(/node_modules/)
.end()
.test(/\.css$/)
.use('raw-loader')
.loader('raw-loader');
// get base postCSS options
const postCSSOptions = config.module
.rule('scss')
.uses.get('postcss-loader')
.get('options');
// exclude component css files from the normal css rule
config.module
.rule('scss')
.include.add(resolve(getEntryDirPath(), 'app.scss'))
.add(resolve(getEntryDirPath(), `app.${platform}.scss`))
.add(/node_modules/);
// and instead use raw-loader, since that's what angular expects
config.module
.rule('scss|component')
.exclude.add(resolve(getEntryDirPath(), 'app.css'))
.add(resolve(getEntryDirPath(), `app.${platform}.css`))
.add(/node_modules/)
.end()
.test(/\.scss$/)
.use('raw-loader')
.loader('raw-loader')
.end()
.use('postcss-loader')
.loader('postcss-loader')
.options(postCSSOptions)
.end()
.use('sass-loader')
.loader('sass-loader');
const angularCompilerPlugin = getAngularCompilerPlugin();
if (angularCompilerPlugin) {
config.plugin('AngularCompilerPlugin').use(angularCompilerPlugin, [
{
tsConfigPath,
mainPath: getEntryPath(),
// disable type checking in a forked process - it ignores
// the hostReplacementPaths and prints errors about
// platform suffixed files, even though they are
// working as expected.
forkTypeChecker: false,
hostReplacementPaths(path: string) {
const ext = extname(path);
const platformExt = `.${platform}${ext}`;
// already includes a platform specific extension - ignore
if (path.includes(platformExt)) {
return path;
}
const platformPath = path.replace(ext, platformExt);
// check if the same file exists with a platform suffix and return if it does.
if (existsSync(platformPath)) {
// console.log(`[hostReplacementPaths] resolving "${path}" to "${platformPath}"`);
return platformPath;
}
// just return the original path otherwise
return path;
},
platformTransformers: [require('../transformers/NativeClass').default],
},
]);
}
const angularWebpackPlugin = getAngularWebpackPlugin();
if (angularWebpackPlugin) {
// angular no longer supports transformers.
// so we patch their method until they do
// https://github.com/angular/angular-cli/pull/21046
const originalCreateFileEmitter =
angularWebpackPlugin.prototype.createFileEmitter;
angularWebpackPlugin.prototype.createFileEmitter = function (
...args: any[]
) {
let transformers = args[1] || {};
if (!transformers.before) {
transformers.before = [];
}
transformers.before.push(require('../transformers/NativeClass').default);
args[1] = transformers;
return originalCreateFileEmitter.apply(this, args);
};
config.plugin('AngularWebpackPlugin').use(angularWebpackPlugin, [
{
tsconfig: tsConfigPath,
directTemplateLoading: false,
},
]);
config.when(env.hmr, (config) => {
config.module
.rule('angular-hmr')
.enforce('post')
.test(getEntryPath())
.use('angular-hot-loader')
.loader('angular-hot-loader');
});
}
// look for platform specific polyfills first
// falling back to independent polyfills
const polyfillsPath = [
resolve(getEntryDirPath(), `polyfills.${platform}.ts`),
resolve(getEntryDirPath(), `polyfills.ts`),
].find((path) => existsSync(path));
if (polyfillsPath) {
const paths = config.entry('bundle').values();
// replace globals with the polyfills file which
// should handle loading the correct globals
// and any additional polyfills required.
if (paths.includes('@nativescript/core/globals/index.js')) {
paths[
paths.indexOf('@nativescript/core/globals/index.js')
] = polyfillsPath;
// replace paths with the update paths
config.entry('bundle').clear().merge(paths);
}
}
// Filter common undesirable warnings
config.set(
'ignoreWarnings',
(config.get('ignoreWarnings') ?? []).concat([
/**
* This rule hides
* +-----------------------------------------------------------------------------------------+
* | WARNING in Zone.js does not support native async/await in ES2017+. |
* | These blocks are not intercepted by zone.js and will not triggering change detection. |
* | See: https://github.com/angular/zone.js/pull/1140 for more information. |
* +-----------------------------------------------------------------------------------------+
*/
/Zone\.js does not support native async\/await/,
/**
* This rule hides
* +-----------------------------------------------------------------------------------------+
* | WARNING in environment.*.ts is part of the TypeScript compilation but it's unused. |
* | Add only entry points to the 'files' or 'include' properties in your tsconfig. |
* +-----------------------------------------------------------------------------------------+
*/
/environment(\.(\w+))?\.ts is part of the TypeScript compilation but it's unused/,
// Additional rules to suppress warnings that are safe to ignore
{
module: /@angular\/core\/(__ivy_ngcc__\/)?fesm2015\/core.js/,
message: /Critical dependency: the request of a dependency is an expression/,
},
/core\/profiling/,
/core\/ui\/styling/,
])
);
return config;
}
function getAngularCompilerPlugin(): any {
const { AngularCompilerPlugin } = require('@ngtools/webpack');
return AngularCompilerPlugin;
}
function getAngularWebpackPlugin(): any {
const { AngularWebpackPlugin } = require('@ngtools/webpack');
return AngularWebpackPlugin;
}