11import { extname , relative , resolve } from 'path' ;
2- import {
3- ContextExclusionPlugin ,
4- DefinePlugin ,
5- HotModuleReplacementPlugin ,
6- } from 'webpack' ;
2+ import { ContextExclusionPlugin , HotModuleReplacementPlugin } from 'webpack' ;
73import Config from 'webpack-chain' ;
84import { satisfies } from 'semver' ;
5+ import { isVersionGteConsideringPrerelease } from '../helpers/dependencies' ;
96import { existsSync } from 'fs' ;
107
118import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin' ;
129import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' ;
1310import TerserPlugin from 'terser-webpack-plugin' ;
1411
1512import { getProjectFilePath , getProjectTSConfigPath } from '../helpers/project' ;
16- import { getDependencyVersion , hasDependency } from '../helpers/dependencies' ;
13+ import {
14+ getDependencyVersion ,
15+ hasDependency ,
16+ getResolvedDependencyVersionForCheck ,
17+ } from '../helpers/dependencies' ;
1718import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin' ;
1819import { applyFileReplacements } from '../helpers/fileReplacements' ;
1920import { addCopyRule , applyCopyRules } from '../helpers/copyRules' ;
2021import { WatchStatePlugin } from '../plugins/WatchStatePlugin' ;
22+ import { CompatDefinePlugin } from '../plugins/CompatDefinePlugin' ;
2123import { applyDotEnvPlugin } from '../helpers/dotEnv' ;
2224import { env as _env , IWebpackEnv } from '../index' ;
2325import { getValue } from '../helpers/config' ;
@@ -39,6 +41,64 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
3941 // set mode
4042 config . mode ( mode ) ;
4143
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+
42102 // config.stats({
43103 // logging: 'verbose'
44104 // })
@@ -57,6 +117,28 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
57117 node : false ,
58118 } ) ;
59119
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+
60142 const getSourceMapType = ( map : string | boolean ) : Config . DevTool => {
61143 const defaultSourceMap = 'inline-source-map' ;
62144
@@ -98,6 +180,8 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
98180 // appears to be working - but we still have to deal with HMR
99181 config . target ( 'node' ) ;
100182
183+ // config.entry('globals').add('@nativescript/core/globals/index').end();
184+
101185 config
102186 . entry ( 'bundle' )
103187 // ensure we load nativescript globals first
@@ -124,16 +208,38 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
124208 . add ( '@nativescript/core/inspector_modules' ) ;
125209 } ) ;
126210
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+ } ) ;
134231
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+ }
137243 }
138244
139245 config . watchOptions ( {
@@ -175,16 +281,43 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
175281
176282 config . optimization . runtimeChunk ( 'single' ) ;
177283
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+ } ,
185294 } ,
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+ }
188321
189322 // look for loaders in
190323 // - node_modules/@nativescript/webpack/dist/loaders
@@ -407,7 +540,14 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
407540 . options ( postCSSOptions )
408541 . end ( )
409542 . 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+ } ) ;
411551
412552 // config.plugin('NormalModuleReplacementPlugin').use(NormalModuleReplacementPlugin, [
413553 // /.*/,
@@ -440,7 +580,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
440580 config
441581 . plugin ( 'ContextExclusionPlugin|Other_Platforms' )
442582 . use ( ContextExclusionPlugin , [
443- new RegExp ( `\\ .(${ otherPlatformsRE } )\\.(\ \w+)$` ) ,
583+ new RegExp ( `\.(${ otherPlatformsRE } )\.( \w+)$` ) ,
444584 ] ) ;
445585
446586 // Filter common undesirable warnings
@@ -460,30 +600,31 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
460600 ) ;
461601
462602 // 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+ ) ;
487628
488629 // enable DotEnv
489630 applyDotEnvPlugin ( config ) ;
0 commit comments