1
1
import { extname , relative , resolve } from 'path' ;
2
- import {
3
- ContextExclusionPlugin ,
4
- DefinePlugin ,
5
- HotModuleReplacementPlugin ,
6
- } from 'webpack' ;
2
+ import { ContextExclusionPlugin , HotModuleReplacementPlugin } from 'webpack' ;
7
3
import Config from 'webpack-chain' ;
8
4
import { satisfies } from 'semver' ;
5
+ import { isVersionGteConsideringPrerelease } from '../helpers/dependencies' ;
9
6
import { existsSync } from 'fs' ;
10
7
11
8
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin' ;
12
9
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' ;
13
10
import TerserPlugin from 'terser-webpack-plugin' ;
14
11
15
12
import { getProjectFilePath , getProjectTSConfigPath } from '../helpers/project' ;
16
- import { getDependencyVersion , hasDependency } from '../helpers/dependencies' ;
13
+ import {
14
+ getDependencyVersion ,
15
+ hasDependency ,
16
+ getResolvedDependencyVersionForCheck ,
17
+ } from '../helpers/dependencies' ;
17
18
import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin' ;
18
19
import { applyFileReplacements } from '../helpers/fileReplacements' ;
19
20
import { addCopyRule , applyCopyRules } from '../helpers/copyRules' ;
20
21
import { WatchStatePlugin } from '../plugins/WatchStatePlugin' ;
22
+ import { CompatDefinePlugin } from '../plugins/CompatDefinePlugin' ;
21
23
import { applyDotEnvPlugin } from '../helpers/dotEnv' ;
22
24
import { env as _env , IWebpackEnv } from '../index' ;
23
25
import { getValue } from '../helpers/config' ;
@@ -39,6 +41,64 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
39
41
// set mode
40
42
config . mode ( mode ) ;
41
43
44
+ // use source map files by default with v9+
45
+ function useSourceMapFiles ( ) {
46
+ if ( mode === 'development' ) {
47
+ // in development we always use source-map files with v9+ runtimes
48
+ // they are parsed and mapped to display in-flight app error screens
49
+ env . sourceMap = 'source-map' ;
50
+ }
51
+ }
52
+ // determine target output by @nativescript /* runtime version
53
+ // v9+ supports ESM output, anything below uses CommonJS
54
+ if (
55
+ hasDependency ( '@nativescript/ios' ) ||
56
+ hasDependency ( '@nativescript/visionos' ) ||
57
+ hasDependency ( '@nativescript/android' )
58
+ ) {
59
+ const iosVersion = getDependencyVersion ( '@nativescript/ios' ) ;
60
+ const visionosVersion = getDependencyVersion ( '@nativescript/visionos' ) ;
61
+ const androidVersion = getDependencyVersion ( '@nativescript/android' ) ;
62
+
63
+ if ( platform === 'ios' ) {
64
+ const iosResolved =
65
+ getResolvedDependencyVersionForCheck ( '@nativescript/ios' , '9.0.0' ) ??
66
+ iosVersion ??
67
+ undefined ;
68
+ if ( isVersionGteConsideringPrerelease ( iosResolved , '9.0.0' ) ) {
69
+ useSourceMapFiles ( ) ;
70
+ } else {
71
+ env . commonjs = true ;
72
+ }
73
+ } else if ( platform === 'visionos' ) {
74
+ const visionosResolved =
75
+ getResolvedDependencyVersionForCheck (
76
+ '@nativescript/visionos' ,
77
+ '9.0.0' ,
78
+ ) ??
79
+ visionosVersion ??
80
+ undefined ;
81
+ if ( isVersionGteConsideringPrerelease ( visionosResolved , '9.0.0' ) ) {
82
+ useSourceMapFiles ( ) ;
83
+ } else {
84
+ env . commonjs = true ;
85
+ }
86
+ } else if ( platform === 'android' ) {
87
+ const androidResolved =
88
+ getResolvedDependencyVersionForCheck (
89
+ '@nativescript/android' ,
90
+ '9.0.0' ,
91
+ ) ??
92
+ androidVersion ??
93
+ undefined ;
94
+ if ( isVersionGteConsideringPrerelease ( androidResolved , '9.0.0' ) ) {
95
+ useSourceMapFiles ( ) ;
96
+ } else {
97
+ env . commonjs = true ;
98
+ }
99
+ }
100
+ }
101
+
42
102
// config.stats({
43
103
// logging: 'verbose'
44
104
// })
@@ -57,6 +117,28 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
57
117
node : false ,
58
118
} ) ;
59
119
120
+ // Mock Node.js built-ins that are not available in NativeScript runtime
121
+ // but are required by some packages like css-tree
122
+ config . resolve . merge ( {
123
+ fallback : {
124
+ module : require . resolve ( '../polyfills/module.js' ) ,
125
+ } ,
126
+ alias : {
127
+ // Mock mdn-data modules that css-tree tries to load
128
+ 'mdn-data/css/properties.json' : require . resolve (
129
+ '../polyfills/mdn-data-properties.js' ,
130
+ ) ,
131
+ 'mdn-data/css/syntaxes.json' : require . resolve (
132
+ '../polyfills/mdn-data-syntaxes.js' ,
133
+ ) ,
134
+ 'mdn-data/css/at-rules.json' : require . resolve (
135
+ '../polyfills/mdn-data-at-rules.js' ,
136
+ ) ,
137
+ // Ensure imports of the Node 'module' builtin resolve to our polyfill
138
+ module : require . resolve ( '../polyfills/module.js' ) ,
139
+ } ,
140
+ } ) ;
141
+
60
142
const getSourceMapType = ( map : string | boolean ) : Config . DevTool => {
61
143
const defaultSourceMap = 'inline-source-map' ;
62
144
@@ -98,6 +180,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
98
180
// appears to be working - but we still have to deal with HMR
99
181
config . target ( 'node' ) ;
100
182
183
+ // config.entry('globals').add('@nativescript/core/globals/index').end();
184
+
101
185
config
102
186
. entry ( 'bundle' )
103
187
// ensure we load nativescript globals first
@@ -124,16 +208,38 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
124
208
. add ( '@nativescript/core/inspector_modules' ) ;
125
209
} ) ;
126
210
127
- config . output
128
- . path ( outputPath )
129
- . pathinfo ( false )
130
- . publicPath ( '' )
131
- . libraryTarget ( 'commonjs' )
132
- . globalObject ( 'global' )
133
- . set ( 'clean' , true ) ;
211
+ if ( env . commonjs ) {
212
+ // CommonJS output
213
+ config . output
214
+ . path ( outputPath )
215
+ . pathinfo ( false )
216
+ . publicPath ( '' )
217
+ . libraryTarget ( 'commonjs' )
218
+ . globalObject ( 'global' )
219
+ . set ( 'clean' , true ) ;
220
+ if ( env === null || env === void 0 ? void 0 : env . uniqueBundle ) {
221
+ config . output . filename ( `[name].${ env . uniqueBundle } .js` ) ;
222
+ }
223
+ } else {
224
+ // ESM output
225
+ config . merge ( {
226
+ experiments : {
227
+ // enable ES module syntax (import/exports)
228
+ outputModule : true ,
229
+ } ,
230
+ } ) ;
134
231
135
- if ( env ?. uniqueBundle ) {
136
- config . output . filename ( `[name].${ env . uniqueBundle } .js` ) ;
232
+ config . output
233
+ . path ( outputPath )
234
+ . pathinfo ( false )
235
+ . publicPath ( 'file:///app/' )
236
+ . set ( 'module' , true )
237
+ . libraryTarget ( 'module' )
238
+ . globalObject ( 'global' )
239
+ . set ( 'clean' , true ) ;
240
+ if ( env === null || env === void 0 ? void 0 : env . uniqueBundle ) {
241
+ config . output . filename ( `[name].${ env . uniqueBundle } .mjs` ) ;
242
+ }
137
243
}
138
244
139
245
config . watchOptions ( {
@@ -175,16 +281,43 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
175
281
176
282
config . optimization . runtimeChunk ( 'single' ) ;
177
283
178
- config . optimization . splitChunks ( {
179
- cacheGroups : {
180
- defaultVendor : {
181
- test : / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] / ,
182
- priority : - 10 ,
183
- name : 'vendor' ,
184
- chunks : 'all' ,
284
+ if ( env . commonjs ) {
285
+ // Set up CommonJS output
286
+ config . optimization . splitChunks ( {
287
+ cacheGroups : {
288
+ defaultVendor : {
289
+ test : / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] / ,
290
+ priority : - 10 ,
291
+ name : 'vendor' ,
292
+ chunks : 'all' ,
293
+ } ,
185
294
} ,
186
- } ,
187
- } ) ;
295
+ } ) ;
296
+ } else {
297
+ // Set up ESM output
298
+ config . output . chunkFilename ( '[name].mjs' ) ;
299
+
300
+ // now re‑add exactly what you want:
301
+ config . optimization . splitChunks ( {
302
+ // only split out vendor from the main bundle…
303
+ chunks : 'initial' ,
304
+ cacheGroups : {
305
+ // no “default” group
306
+ default : false ,
307
+
308
+ // only pull node_modules into vendor.js from the *initial* chunk
309
+ vendor : {
310
+ test : / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] / ,
311
+ name : 'vendor' ,
312
+ chunks : 'initial' ,
313
+ priority : - 10 ,
314
+ reuseExistingChunk : true ,
315
+ } ,
316
+ } ,
317
+ } ) ;
318
+
319
+ config . optimization . set ( 'moduleIds' , 'named' ) . set ( 'chunkIds' , 'named' ) ;
320
+ }
188
321
189
322
// look for loaders in
190
323
// - node_modules/@nativescript/webpack/dist/loaders
@@ -407,7 +540,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
407
540
. options ( postCSSOptions )
408
541
. end ( )
409
542
. use ( 'sass-loader' )
410
- . loader ( 'sass-loader' ) ;
543
+ . loader ( 'sass-loader' )
544
+ . options ( {
545
+ // helps ensure proper project compatibility
546
+ // particularly in cases of workspaces
547
+ // which may have different nested Sass implementations
548
+ // via transient dependencies
549
+ implementation : require ( 'sass' ) ,
550
+ } ) ;
411
551
412
552
// config.plugin('NormalModuleReplacementPlugin').use(NormalModuleReplacementPlugin, [
413
553
// /.*/,
@@ -440,7 +580,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
440
580
config
441
581
. plugin ( 'ContextExclusionPlugin|Other_Platforms' )
442
582
. use ( ContextExclusionPlugin , [
443
- new RegExp ( `\\ .(${ otherPlatformsRE } )\\.(\ \w+)$` ) ,
583
+ new RegExp ( `\.(${ otherPlatformsRE } )\.( \w+)$` ) ,
444
584
] ) ;
445
585
446
586
// Filter common undesirable warnings
@@ -460,30 +600,31 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
460
600
) ;
461
601
462
602
// todo: refine defaults
463
- config . plugin ( 'DefinePlugin' ) . use ( DefinePlugin , [
464
- {
465
- __DEV__ : mode === 'development' ,
466
- __NS_WEBPACK__ : true ,
467
- __NS_ENV_VERBOSE__ : ! ! env . verbose ,
468
- __NS_DEV_HOST_IPS__ :
469
- mode === 'development' ? JSON . stringify ( getIPS ( ) ) : `[]` ,
470
- __CSS_PARSER__ : JSON . stringify ( getValue ( 'cssParser' , 'css-tree' ) ) ,
471
- __UI_USE_XML_PARSER__ : true ,
472
- __UI_USE_EXTERNAL_RENDERER__ : false ,
473
- __ANDROID__ : platform === 'android' ,
474
- __IOS__ : platform === 'ios' ,
475
- __VISIONOS__ : platform === 'visionos' ,
476
- __APPLE__ : platform === 'ios' || platform === 'visionos' ,
477
- /* for compat only */ 'global.isAndroid' : platform === 'android' ,
478
- /* for compat only */ 'global.isIOS' :
479
- platform === 'ios' || platform === 'visionos' ,
480
- /* for compat only */ 'global.isVisionOS' : platform === 'visionos' ,
481
- process : 'global.process' ,
482
-
483
- // todo: ?!?!
484
- // profile: '() => {}',
485
- } ,
486
- ] ) ;
603
+ config . plugin ( 'DefinePlugin' ) . use (
604
+ CompatDefinePlugin as any ,
605
+ [
606
+ {
607
+ __DEV__ : mode === 'development' ,
608
+ __NS_WEBPACK__ : true ,
609
+ __NS_ENV_VERBOSE__ : ! ! env . verbose ,
610
+ __NS_DEV_HOST_IPS__ :
611
+ mode === 'development' ? JSON . stringify ( getIPS ( ) ) : `[]` ,
612
+ __CSS_PARSER__ : JSON . stringify ( getValue ( 'cssParser' , 'css-tree' ) ) ,
613
+ __UI_USE_XML_PARSER__ : true ,
614
+ __UI_USE_EXTERNAL_RENDERER__ : false ,
615
+ __COMMONJS__ : ! ! env . commonjs ,
616
+ __ANDROID__ : platform === 'android' ,
617
+ __IOS__ : platform === 'ios' ,
618
+ __VISIONOS__ : platform === 'visionos' ,
619
+ __APPLE__ : platform === 'ios' || platform === 'visionos' ,
620
+ /* for compat only */ 'global.isAndroid' : platform === 'android' ,
621
+ /* for compat only */ 'global.isIOS' :
622
+ platform === 'ios' || platform === 'visionos' ,
623
+ /* for compat only */ 'global.isVisionOS' : platform === 'visionos' ,
624
+ process : 'global.process' ,
625
+ } ,
626
+ ] as any ,
627
+ ) ;
487
628
488
629
// enable DotEnv
489
630
applyDotEnvPlugin ( config ) ;
0 commit comments