1
+ const { join, relative, resolve, sep, dirname } = require ( "path" ) ;
2
+
3
+ const webpack = require ( "webpack" ) ;
4
+ const nsWebpack = require ( "nativescript-dev-webpack" ) ;
5
+ const nativescriptTarget = require ( "nativescript-dev-webpack/nativescript-target" ) ;
6
+ const { nsReplaceBootstrap } = require ( "nativescript-dev-webpack/transformers/ns-replace-bootstrap" ) ;
7
+ const { nsReplaceLazyLoader } = require ( "nativescript-dev-webpack/transformers/ns-replace-lazy-loader" ) ;
8
+ const { nsSupportHmrNg } = require ( "nativescript-dev-webpack/transformers/ns-support-hmr-ng" ) ;
9
+ const { getMainModulePath } = require ( "nativescript-dev-webpack/utils/ast-utils" ) ;
10
+ const CleanWebpackPlugin = require ( "clean-webpack-plugin" ) ;
11
+ const CopyWebpackPlugin = require ( "copy-webpack-plugin" ) ;
12
+ const { BundleAnalyzerPlugin } = require ( "webpack-bundle-analyzer" ) ;
13
+ const { NativeScriptWorkerPlugin } = require ( "nativescript-worker-loader/NativeScriptWorkerPlugin" ) ;
14
+ const TerserPlugin = require ( "terser-webpack-plugin" ) ;
15
+ const { getAngularCompilerPlugin } = require ( "nativescript-dev-webpack/plugins/NativeScriptAngularCompilerPlugin" ) ;
16
+ const hashSalt = Date . now ( ) . toString ( ) ;
17
+
18
+ module . exports = env => {
19
+ // Add your custom Activities, Services and other Android app components here.
20
+ const appComponents = [
21
+ "tns-core-modules/ui/frame" ,
22
+ "tns-core-modules/ui/frame/activity" ,
23
+ resolve ( __dirname , "app/activity.android.ts" )
24
+ ] ;
25
+
26
+ const platform = env && ( env . android && "android" || env . ios && "ios" ) ;
27
+ if ( ! platform ) {
28
+ throw new Error ( "You need to provide a target platform!" ) ;
29
+ }
30
+
31
+ const AngularCompilerPlugin = getAngularCompilerPlugin ( platform ) ;
32
+ const projectRoot = __dirname ;
33
+
34
+ // Default destination inside platforms/<platform>/...
35
+ const dist = resolve ( projectRoot , nsWebpack . getAppPath ( platform , projectRoot ) ) ;
36
+
37
+ const {
38
+ // The 'appPath' and 'appResourcesPath' values are fetched from
39
+ // the nsconfig.json configuration file.
40
+ appPath = "src" ,
41
+ appResourcesPath = "App_Resources" ,
42
+
43
+ // You can provide the following flags when running 'tns run android|ios'
44
+ aot, // --env.aot
45
+ snapshot, // --env.snapshot,
46
+ production, // --env.production
47
+ uglify, // --env.uglify
48
+ report, // --env.report
49
+ sourceMap, // --env.sourceMap
50
+ hiddenSourceMap, // --env.hiddenSourceMap
51
+ hmr, // --env.hmr,
52
+ unitTesting, // --env.unitTesting
53
+ verbose, // --env.verbose
54
+ } = env ;
55
+
56
+ const isAnySourceMapEnabled = ! ! sourceMap || ! ! hiddenSourceMap ;
57
+ const externals = nsWebpack . getConvertedExternals ( env . externals ) ;
58
+ const appFullPath = resolve ( projectRoot , appPath ) ;
59
+ const appResourcesFullPath = resolve ( projectRoot , appResourcesPath ) ;
60
+ const tsConfigName = "tsconfig.tns.json" ;
61
+ const entryModule = `${ nsWebpack . getEntryModule ( appFullPath , platform ) } .ts` ;
62
+ const entryPath = `.${ sep } ${ entryModule } ` ;
63
+ const entries = { bundle : entryPath , application : "./application.android" } ;
64
+ const areCoreModulesExternal = Array . isArray ( env . externals ) && env . externals . some ( e => e . indexOf ( "tns-core-modules" ) > - 1 ) ;
65
+ if ( platform === "ios" && ! areCoreModulesExternal ) {
66
+ entries [ "tns_modules/tns-core-modules/inspector_modules" ] = "inspector_modules" ;
67
+ } ;
68
+
69
+ const ngCompilerTransformers = [ ] ;
70
+ const additionalLazyModuleResources = [ ] ;
71
+ if ( aot ) {
72
+ ngCompilerTransformers . push ( nsReplaceBootstrap ) ;
73
+ }
74
+
75
+ if ( hmr ) {
76
+ ngCompilerTransformers . push ( nsSupportHmrNg ) ;
77
+ }
78
+
79
+ // when "@angular/core" is external, it's not included in the bundles. In this way, it will be used
80
+ // directly from node_modules and the Angular modules loader won't be able to resolve the lazy routes
81
+ // fixes https://github.com/NativeScript/nativescript-cli/issues/4024
82
+ if ( env . externals && env . externals . indexOf ( "@angular/core" ) > - 1 ) {
83
+ const appModuleRelativePath = getMainModulePath ( resolve ( appFullPath , entryModule ) , tsConfigName ) ;
84
+ if ( appModuleRelativePath ) {
85
+ const appModuleFolderPath = dirname ( resolve ( appFullPath , appModuleRelativePath ) ) ;
86
+ // include the lazy loader inside app module
87
+ ngCompilerTransformers . push ( nsReplaceLazyLoader ) ;
88
+ // include the new lazy loader path in the allowed ones
89
+ additionalLazyModuleResources . push ( appModuleFolderPath ) ;
90
+ }
91
+ }
92
+
93
+ const ngCompilerPlugin = new AngularCompilerPlugin ( {
94
+ hostReplacementPaths : nsWebpack . getResolver ( [ platform , "tns" ] ) ,
95
+ platformTransformers : ngCompilerTransformers . map ( t => t ( ( ) => ngCompilerPlugin , resolve ( appFullPath , entryModule ) , projectRoot ) ) ,
96
+ mainPath : join ( appFullPath , entryModule ) ,
97
+ tsConfigPath : join ( __dirname , tsConfigName ) ,
98
+ skipCodeGeneration : ! aot ,
99
+ sourceMap : ! ! isAnySourceMapEnabled ,
100
+ additionalLazyModuleResources : additionalLazyModuleResources
101
+ } ) ;
102
+
103
+ let sourceMapFilename = nsWebpack . getSourceMapFilename ( hiddenSourceMap , __dirname , dist ) ;
104
+
105
+ const itemsToClean = [ `${ dist } /**/*` ] ;
106
+ if ( platform === "android" ) {
107
+ itemsToClean . push ( `${ join ( projectRoot , "platforms" , "android" , "app" , "src" , "main" , "assets" , "snapshots" ) } ` ) ;
108
+ itemsToClean . push ( `${ join ( projectRoot , "platforms" , "android" , "app" , "build" , "configurations" , "nativescript-android-snapshot" ) } ` ) ;
109
+ }
110
+
111
+ nsWebpack . processAppComponents ( appComponents , platform ) ;
112
+ const config = {
113
+ mode : production ? "production" : "development" ,
114
+ context : appFullPath ,
115
+ externals,
116
+ watchOptions : {
117
+ ignored : [
118
+ appResourcesFullPath ,
119
+ // Don't watch hidden files
120
+ "**/.*" ,
121
+ ]
122
+ } ,
123
+ target : nativescriptTarget ,
124
+ entry : entries ,
125
+ output : {
126
+ pathinfo : false ,
127
+ path : dist ,
128
+ sourceMapFilename,
129
+ libraryTarget : "commonjs2" ,
130
+ filename : "[name].js" ,
131
+ globalObject : "global" ,
132
+ hashSalt
133
+ } ,
134
+ resolve : {
135
+ extensions : [ ".ts" , ".js" , ".scss" , ".css" ] ,
136
+ // Resolve {N} system modules from tns-core-modules
137
+ modules : [
138
+ resolve ( __dirname , "node_modules/tns-core-modules" ) ,
139
+ resolve ( __dirname , "node_modules" ) ,
140
+ "node_modules/tns-core-modules" ,
141
+ "node_modules" ,
142
+ ] ,
143
+ alias : {
144
+ '~' : appFullPath
145
+ } ,
146
+ symlinks : true
147
+ } ,
148
+ resolveLoader : {
149
+ symlinks : false
150
+ } ,
151
+ node : {
152
+ // Disable node shims that conflict with NativeScript
153
+ "http" : false ,
154
+ "timers" : false ,
155
+ "setImmediate" : false ,
156
+ "fs" : "empty" ,
157
+ "__dirname" : false ,
158
+ } ,
159
+ devtool : hiddenSourceMap ? "hidden-source-map" : ( sourceMap ? "inline-source-map" : "none" ) ,
160
+ optimization : {
161
+ runtimeChunk : "single" ,
162
+ splitChunks : {
163
+ cacheGroups : {
164
+ vendor : {
165
+ name : "vendor" ,
166
+ chunks : "all" ,
167
+ test : ( module , chunks ) => {
168
+ const moduleName = module . nameForCondition ? module . nameForCondition ( ) : '' ;
169
+ return / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] / . test ( moduleName ) ||
170
+ appComponents . some ( comp => comp === moduleName ) ;
171
+ } ,
172
+ enforce : true ,
173
+ } ,
174
+ }
175
+ } ,
176
+ minimize : ! ! uglify ,
177
+ minimizer : [
178
+ new TerserPlugin ( {
179
+ parallel : true ,
180
+ cache : true ,
181
+ sourceMap : isAnySourceMapEnabled ,
182
+ terserOptions : {
183
+ output : {
184
+ comments : false ,
185
+ semicolons : ! isAnySourceMapEnabled
186
+ } ,
187
+ compress : {
188
+ // The Android SBG has problems parsing the output
189
+ // when these options are enabled
190
+ 'collapse_vars' : platform !== "android" ,
191
+ sequences : platform !== "android" ,
192
+ }
193
+ }
194
+ } )
195
+ ] ,
196
+ } ,
197
+ module : {
198
+ rules : [
199
+ {
200
+ include : join ( appFullPath , entryPath ) ,
201
+ use : [
202
+ // Require all Android app components
203
+ platform === "android" && {
204
+ loader : "nativescript-dev-webpack/android-app-components-loader" ,
205
+ options : { modules : appComponents }
206
+ } ,
207
+
208
+ {
209
+ loader : "nativescript-dev-webpack/bundle-config-loader" ,
210
+ options : {
211
+ angular : true ,
212
+ loadCss : ! snapshot , // load the application css if in debug mode
213
+ unitTesting,
214
+ appFullPath,
215
+ projectRoot,
216
+ ignoredFiles : nsWebpack . getUserDefinedEntries ( entries , platform )
217
+ }
218
+ } ,
219
+ ] . filter ( loader => ! ! loader )
220
+ } ,
221
+
222
+ { test : / \. h t m l $ | \. x m l $ / , use : "raw-loader" } ,
223
+
224
+ // tns-core-modules reads the app.css and its imports using css-loader
225
+ {
226
+ test : / [ \/ | \\ ] a p p \. c s s $ / ,
227
+ use : [
228
+ "nativescript-dev-webpack/style-hot-loader" ,
229
+ { loader : "css-loader" , options : { url : false } }
230
+ ]
231
+ } ,
232
+ {
233
+ test : / [ \/ | \\ ] a p p \. s c s s $ / ,
234
+ use : [
235
+ "nativescript-dev-webpack/style-hot-loader" ,
236
+ { loader : "css-loader" , options : { url : false } } ,
237
+ "sass-loader"
238
+ ]
239
+ } ,
240
+
241
+ // Angular components reference css files and their imports using raw-loader
242
+ { test : / \. c s s $ / , exclude : / [ \/ | \\ ] a p p \. c s s $ / , use : "raw-loader" } ,
243
+ { test : / \. s c s s $ / , exclude : / [ \/ | \\ ] a p p \. s c s s $ / , use : [ "raw-loader" , "resolve-url-loader" , "sass-loader" ] } ,
244
+
245
+ {
246
+ test : / (?: \. n g f a c t o r y \. j s | \. n g s t y l e \. j s | \. t s ) $ / ,
247
+ use : [
248
+ "nativescript-dev-webpack/moduleid-compat-loader" ,
249
+ "nativescript-dev-webpack/lazy-ngmodule-hot-loader" ,
250
+ "@ngtools/webpack" ,
251
+ ]
252
+ } ,
253
+
254
+ // Mark files inside `@angular/core` as using SystemJS style dynamic imports.
255
+ // Removing this will cause deprecation warnings to appear.
256
+ {
257
+ test : / [ \/ \\ ] @ a n g u l a r [ \/ \\ ] c o r e [ \/ \\ ] .+ \. j s $ / ,
258
+ parser : { system : true } ,
259
+ } ,
260
+ ] ,
261
+ } ,
262
+ plugins : [
263
+ // Define useful constants like TNS_WEBPACK
264
+ new webpack . DefinePlugin ( {
265
+ "global.TNS_WEBPACK" : "true" ,
266
+ "process" : undefined ,
267
+ } ) ,
268
+ // Remove all files from the out dir.
269
+ new CleanWebpackPlugin ( itemsToClean , { verbose : ! ! verbose } ) ,
270
+ // Copy assets to out dir. Add your own globs as needed.
271
+ new CopyWebpackPlugin ( [
272
+ { from : { glob : "fonts/**" } } ,
273
+ { from : { glob : "**/*.jpg" } } ,
274
+ { from : { glob : "**/*.png" } } ,
275
+ ] , { ignore : [ `${ relative ( appPath , appResourcesFullPath ) } /**` ] } ) ,
276
+ new nsWebpack . GenerateNativeScriptEntryPointsPlugin ( "bundle" ) ,
277
+ // For instructions on how to set up workers with webpack
278
+ // check out https://github.com/nativescript/worker-loader
279
+ new NativeScriptWorkerPlugin ( ) ,
280
+ ngCompilerPlugin ,
281
+ // Does IPC communication with the {N} CLI to notify events when running in watch mode.
282
+ new nsWebpack . WatchStateLoggerPlugin ( ) ,
283
+ ] ,
284
+ } ;
285
+
286
+ if ( report ) {
287
+ // Generate report files for bundles content
288
+ config . plugins . push ( new BundleAnalyzerPlugin ( {
289
+ analyzerMode : "static" ,
290
+ openAnalyzer : false ,
291
+ generateStatsFile : true ,
292
+ reportFilename : resolve ( projectRoot , "report" , `report.html` ) ,
293
+ statsFilename : resolve ( projectRoot , "report" , `stats.json` ) ,
294
+ } ) ) ;
295
+ }
296
+
297
+ if ( snapshot ) {
298
+ config . plugins . push ( new nsWebpack . NativeScriptSnapshotPlugin ( {
299
+ chunk : "vendor" ,
300
+ angular : true ,
301
+ requireModules : [
302
+ "reflect-metadata" ,
303
+ "@angular/platform-browser" ,
304
+ "@angular/core" ,
305
+ "@angular/common" ,
306
+ "@angular/router" ,
307
+ "nativescript-angular/platform-static" ,
308
+ "nativescript-angular/router" ,
309
+ ] ,
310
+ projectRoot,
311
+ webpackConfig : config ,
312
+ } ) ) ;
313
+ }
314
+
315
+ if ( hmr ) {
316
+ config . plugins . push ( new webpack . HotModuleReplacementPlugin ( ) ) ;
317
+ }
318
+
319
+ return config ;
320
+ } ;
0 commit comments