1
1
import ReactRefreshWebpackPlugin from '@next/react-refresh-utils/ReactRefreshWebpackPlugin'
2
2
import chalk from 'chalk'
3
3
import crypto from 'crypto'
4
- import { readFileSync , realpathSync } from 'fs'
4
+ import { readFileSync } from 'fs'
5
5
import { codeFrameColumns } from 'next/dist/compiled/babel/code-frame'
6
6
import semver from 'next/dist/compiled/semver'
7
7
import { isWebpack5 , webpack } from 'next/dist/compiled/webpack/webpack'
@@ -170,6 +170,35 @@ export function attachReactRefresh(
170
170
}
171
171
}
172
172
173
+ const WEBPACK_RESOLVE_OPTIONS = {
174
+ // This always uses commonjs resolving, assuming API is identical
175
+ // between ESM and CJS in a package
176
+ // Otherwise combined ESM+CJS packages will never be external
177
+ // as resolving mismatch would lead to opt-out from being external.
178
+ dependencyType : 'commonjs' ,
179
+ }
180
+
181
+ const NODE_RESOLVE_OPTIONS = {
182
+ dependencyType : 'commonjs' ,
183
+ modules : [ 'node_modules' ] ,
184
+ alias : false ,
185
+ fallback : false ,
186
+ exportsFields : [ 'exports' ] ,
187
+ importsFields : [ 'imports' ] ,
188
+ conditionNames : [ 'node' , 'require' , 'module' ] ,
189
+ descriptionFiles : [ 'package.json' ] ,
190
+ extensions : [ '.js' , '.json' , '.node' ] ,
191
+ enforceExtensions : false ,
192
+ symlinks : true ,
193
+ mainFields : [ 'main' ] ,
194
+ mainFiles : [ 'index' ] ,
195
+ roots : [ ] ,
196
+ fullySpecified : false ,
197
+ preferRelative : false ,
198
+ preferAbsolute : false ,
199
+ restrictions : [ ] ,
200
+ }
201
+
173
202
export default async function getBaseWebpackConfig (
174
203
dir : string ,
175
204
{
@@ -606,29 +635,10 @@ export default async function getBaseWebpackConfig(
606
635
async function handleExternals (
607
636
context : string ,
608
637
request : string ,
609
- getResolve : ( ) => (
610
- resolveContext : string ,
611
- resolveRequest : string
612
- ) => Promise < string >
638
+ getResolve : (
639
+ options : any
640
+ ) => ( resolveContext : string , resolveRequest : string ) => Promise < string >
613
641
) {
614
- if ( request === 'next' ) {
615
- return `commonjs ${ request } `
616
- }
617
-
618
- const notExternalModules = [
619
- 'next/app' ,
620
- 'next/document' ,
621
- 'next/link' ,
622
- 'next/image' ,
623
- 'next/error' ,
624
- 'string-hash' ,
625
- 'next/constants' ,
626
- ]
627
-
628
- if ( notExternalModules . indexOf ( request ) !== - 1 ) {
629
- return
630
- }
631
-
632
642
// We need to externalize internal requests for files intended to
633
643
// not be bundled.
634
644
@@ -640,18 +650,27 @@ export default async function getBaseWebpackConfig(
640
650
// When on Windows, we also want to check for Windows-specific
641
651
// absolute paths.
642
652
( process . platform === 'win32' && path . win32 . isAbsolute ( request ) )
643
- const isLikelyNextExternal =
644
- isLocal && / [ / \\ ] n e x t - s e r v e r [ / \\ ] / . test ( request )
645
653
646
654
// Relative requires don't need custom resolution, because they
647
655
// are relative to requests we've already resolved here.
648
656
// Absolute requires (require('/foo')) are extremely uncommon, but
649
657
// also have no need for customization as they're already resolved.
650
- if ( isLocal && ! isLikelyNextExternal ) {
651
- return
658
+ if ( isLocal ) {
659
+ if ( ! / [ / \\ ] n e x t - s e r v e r [ / \\ ] / . test ( request ) ) {
660
+ return
661
+ }
662
+ } else {
663
+ if ( / ^ (?: n e x t $ | r e a c t (?: $ | \/ ) ) / . test ( request ) ) {
664
+ return `commonjs ${ request } `
665
+ }
666
+
667
+ const notExternalModules = / ^ (?: p r i v a t e - n e x t - p a g e s \/ | n e x t \/ (?: d i s t \/ p a g e s \/ | (?: a p p | d o c u m e n t | l i n k | i m a g e | c o n s t a n t s ) $ ) | s t r i n g - h a s h $ ) /
668
+ if ( notExternalModules . test ( request ) ) {
669
+ return
670
+ }
652
671
}
653
672
654
- const resolve = getResolve ( )
673
+ const resolve = getResolve ( WEBPACK_RESOLVE_OPTIONS )
655
674
656
675
// Resolve the import with the webpack provided context, this
657
676
// ensures we're resolving the correct version when multiple
@@ -672,54 +691,59 @@ export default async function getBaseWebpackConfig(
672
691
return
673
692
}
674
693
675
- let isNextExternal : boolean = false
676
694
if ( isLocal ) {
677
695
// we need to process next-server/lib/router/router so that
678
696
// the DefinePlugin can inject process.env values
679
- isNextExternal = / n e x t [ / \\ ] d i s t [ / \\ ] n e x t - s e r v e r [ / \\ ] (? ! l i b [ / \\ ] r o u t e r [ / \\ ] r o u t e r ) / . test (
697
+ const isNextExternal = / n e x t [ / \\ ] d i s t [ / \\ ] n e x t - s e r v e r [ / \\ ] (? ! l i b [ / \\ ] r o u t e r [ / \\ ] r o u t e r ) / . test (
680
698
res
681
699
)
682
700
683
- if ( ! isNextExternal ) {
701
+ if ( isNextExternal ) {
702
+ // Generate Next.js external import
703
+ const externalRequest = path . posix . join (
704
+ 'next' ,
705
+ 'dist' ,
706
+ path
707
+ . relative (
708
+ // Root of Next.js package:
709
+ path . join ( __dirname , '..' ) ,
710
+ res
711
+ )
712
+ // Windows path normalization
713
+ . replace ( / \\ / g, '/' )
714
+ )
715
+ return `commonjs ${ externalRequest } `
716
+ } else {
684
717
return
685
718
}
686
719
}
687
720
688
- // `isNextExternal` special cases Next.js' internal requires that
689
- // should not be bundled. We need to skip the base resolve routine
690
- // to prevent it from being bundled (assumes Next.js version cannot
691
- // mismatch).
692
- if ( ! isNextExternal ) {
693
- // Bundled Node.js code is relocated without its node_modules tree.
694
- // This means we need to make sure its request resolves to the same
695
- // package that'll be available at runtime. If it's not identical,
696
- // we need to bundle the code (even if it _should_ be external).
697
- let baseRes : string | null
698
- try {
699
- baseRes = await resolve ( dir , request )
700
- } catch ( err ) {
701
- baseRes = null
702
- }
721
+ // Bundled Node.js code is relocated without its node_modules tree.
722
+ // This means we need to make sure its request resolves to the same
723
+ // package that'll be available at runtime. If it's not identical,
724
+ // we need to bundle the code (even if it _should_ be external).
725
+ let baseRes : string | null
726
+ try {
727
+ const baseResolve = getResolve ( NODE_RESOLVE_OPTIONS )
728
+ baseRes = await baseResolve ( dir , request )
729
+ } catch ( err ) {
730
+ baseRes = null
731
+ }
703
732
704
- // Same as above: if the package, when required from the root,
705
- // would be different from what the real resolution would use, we
706
- // cannot externalize it.
707
- if (
708
- ! baseRes ||
709
- ( baseRes !== res &&
710
- // if res and baseRes are symlinks they could point to the the same file
711
- realpathSync ( baseRes ) !== realpathSync ( res ) )
712
- ) {
713
- return
714
- }
733
+ // Same as above: if the package, when required from the root,
734
+ // would be different from what the real resolution would use, we
735
+ // cannot externalize it.
736
+ // if res or baseRes are symlinks they could point to the the same file,
737
+ // but the resolver will resolve symlinks so this is already handled
738
+ if ( baseRes !== res ) {
739
+ return
715
740
}
716
741
717
742
// Default pages have to be transpiled
718
743
if (
719
- ! res . match ( / n e x t [ / \\ ] d i s t [ / \\ ] n e x t - s e r v e r [ / \\ ] / ) &&
720
- ( res . match ( / [ / \\ ] n e x t [ / \\ ] d i s t [ / \\ ] / ) ||
721
- // This is the @babel /plugin-transform-runtime "helpers: true" option
722
- res . match ( / n o d e _ m o d u l e s [ / \\ ] @ b a b e l [ / \\ ] r u n t i m e [ / \\ ] / ) )
744
+ res . match ( / [ / \\ ] n e x t [ / \\ ] d i s t [ / \\ ] / ) ||
745
+ // This is the @babel /plugin-transform-runtime "helpers: true" option
746
+ res . match ( / n o d e _ m o d u l e s [ / \\ ] @ b a b e l [ / \\ ] r u n t i m e [ / \\ ] / )
723
747
) {
724
748
return
725
749
}
@@ -734,24 +758,8 @@ export default async function getBaseWebpackConfig(
734
758
735
759
// Anything else that is standard JavaScript within `node_modules`
736
760
// can be externalized.
737
- if ( isNextExternal || res . match ( / n o d e _ m o d u l e s [ / \\ ] .* \. j s $ / ) ) {
738
- const externalRequest = isNextExternal
739
- ? // Generate Next.js external import
740
- path . posix . join (
741
- 'next' ,
742
- 'dist' ,
743
- path
744
- . relative (
745
- // Root of Next.js package:
746
- path . join ( __dirname , '..' ) ,
747
- res
748
- )
749
- // Windows path normalization
750
- . replace ( / \\ / g, '/' )
751
- )
752
- : request
753
-
754
- return `commonjs ${ externalRequest } `
761
+ if ( / n o d e _ m o d u l e s [ / \\ ] .* \. c ? j s $ / . test ( res ) ) {
762
+ return `commonjs ${ request } `
755
763
}
756
764
757
765
// Default behavior: bundle the code!
@@ -775,7 +783,9 @@ export default async function getBaseWebpackConfig(
775
783
} : {
776
784
context : string
777
785
request : string
778
- getResolve : ( ) => (
786
+ getResolve : (
787
+ options : any
788
+ ) => (
779
789
resolveContext : string ,
780
790
resolveRequest : string
781
791
) => Promise < string >
0 commit comments