Skip to content

Commit

Permalink
refactor: split overrideWebpackConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
SolidZORO committed Apr 4, 2021
1 parent 590f116 commit aded75c
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 135 deletions.
144 changes: 9 additions & 135 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
/* eslint-disable no-param-reassign, consistent-return, no-restricted-syntax */
const clone = require('clone');
const fs = require('fs');
const lessToJS = require('less-vars-to-js');
const { overrideWebpackConfig } = require('./overrideWebpackConfig');

// fix: prevents error when .less files are required by node
if (typeof require !== 'undefined') require.extensions['.less'] = () => {
Expand All @@ -13,144 +11,20 @@ module.exports = (
modifyVars: {},
// optional
lessVarsFilePath: undefined,
// optional https://github.com/webpack-contrib/css-loader#object
// optional / https://github.com/webpack-contrib/css-loader#object
cssLoaderOptions: {},
// optional / https://github.com/webpack-contrib/less-loader#options
lessLoaderOptions: {},
},
) => {
const lessVarsByFile = pluginOptions.lessVarsFilePath
? lessToJS(fs.readFileSync(pluginOptions.lessVarsFilePath, 'utf8'))
: {};

const modifyVars = {
...lessVarsByFile,
...pluginOptions.modifyVars,
};

return {
...pluginOptions,
webpack(webpackConfig, nextConfig) {
if (!nextConfig.defaultLoaders) {
throw new Error(
// eslint-disable-next-line max-len
'This plugin is not compatible with Next.js versions below 5.0.0 https://err.sh/next-plugins/upgrade',
);
}

const { dev } = nextConfig;
const { rules } = webpackConfig.module;

// compatible w/ webpack 4 and 5
const ruleIndex = rules.findIndex((rule) => Array.isArray(rule.oneOf));
const rule = rules[ruleIndex];

// ---- module ----

// find
const sassModuleRegx = '/\\.module\\.(scss|sass)$/';
const sassModuleIndex = rule.oneOf.findIndex(
(item) => `${item.test}` === sassModuleRegx,
);
const sassModule = rule.oneOf.find(
(item) => `${item.test}` === sassModuleRegx,
);

// clone
const lessModule = clone(sassModule);
lessModule.test = /\.less$/;
delete lessModule.issuer;

// overwrite
const lessModuleIndex = lessModule.use.findIndex((item) =>
`${item.loader}`.includes('sass-loader'),
);
lessModule.use.splice(lessModuleIndex, 1, {
// https://www.npmjs.com/package/less-loader
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
modifyVars,
},
},
return overrideWebpackConfig({
webpackConfig,
nextConfig,
pluginOptions
});

// ---- loader ----

// find
const cssModuleIndex = lessModule.use.findIndex((item) =>
`${item.loader}`.includes('css-loader'),
);
const cssModule = lessModule.use.find((item) =>
`${item.loader}`.includes('css-loader'),
);

// clone
const nextCssModule = clone(cssModule);

// merge webpackConfig
nextCssModule.options = {
...nextCssModule.options,
esModule: false,
sourceMap: false,
...pluginOptions.cssLoaderOptions,
//
modules: {
...nextCssModule.options.modules,
localIdentName: dev ? '[local]--[hash:4]' : '[hash:4]',
// if enable `local` mode, you can write this less
//
// ```styles.module.less
// .abc { <---- is local, match class='abc--nx3xc2'
// color: red;
//
// :global {
// .xyz { <---- is global, match class='xyz'
// color: blue;
// }
// }
// }
//
mode: 'local', // local, global, and pure, next.js default is `pure`
...(pluginOptions.cssLoaderOptions || {}).modules,
auto: true, // keep true
},
};

// overwrite
lessModule.use.splice(cssModuleIndex, 1, nextCssModule);

// append lessModule to webpack modules
rule.oneOf.splice(sassModuleIndex, 0, lessModule);
webpackConfig.module.rules[ruleIndex] = rule;

webpackConfig = handleAntdInServer(webpackConfig, nextConfig);

if (typeof pluginOptions.webpack === 'function')
return pluginOptions.webpack(webpackConfig, nextConfig);

return webpackConfig;
},
}
};
};

function handleAntdInServer(config, options) {
if (!options.isServer) return config;

const ANTD_STYLE_REGX = /antd\/.*?\/style.*?/;
const rawExternals = [...config.externals];

config.externals = [
(context, request, callback) => {
if (request.match(ANTD_STYLE_REGX)) return callback();

if (typeof rawExternals[0] === 'function')
rawExternals[0](context, request, callback);
else callback();
},
...(typeof rawExternals[0] === 'function' ? [] : rawExternals),
];

config.module.rules.unshift({ test: ANTD_STYLE_REGX, use: 'null-loader' });

return config;
}
152 changes: 152 additions & 0 deletions overrideWebpackConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/* eslint-disable no-param-reassign, consistent-return, no-restricted-syntax */
const clone = require('clone');
const fs = require('fs');
const lessToJS = require('less-vars-to-js');

// fix: prevents error when .less files are required by node
if (typeof require !== 'undefined') require.extensions['.less'] = () => {
};

// function overrideWebpackConfig(webpackConfig, nextConfig, pluginOptions) {
function overrideWebpackConfig({ webpackConfig, nextConfig, pluginOptions }) {
const lessVarsByFile = pluginOptions.lessVarsFilePath
? lessToJS(fs.readFileSync(pluginOptions.lessVarsFilePath, 'utf8'))
: {};

const modifyVars = {
...lessVarsByFile,
...pluginOptions.modifyVars,
};

if (nextConfig && !nextConfig.defaultLoaders) {
throw new Error(
// eslint-disable-next-line max-len
'This plugin is not compatible with Next.js versions below 5.0.0 https://err.sh/next-plugins/upgrade',
);
}

const { dev } = nextConfig;
const { rules } = webpackConfig.module;

// compatible w/ webpack 4 and 5
const ruleIndex = rules.findIndex((rule) => Array.isArray(rule.oneOf));
const rule = rules[ruleIndex];

// ---- module ----

// find
const sassModuleRegx = '/\\.module\\.(scss|sass)$/';
const sassModuleIndex = rule.oneOf.findIndex(
(item) => `${item.test}` === sassModuleRegx,
);
const sassModule = rule.oneOf.find(
(item) => `${item.test}` === sassModuleRegx,
);

// clone
const lessModule = clone(sassModule);
lessModule.test = /\.less$/;
delete lessModule.issuer;

// overwrite
const lessModuleIndex = lessModule.use.findIndex((item) =>
`${item.loader}`.includes('sass-loader'),
);
lessModule.use.splice(lessModuleIndex, 1, {
// https://github.com/webpack-contrib/less-loader#options
loader: 'less-loader',
options: {
lessOptions: {
javascriptEnabled: true,
modifyVars,
},
...pluginOptions.lessLoaderOptions,
},
});

// ---- loader ----

// find
const cssModuleIndex = lessModule.use.findIndex((item) =>
`${item.loader}`.includes('css-loader'),
);
const cssModule = lessModule.use.find((item) =>
`${item.loader}`.includes('css-loader'),
);

// clone
const nextCssModule = clone(cssModule);

// merge webpackConfig
nextCssModule.options = {
...nextCssModule.options,
esModule: false,
sourceMap: false,
...pluginOptions.cssLoaderOptions,
//
modules: {
...nextCssModule.options.modules,
localIdentName: dev ? '[local]--[hash:4]' : '[hash:4]',
// if enable `local` mode, you can write this less
//
// ```styles.module.less
// .abc { <---- is local, match class='abc--nx3xc2'
// color: red;
//
// :global {
// .xyz { <---- is global, match class='xyz'
// color: blue;
// }
// }
// }
//
mode: 'local', // local, global, and pure, next.js default is `pure`
...(pluginOptions.cssLoaderOptions || {}).modules,
auto: true, // keep true
},
};

// overwrite
lessModule.use.splice(cssModuleIndex, 1, nextCssModule);

// append lessModule to webpack modules
rule.oneOf.splice(sassModuleIndex, 0, lessModule);
webpackConfig.module.rules[ruleIndex] = rule;

// ONLY for next.js server
if (nextConfig) {
webpackConfig = handleAntdInServer(webpackConfig, nextConfig);

if (typeof pluginOptions.webpack === 'function')
return pluginOptions.webpack(webpackConfig, nextConfig);
}

return webpackConfig;
}

function handleAntdInServer(config, options) {
if (!options.isServer) return config;

const ANTD_STYLE_REGX = /antd\/.*?\/style.*?/;
const rawExternals = [...config.externals];

config.externals = [
(context, request, callback) => {
if (request.match(ANTD_STYLE_REGX)) return callback();

if (typeof rawExternals[0] === 'function')
rawExternals[0](context, request, callback);
else callback();
},
...(typeof rawExternals[0] === 'function' ? [] : rawExternals),
];

config.module.rules.unshift({ test: ANTD_STYLE_REGX, use: 'null-loader' });

return config;
}

module.exports = {
overrideWebpackConfig,
handleAntdInServer,
};

0 comments on commit aded75c

Please sign in to comment.