fix(core): resolve webpack loaders with require.resolve() (#3341)

With strict package managers such as pnpm or Yarn PnP, transitive
dependencies are *not* hoisted to the root node_modules folder. This
means that a webpack config defined within a package like
'@nrwl/cypress' cannot resolve loaders like 'ts-loader', unless
'ts-loader' is declared in the workspace's own package.json.

This is a problem because the workspace might define a different version
of 'ts-loader', incompatible with the version declared by
'@nrwl/cypress/package.json'. The workspace should not need to declare
a dependency on 'ts-loader' anyway.

See also:
* https://github.com/pnpm/pnpm/issues/801
* https://github.com/webpack/webpack/issues/5087
This commit is contained in:
Spencer Elliott 2020-07-15 13:55:38 -04:00 committed by GitHub
parent 24f544100e
commit d74ab4e9d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 35 additions and 31 deletions

View File

@ -20,7 +20,7 @@ describe('getWebpackConfig', () => {
});
expect(config.module.rules).toContainEqual({
test: /\.(j|t)sx?$/,
loader: 'ts-loader',
loader: require.resolve('ts-loader'),
exclude: [/node_modules/],
options: {
configFile: './tsconfig.json',

View File

@ -37,7 +37,7 @@ export function getWebpackConfig(config: any) {
rules: [
{
test: /\.(j|t)sx?$/,
loader: 'ts-loader',
loader: require.resolve('ts-loader'),
exclude: [/node_modules/],
options: {
configFile: config.env.tsConfig,

View File

@ -58,7 +58,7 @@ export function createWebpackConfig(
use: [
'@svgr/webpack?-svgo,+titleProp,+ref![path]',
{
loader: 'url-loader',
loader: require.resolve('url-loader'),
options: {
limit: 10000, // 10kB
name: '[name].[hash:7].[ext]',
@ -70,7 +70,7 @@ export function createWebpackConfig(
{
use: [
{
loader: 'url-loader',
loader: require.resolve('url-loader'),
options: {
limit: 10000, // 10kB
name: '[name].[hash:7].[ext]',

View File

@ -47,7 +47,7 @@ describe('getBaseWebpackPartial', () => {
);
expect(typescriptRule).toBeTruthy();
expect(typescriptRule.loader).toEqual('ts-loader');
expect(typescriptRule.loader).toContain('ts-loader');
});
it('should split typescript type checking into a separate workers', () => {
@ -131,7 +131,9 @@ describe('getBaseWebpackPartial', () => {
const result = getBaseWebpackPartial(input);
expect(
result.module.rules.find((rule) => rule.loader === 'ts-loader').options
result.module.rules.find((rule) =>
rule.loader.toString().includes('ts-loader')
).options
).toEqual({
configFile: 'tsconfig.json',
transpileOnly: true,

View File

@ -36,7 +36,7 @@ export function getBaseWebpackPartial(
rules: [
{
test: /\.(j|t)sx?$/,
loader: `ts-loader`,
loader: require.resolve(`ts-loader`),
exclude: /node_modules/,
options: {
configFile: options.tsConfig,

View File

@ -5,7 +5,7 @@ function getWebpackConfig(config: Configuration) {
config.module.rules.push(
{
test: /\.(png|jpe?g|gif|webp)$/,
loader: 'url-loader',
loader: require.resolve('url-loader'),
options: {
limit: 10000, // 10kB
name: '[name].[hash:7].[ext]',
@ -22,7 +22,7 @@ function getWebpackConfig(config: Configuration) {
use: [
'@svgr/webpack?-svgo,+titleProp,+ref![path]',
{
loader: 'url-loader',
loader: require.resolve('url-loader'),
options: {
limit: 10000, // 10kB
name: '[name].[hash:7].[ext]',
@ -34,7 +34,7 @@ function getWebpackConfig(config: Configuration) {
{
use: [
{
loader: 'url-loader',
loader: require.resolve('url-loader'),
options: {
limit: 10000, // 10kB
name: '[name].[hash:7].[ext]',

View File

@ -49,7 +49,7 @@ describe('getBaseWebpackPartial', () => {
);
expect(rule).toBeTruthy();
expect(rule.loader).toEqual('babel-loader');
expect(rule.loader).toContain('babel-loader');
});
it('should split typescript type checking into a separate workers', () => {
@ -165,8 +165,9 @@ describe('getBaseWebpackPartial', () => {
const result = getBaseWebpackPartial(input, true);
expect(
(result.module.rules.find((rule) => rule.loader === 'babel-loader')
.options as any).envName
(result.module.rules.find((rule) =>
rule.loader.toString().includes('babel-loader')
).options as any).envName
).toMatch('modern');
});
@ -174,8 +175,9 @@ describe('getBaseWebpackPartial', () => {
const result = getBaseWebpackPartial(input, false);
expect(
(result.module.rules.find((rule) => rule.loader === 'babel-loader')
.options as any).envName
(result.module.rules.find((rule) =>
rule.loader.toString().includes('babel-loader')
).options as any).envName
).toMatch('legacy');
});
});

View File

@ -48,7 +48,7 @@ export function getBaseWebpackPartial(
rules: [
{
test: /\.([jt])sx?$/,
loader: `babel-loader`,
loader: require.resolve(`babel-loader`),
exclude: /node_modules/,
options: {
rootMode: 'upward',

View File

@ -316,7 +316,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
sourceMapUseRule = {
use: [
{
loader: 'source-map-loader',
loader: require.resolve('source-map-loader'),
},
],
};
@ -490,7 +490,7 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration {
rules: [
{
test: /\.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/,
loader: 'file-loader',
loader: require.resolve('file-loader'),
options: {
name: `[name]${hashFormat.file}.[ext]`,
},

View File

@ -146,7 +146,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
test: /\.scss$|\.sass$/,
use: [
{
loader: 'sass-loader',
loader: require.resolve('sass-loader'),
options: {
implementation: sassImplementation,
sourceMap: cssSourceMap,
@ -164,7 +164,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
test: /\.less$/,
use: [
{
loader: 'less-loader',
loader: require.resolve('less-loader'),
options: {
sourceMap: cssSourceMap,
javascriptEnabled: true,
@ -177,7 +177,7 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
test: /\.styl$/,
use: [
{
loader: 'stylus-loader',
loader: require.resolve('stylus-loader'),
options: {
sourceMap: cssSourceMap,
paths: includePaths,
@ -192,9 +192,9 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
exclude: globalStylePaths,
test,
use: [
{ loader: 'raw-loader' },
{ loader: require.resolve('raw-loader') },
{
loader: 'postcss-loader',
loader: require.resolve('postcss-loader'),
options: {
ident: 'embedded',
plugins: postcssPluginCreator,
@ -224,10 +224,10 @@ export function getStylesConfig(wco: WebpackConfigOptions) {
use: [
buildOptions.extractCss
? MiniCssExtractPlugin.loader
: 'style-loader',
: require.resolve('style-loader'),
RawCssLoader,
{
loader: 'postcss-loader',
loader: require.resolve('postcss-loader'),
options: {
ident: buildOptions.extractCss ? 'extracted' : 'embedded',
plugins: postcssPluginCreator,

View File

@ -121,7 +121,7 @@ function getStylesPartial(
loaderConfig.loader === 'raw-loader'
) {
return {
loader: 'style-loader',
loader: require.resolve('style-loader'),
};
}
return loaderConfig;
@ -138,10 +138,10 @@ function getStylesPartial(
{
loader: options.extractCss
? MiniCssExtractPlugin.loader
: 'style-loader',
: require.resolve('style-loader'),
},
{
loader: 'css-loader',
loader: require.resolve('css-loader'),
options: {
modules: true,
importLoaders: 1,
@ -155,16 +155,16 @@ function getStylesPartial(
{
loader: options.extractCss
? MiniCssExtractPlugin.loader
: 'style-loader',
: require.resolve('style-loader'),
},
{
loader: 'css-loader',
loader: require.resolve('css-loader'),
options: {
modules: true,
importLoaders: 1,
},
},
{ loader: 'sass-loader' },
{ loader: require.resolve('sass-loader') },
],
},
...rules,