Skip to content

Commit

Permalink
fix: patch scss/style loader to support unpatched configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
BowlingX committed Jul 13, 2023
1 parent aa5f32c commit 4b808fc
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 13 deletions.
3 changes: 2 additions & 1 deletion src/webpack/nextjs-webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Span } from 'next/dist/trace/index.js'
import findPagesDirPkg from 'next/dist/lib/find-pages-dir.js'
import semver from 'semver'
import packageJson from 'next/package.json' assert { type: 'json' }
import { type Configuration } from 'webpack'

const { findPagesDir } = findPagesDirPkg

Expand All @@ -17,7 +18,7 @@ export const createNextJsWebpackConfig = async (
runWebpackSpan: Span,
compilerType: CompilerNameValues,
config: NextConfigComplete
) => {
): Promise<Configuration> => {
const isAppDirEnabled = !!config.experimental.appDir
const { appDir, ...rest } = findPagesDir(appDirectory, isAppDirEnabled)

Expand Down
70 changes: 58 additions & 12 deletions src/webpack/webpack.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import webpack, { type Configuration, web } from 'webpack'
import webpack, {
type Configuration,
web,
WebpackPluginInstance,
} from 'webpack'
import process from 'node:process'
import LoadablePlugin from '@loadable/webpack-plugin'
import { ERROR_NO_RESOLVE, resolveEntry } from '../utils.js'
Expand Down Expand Up @@ -45,6 +49,11 @@ export default async (env: Args) => {
import.meta.url
)

const errorLoaderShim = await resolveEntry(
'../webpack/error-loader.shim.js',
import.meta.url
)

// @ts-ignore
await nextJsWebpack.init()

Expand Down Expand Up @@ -100,6 +109,42 @@ export default async (env: Args) => {
mode: 'production',
}

// We have to patch some of the sass / css behaviour to have support for global imports which are not inside the _app.js / _app.tsx file

// let's find all css loaders
const nextCssLoaders = clientModule?.rules?.find(
(rule) => typeof (rule as webpack.RuleSetRule).oneOf === 'object'
) as webpack.RuleSetRule

// Let's find the nextjs original sass loader definition
const nextSassLoader = nextCssLoaders?.oneOf?.find(
(rule: webpack.RuleSetRule) =>
rule.sideEffects === false &&
rule.test?.toString() === /\.module\.(scss|sass)$/.toString()
) as webpack.RuleSetRule

// apply rules to all scss files
nextSassLoader.test = /(\.scss|\.sass)$/

const cssLoader = (nextSassLoader?.use as webpack.RuleSetUseItem[])?.find(
(loader) => {
if (typeof loader === 'object') {
return loader.loader?.match(/css-loader/)
}
return false
}
)

if (typeof cssLoader === 'object') {
if (typeof cssLoader!.options === 'object') {
if (cssLoader?.options?.modules)
cssLoader!.options!.modules = {
...cssLoader!.options!.modules,
auto: true,
}
}
}

return [
// server/node bundle
{
Expand All @@ -112,16 +157,16 @@ export default async (env: Args) => {
resolve: {
...serverConfig.resolve,
alias: {
...serverConfig.resolve.alias,
...serverConfig?.resolve?.alias,
...baseAliases,
},
},
module: {
...serverModule,
parser: {
...serverModule.parser,
...serverModule?.parser,
javascript: {
...serverModule.parser.javascript,
...serverModule?.parser?.javascript,
dynamicImportMode: 'eager',
},
},
Expand All @@ -147,22 +192,22 @@ export default async (env: Args) => {
new webpack.DefinePlugin({
'process.env.__NEXT_STATIC_I18N': JSON.stringify(config.i18n || {}),
}),
...serverConfig.plugins
.filter(
...(serverConfig?.plugins
?.filter(
(plugin: webpack.WebpackPluginInstance) =>
!(
plugin instanceof PagesManifestPlugin.default ||
plugin instanceof TraceEntryPointsPlugin
)
)
.map((plugin: webpack.WebpackPluginInstance) => {
?.map((plugin: webpack.WebpackPluginInstance) => {
if (plugin instanceof webpack.DefinePlugin) {
// we have to define these envs, as we do not transpile any next dependencies
delete plugin.definitions['process.env.__NEXT_I18N_SUPPORT']
delete plugin.definitions['process.env.__NEXT_ROUTER_BASEPATH']
}
return plugin
}),
}) || []),
// output only a single file (we don't need to split on the server)
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
Expand All @@ -178,6 +223,7 @@ export default async (env: Args) => {
},
...baseConfig,
module: clientModule,
resolveLoader: clientConfig.resolveLoader,
entry: {
[INIT_ENTRY]: publicPathConfigShell,
[SHELL_ENTRY]: {
Expand All @@ -188,7 +234,7 @@ export default async (env: Args) => {
resolve: {
...clientConfig.resolve,
alias: {
...clientConfig.resolve.alias,
...clientConfig?.resolve?.alias,
...baseAliases,
},
},
Expand All @@ -203,15 +249,15 @@ export default async (env: Args) => {
/next\/dynamic/,
nextDynamicShim
),
...clientConfig.plugins.filter(
...(clientConfig?.plugins?.filter(
(plugin: webpack.WebpackPluginInstance) =>
// we are using @loadable instead of the build in
!(plugin instanceof ReactLoadablePlugin)
),
) || []),
new LoadablePlugin.default({
filename: `../loadable-stats.json`,
writeToDisk: true,
}),
}) as WebpackPluginInstance,
],
target: 'web',
} as Configuration,
Expand Down

0 comments on commit 4b808fc

Please sign in to comment.