Skip to content

Commit

Permalink
fix(nextjs): add missing style deps for less and stylus (#15839)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysoo committed Mar 22, 2023
1 parent a106280 commit e904e04
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 148 deletions.
6 changes: 6 additions & 0 deletions packages/next/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
"version": "14.5.3-beta.0",
"description": "Update development outputPath to the project root.",
"factory": "./src/migrations/update-14-5-3/update-dev-output-path"
},
"add-style-packages": {
"cli": "nx",
"version": "15.8.8-beta.0",
"description": "Add less and stylus packages if used.",
"factory": "./src/migrations/update-15-8-8/add-style-packages"
}
},
"packageJsonUpdates": {
Expand Down
155 changes: 81 additions & 74 deletions packages/next/plugins/with-less.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Adapted from https://raw.githubusercontent.com/elado/next-with-less/main/src/index.js
import { merge } from 'webpack-merge';
import { NextConfigFn } from './with-nx';

const addLessToRegExp = (rx) =>
new RegExp(rx.source.replace('|sass', '|sass|less'), rx.flags);
Expand All @@ -12,86 +13,92 @@ function patchNextCSSWithLess(

patchNextCSSWithLess();

export function withLess({ lessLoaderOptions = {}, ...nextConfig }) {
return Object.assign({}, nextConfig, {
webpack(config, opts) {
// there are 2 relevant sass rules in next.js - css modules and global css
let sassModuleRule;
// global sass rule (does not exist in server builds)
let sassGlobalRule;

const cssRule = config.module.rules.find((rule) =>
rule.oneOf?.find((r) => r?.[Symbol.for('__next_css_remove')])
);

const addLessToRuleTest = (test) => {
if (Array.isArray(test)) {
return test.map((rx) => addLessToRegExp(rx));
} else {
return addLessToRegExp(test);
}
};

cssRule.oneOf.forEach((rule) => {
if (rule.options?.__next_css_remove) return;

if (rule.use?.loader === 'error-loader') {
rule.test = addLessToRuleTest(rule.test);
} else if (rule.use?.loader?.includes('file-loader')) {
rule.issuer = addLessToRuleTest(rule.issuer);
} else if (rule.use?.includes?.('ignore-loader')) {
rule.test = addLessToRuleTest(rule.test);
} else if (rule.test?.source === '\\.module\\.(scss|sass)$') {
sassModuleRule = rule;
} else if (rule.test?.source === '(?<!\\.module)\\.(scss|sass)$') {
sassGlobalRule = rule;
}
});

const lessLoader = {
loader: 'less-loader',
options: {
...lessLoaderOptions,
lessOptions: {
javascriptEnabled: true,
// @ts-ignore
...lessLoaderOptions.lessOptions,
export function withLess(configFn: NextConfigFn): NextConfigFn {
return async (phase: string) => {
const { lessLoaderOptions = {}, ...nextConfig } = await configFn(phase);

return Object.assign({}, nextConfig, {
webpack(config, opts) {
// there are 2 relevant sass rules in next.js - css modules and global css
let sassModuleRule;
// global sass rule (does not exist in server builds)
let sassGlobalRule;

const cssRule = config.module.rules.find((rule) =>
rule.oneOf?.find((r) => r?.[Symbol.for('__next_css_remove')])
);

const addLessToRuleTest = (test) => {
if (Array.isArray(test)) {
return test.map((rx) => addLessToRegExp(rx));
} else {
return addLessToRegExp(test);
}
};

cssRule.oneOf.forEach((rule) => {
if (rule.options?.__next_css_remove) return;

if (rule.use?.loader === 'error-loader') {
rule.test = addLessToRuleTest(rule.test);
} else if (rule.use?.loader?.includes('file-loader')) {
rule.issuer = addLessToRuleTest(rule.issuer);
} else if (rule.use?.includes?.('ignore-loader')) {
rule.test = addLessToRuleTest(rule.test);
} else if (rule.test?.source === '\\.module\\.(scss|sass)$') {
sassModuleRule = rule;
} else if (rule.test?.source === '(?<!\\.module)\\.(scss|sass)$') {
sassGlobalRule = rule;
}
});

const lessLoader = {
loader: 'less-loader',
options: {
...lessLoaderOptions,
lessOptions: {
javascriptEnabled: true,
// @ts-ignore
...lessLoaderOptions.lessOptions,
},
},
},
};

let lessModuleRule = merge(sassModuleRule);

const configureLessRule = (rule) => {
rule.test = new RegExp(rule.test.source.replace('(scss|sass)', 'less'));
// replace sass-loader (last entry) with less-loader
rule.use.splice(-1, 1, lessLoader);
};

configureLessRule(lessModuleRule);
cssRule.oneOf.splice(
cssRule.oneOf.indexOf(sassModuleRule) + 1,
0,
lessModuleRule
);

if (sassGlobalRule) {
let lessGlobalRule = merge(sassGlobalRule);
configureLessRule(lessGlobalRule);
};

let lessModuleRule = merge(sassModuleRule);

const configureLessRule = (rule) => {
rule.test = new RegExp(
rule.test.source.replace('(scss|sass)', 'less')
);
// replace sass-loader (last entry) with less-loader
rule.use.splice(-1, 1, lessLoader);
};

configureLessRule(lessModuleRule);
cssRule.oneOf.splice(
cssRule.oneOf.indexOf(sassGlobalRule) + 1,
cssRule.oneOf.indexOf(sassModuleRule) + 1,
0,
lessGlobalRule
lessModuleRule
);
}

if (typeof nextConfig.webpack === 'function') {
return nextConfig.webpack(config, opts);
}
if (sassGlobalRule) {
let lessGlobalRule = merge(sassGlobalRule);
configureLessRule(lessGlobalRule);
cssRule.oneOf.splice(
cssRule.oneOf.indexOf(sassGlobalRule) + 1,
0,
lessGlobalRule
);
}

if (typeof nextConfig.webpack === 'function') {
return nextConfig.webpack(config, opts);
}

return config;
},
});
return config;
},
});
};
}

module.exports = withLess;
Expand Down
6 changes: 5 additions & 1 deletion packages/next/plugins/with-nx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export interface WithNxOptions extends NextConfig {
};
}

export interface NextConfigFn {
(phase: string): Promise<NextConfig>;
}

export interface WithNxContext {
workspaceRoot: string;
libsDir: string;
Expand Down Expand Up @@ -114,7 +118,7 @@ function getNxContext(
export function withNx(
_nextConfig = {} as WithNxOptions,
context: WithNxContext = getWithNxContext()
): (phase: string) => Promise<NextConfig> {
): NextConfigFn {
return async (phase: string) => {
if (phase === PHASE_PRODUCTION_SERVER) {
// If we are running an already built production server, just return the configuration.
Expand Down
153 changes: 80 additions & 73 deletions packages/next/plugins/with-stylus.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Adapted from https://raw.githubusercontent.com/elado/next-with-less/main/src/index.js
import { merge } from 'webpack-merge';
import { NextConfigFn } from './with-nx';

const addStylusToRegExp = (rx) =>
new RegExp(rx.source.replace('|sass', '|sass|styl'), rx.flags);
Expand All @@ -12,85 +13,91 @@ function patchNextCSSWithStylus(

patchNextCSSWithStylus();

export function withStylus({ stylusLoaderOptions = {}, ...nextConfig }: any) {
return Object.assign({}, nextConfig, {
webpack(config, opts) {
// there are 2 relevant sass rules in next.js - css modules and global css
let sassModuleRule;
// global sass rule (does not exist in server builds)
let sassGlobalRule;

const cssRule = config.module.rules.find((rule) =>
rule.oneOf?.find((r) => r?.[Symbol.for('__next_css_remove')])
);

const addStylusRuleToTest = (test) => {
if (Array.isArray(test)) {
return test.map((rx) => addStylusToRegExp(rx));
} else {
return addStylusToRegExp(test);
}
};

cssRule.oneOf.forEach((rule) => {
if (rule.options?.__next_css_remove) return;

if (rule.use?.loader === 'error-loader') {
rule.test = addStylusRuleToTest(rule.test);
} else if (rule.use?.loader?.includes('file-loader')) {
rule.issuer = addStylusRuleToTest(rule.issuer);
} else if (rule.use?.includes?.('ignore-loader')) {
rule.test = addStylusRuleToTest(rule.test);
} else if (rule.test?.source === '\\.module\\.(scss|sass)$') {
sassModuleRule = rule;
} else if (rule.test?.source === '(?<!\\.module)\\.(scss|sass)$') {
sassGlobalRule = rule;
}
});

const stylusLoader = {
loader: 'stylus-loader',
options: {
...stylusLoaderOptions,
stylusOptions: {
javascriptEnabled: true,
...stylusLoaderOptions.stylusOptions,
export function withStylus(configFn: NextConfigFn): NextConfigFn {
return async (phase: string) => {
const { stylusLoaderOptions = {}, ...nextConfig } = await configFn(phase);

return Object.assign({}, nextConfig, {
webpack(config, opts) {
// there are 2 relevant sass rules in next.js - css modules and global css
let sassModuleRule;
// global sass rule (does not exist in server builds)
let sassGlobalRule;

const cssRule = config.module.rules.find((rule) =>
rule.oneOf?.find((r) => r?.[Symbol.for('__next_css_remove')])
);

const addStylusRuleToTest = (test) => {
if (Array.isArray(test)) {
return test.map((rx) => addStylusToRegExp(rx));
} else {
return addStylusToRegExp(test);
}
};

cssRule.oneOf.forEach((rule) => {
if (rule.options?.__next_css_remove) return;

if (rule.use?.loader === 'error-loader') {
rule.test = addStylusRuleToTest(rule.test);
} else if (rule.use?.loader?.includes('file-loader')) {
rule.issuer = addStylusRuleToTest(rule.issuer);
} else if (rule.use?.includes?.('ignore-loader')) {
rule.test = addStylusRuleToTest(rule.test);
} else if (rule.test?.source === '\\.module\\.(scss|sass)$') {
sassModuleRule = rule;
} else if (rule.test?.source === '(?<!\\.module)\\.(scss|sass)$') {
sassGlobalRule = rule;
}
});

const stylusLoader = {
loader: 'stylus-loader',
options: {
...stylusLoaderOptions,
stylusOptions: {
javascriptEnabled: true,
...stylusLoaderOptions.stylusOptions,
},
},
},
};

let stylusModuleRule = merge({}, sassModuleRule);

const configureStylusRule = (rule) => {
rule.test = new RegExp(rule.test.source.replace('(scss|sass)', 'styl'));
// replace sass-loader (last entry) with stylus-loader
rule.use.splice(-1, 1, stylusLoader);
};

configureStylusRule(stylusModuleRule);
cssRule.oneOf.splice(
cssRule.oneOf.indexOf(sassModuleRule) + 1,
0,
stylusModuleRule
);

if (sassGlobalRule) {
let stylusGlobalRule = merge({}, sassGlobalRule);
configureStylusRule(stylusGlobalRule);
};

let stylusModuleRule = merge({}, sassModuleRule);

const configureStylusRule = (rule) => {
rule.test = new RegExp(
rule.test.source.replace('(scss|sass)', 'styl')
);
// replace sass-loader (last entry) with stylus-loader
rule.use.splice(-1, 1, stylusLoader);
};

configureStylusRule(stylusModuleRule);
cssRule.oneOf.splice(
cssRule.oneOf.indexOf(sassGlobalRule) + 1,
cssRule.oneOf.indexOf(sassModuleRule) + 1,
0,
stylusGlobalRule
stylusModuleRule
);
}

if (typeof nextConfig.webpack === 'function') {
return nextConfig.webpack(config, opts);
}
if (sassGlobalRule) {
let stylusGlobalRule = merge({}, sassGlobalRule);
configureStylusRule(stylusGlobalRule);
cssRule.oneOf.splice(
cssRule.oneOf.indexOf(sassGlobalRule) + 1,
0,
stylusGlobalRule
);
}

if (typeof nextConfig.webpack === 'function') {
return nextConfig.webpack(config, opts);
}

return config;
},
});
return config;
},
});
};
}

module.exports = withStylus;
Expand Down

0 comments on commit e904e04

Please sign in to comment.