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