@@ -25,7 +25,9 @@ const configuration = require('chaire-lib-backend/lib/config/server.config');
2525// Extract from the config all options that we should not send to the frontend.
2626// The `{ ...config }` will be sent to the frontend
2727// TODO This won't be necessary once we have frontend and backend configuration separated
28- const { trRoutingCacheAllScenarios, routing, ...config } = configuration . default ? configuration . default : configuration ;
28+ const { trRoutingCacheAllScenarios, routing, ...config } = configuration . default
29+ ? configuration . default
30+ : configuration ;
2931
3032// Public directory from which files are served
3133const publicDirectory = path . join ( __dirname , '..' , '..' , 'public' ) ;
@@ -41,18 +43,29 @@ module.exports = (env) => {
4143 const isProduction = process . env . NODE_ENV === 'production' ;
4244
4345 // Make sure all builds have different names if not a production bundle
44- const bundleFileName = isProduction ? `transition-${ config . projectShortname } -bundle-${ process . env . NODE_ENV } .[contenthash].js` : `transition-${ config . projectShortname } -bundle-${ process . env . NODE_ENV } .dev.js` ;
45- const styleFileName = isProduction ? `transition-${ config . projectShortname } -styles.[contenthash].css` : `transition-${ config . projectShortname } -styles.dev.css` ;
46+ const bundleFileName = isProduction
47+ ? `transition-${ config . projectShortname } -bundle-${ process . env . NODE_ENV } .[contenthash].js`
48+ : `transition-${ config . projectShortname } -bundle-${ process . env . NODE_ENV } .dev.js` ;
49+ const styleFileName = isProduction
50+ ? `transition-${ config . projectShortname } -styles.[contenthash].css`
51+ : `transition-${ config . projectShortname } -styles.dev.css` ;
4652 // HTML main file name
4753 const htmlFileName = path . join ( `index-${ config . projectShortname } .html` ) ;
4854
55+ // In dev, style-loader injects CSS via <style> so SCSS changes apply after reload without a separate .css file
56+ const styleLoader = isProduction ? MiniCssExtractPlugin . loader : 'style-loader' ;
57+ const chaireLibFrontendRoot = path . dirname ( require . resolve ( 'chaire-lib-frontend/package.json' ) ) ;
58+ const transitionFrontendRoot = __dirname ;
59+
4960 const languages = config . languages || [ 'fr' , 'en' ] ;
5061 const languagesFilter = `/${ languages . join ( '|' ) } /` ;
5162
5263 // TODO Custom styles and locales should be set in config (#419, #420)
5364 const customStylesFilePath = `${ config . projectDir } /styles/styles.scss` ;
5465 const customLocalesFilePath = `${ config . projectDir } /locales` ;
55- const entry = fs . existsSync ( './' + customStylesFilePath ) ? [ entryFileName , './' + customStylesFilePath ] : [ entryFileName ] ;
66+ const entry = fs . existsSync ( './' + customStylesFilePath )
67+ ? [ entryFileName , './' + customStylesFilePath ]
68+ : [ entryFileName ] ;
5669 const includeDirectories = [
5770 path . join ( __dirname , 'lib' ) ,
5871
@@ -64,7 +77,7 @@ module.exports = (env) => {
6477 // Controls which information to display (see https://webpack.js.org/configuration/stats/)
6578 stats : {
6679 errorDetails : true ,
67- children : true ,
80+ children : true
6881 } ,
6982 node : {
7083 // global will be deprecated at next major release, see where it is being used
@@ -78,15 +91,34 @@ module.exports = (env) => {
7891 publicPath : '/dist/'
7992 } ,
8093 watchOptions : {
81- ignored : [ 'node_modules/**' ] ,
94+ // In dev, watch chaire-lib-frontend so CSS/TS changes trigger rebuild
95+ // Exclude lib/styles from chaire-lib-frontend and transition-frontend since we use alias to point to src/styles
96+ ignored : isProduction
97+ ? // In production, ignore all node_modules to avoid rebuilding the whole project
98+ new RegExp ( 'node_modules/' )
99+ : /* Ignore all node_modules except chaire-lib-frontend,
100+ and also specifically ignore the lib/styles directory of chaire-lib-frontend and transition-frontend
101+ (which we override via an alias to src/styles).
102+ Paths are normalized and escaped: .replace(/\\/g,'/') for forward slashes and
103+ .replace(/[.*+?^${}()|[\]\\]/g,'\\$&') escapes regex metacharacters (. * + ? ^ $ { } ( ) | [ ] \)
104+ so the path is matched literally (e.g. paths with parentheses like "Program Files (x86)"). */
105+ new RegExp (
106+ `(node_modules\\/(?!chaire-lib-frontend)|${ path
107+ . join ( chaireLibFrontendRoot , 'lib' , 'styles' )
108+ . replace ( / \\ / g, '/' )
109+ . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) } |${ path
110+ . join ( transitionFrontendRoot , 'lib' , 'styles' )
111+ . replace ( / \\ / g, '/' )
112+ . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) } )`
113+ ) ,
82114 aggregateTimeout : 600
83115 } ,
84116 module : {
85117 rules : [
86118 {
87119 test : / \. t s x ? $ / ,
88120 use : 'ts-loader' ,
89- exclude : / n o d e _ m o d u l e s / ,
121+ exclude : / n o d e _ m o d u l e s /
90122 } ,
91123 {
92124 use : 'json-loader' ,
@@ -104,7 +136,7 @@ module.exports = (env) => {
104136 {
105137 test : / \. s ? c s s $ / ,
106138 use : [
107- MiniCssExtractPlugin . loader ,
139+ styleLoader , // In dev, style-loader injects CSS via <style> so SCSS changes apply after reload without a separate .css file
108140 {
109141 loader : 'css-loader' ,
110142 options : {
@@ -124,7 +156,7 @@ module.exports = (env) => {
124156 loader : '@alienfast/i18next-loader' ,
125157 options : {
126158 basenameAsNamespace : true ,
127- overrides : ( fs . existsSync ( './' + customLocalesFilePath ) ? [ '../' + customLocalesFilePath ] : [ ] )
159+ overrides : fs . existsSync ( './' + customLocalesFilePath ) ? [ '../' + customLocalesFilePath ] : [ ]
128160 }
129161 }
130162 ]
@@ -133,32 +165,38 @@ module.exports = (env) => {
133165 new CleanWebpackPlugin ( {
134166 dry : ! isProduction ,
135167 verbose : true ,
136- cleanAfterEveryBuildPatterns : [ '**/*' , '!images/**' , '!*.html' ] ,
168+ cleanAfterEveryBuildPatterns : [ '**/*' , '!images/**' , '!*.html' ]
137169 } ) ,
138170 new HtmlWebpackPlugin ( {
139171 filename : htmlFileName ,
140- template : path . join ( publicDirectory , 'index.html' ) ,
172+ template : path . join ( publicDirectory , 'index.html' )
141173 } ) ,
142174 new MiniCssExtractPlugin ( {
143175 filename : styleFileName
144176 } ) ,
145177 new webpack . DefinePlugin ( {
146178 'process.env' : {
147- 'IS_BROWSER' : JSON . stringify ( true ) ,
148- 'HOST' : JSON . stringify ( process . env . HOST ) ,
149- 'TRROUTING_HOST' : JSON . stringify ( process . env . TRROUTING_HOST ) ,
150- 'PROJECT_SOURCE' : JSON . stringify ( process . env . PROJECT_SOURCE ) ,
151- 'IS_TESTING' : JSON . stringify ( process . env . NODE_ENV === 'test' ) ,
152- 'GOOGLE_API_KEY' : JSON . stringify ( process . env . GOOGLE_API_KEY ) ,
153- 'CUSTOM_RASTER_TILES_XYZ_URL' : JSON . stringify ( process . env . CUSTOM_RASTER_TILES_XYZ_URL || config . customRasterTilesXyzUrl ) ,
154- 'CUSTOM_RASTER_TILES_MIN_ZOOM' : JSON . stringify ( process . env . CUSTOM_RASTER_TILES_MIN_ZOOM || config . customRasterTilesMinZoom ) ,
155- 'CUSTOM_RASTER_TILES_MAX_ZOOM' : JSON . stringify ( process . env . CUSTOM_RASTER_TILES_MAX_ZOOM || config . customRasterTilesMaxZoom )
179+ IS_BROWSER : JSON . stringify ( true ) ,
180+ HOST : JSON . stringify ( process . env . HOST ) ,
181+ TRROUTING_HOST : JSON . stringify ( process . env . TRROUTING_HOST ) ,
182+ PROJECT_SOURCE : JSON . stringify ( process . env . PROJECT_SOURCE ) ,
183+ IS_TESTING : JSON . stringify ( process . env . NODE_ENV === 'test' ) ,
184+ GOOGLE_API_KEY : JSON . stringify ( process . env . GOOGLE_API_KEY ) ,
185+ CUSTOM_RASTER_TILES_XYZ_URL : JSON . stringify (
186+ process . env . CUSTOM_RASTER_TILES_XYZ_URL || config . customRasterTilesXyzUrl
187+ ) ,
188+ CUSTOM_RASTER_TILES_MIN_ZOOM : JSON . stringify (
189+ process . env . CUSTOM_RASTER_TILES_MIN_ZOOM || config . customRasterTilesMinZoom
190+ ) ,
191+ CUSTOM_RASTER_TILES_MAX_ZOOM : JSON . stringify (
192+ process . env . CUSTOM_RASTER_TILES_MAX_ZOOM || config . customRasterTilesMaxZoom
193+ )
156194 } ,
157- ' __CONFIG__' : JSON . stringify ( {
195+ __CONFIG__ : JSON . stringify ( {
158196 ...config
159197 } )
160198 } ) ,
161- new webpack . optimize . AggressiveMergingPlugin ( ) , //Merge chunks
199+ new webpack . optimize . AggressiveMergingPlugin ( ) , //Merge chunks
162200 new CompressionPlugin ( {
163201 filename : '[path][base].gz[query]' ,
164202 algorithm : 'gzip' ,
@@ -168,24 +206,37 @@ module.exports = (env) => {
168206 } ) ,
169207 new webpack . ContextReplacementPlugin ( / m o m e n t [ \/ \\ ] l o c a l e $ / , new RegExp ( languagesFilter ) ) ,
170208 new webpack . ContextReplacementPlugin ( / d a t e \- f n s [ \/ \\ ] / , new RegExp ( languagesFilter ) ) ,
171- new CopyWebpackPlugin (
172- {
173- patterns : [
174- {
175- context : path . join ( __dirname , 'lib' , 'assets' ) ,
176- from : '**/*' ,
177- to : '' ,
178- noErrorOnMissing : true
179- }
180- ]
181- }
182- )
209+ new CopyWebpackPlugin ( {
210+ patterns : [
211+ {
212+ context : path . join ( __dirname , 'lib' , 'assets' ) ,
213+ from : '**/*' ,
214+ to : '' ,
215+ noErrorOnMissing : true
216+ }
217+ ]
218+ } )
183219 ] ,
184220 resolve : {
185221 mainFields : [ 'browser' , 'main' , 'module' ] ,
186222 modules : [ 'node_modules' ] ,
187223 extensions : [ '.json' , '.js' , '.ts' , '.tsx' ] ,
188- fallback : { path : false } ,
224+ // In dev, read SCSS from chaire-lib-frontend and transition-frontend source so changes apply without running copy-files
225+ alias : isProduction
226+ ? { }
227+ : {
228+ [ path . join ( chaireLibFrontendRoot , 'lib' , 'styles' ) ] : path . join (
229+ chaireLibFrontendRoot ,
230+ 'src' ,
231+ 'styles'
232+ ) ,
233+ [ path . join ( transitionFrontendRoot , 'lib' , 'styles' ) ] : path . join (
234+ transitionFrontendRoot ,
235+ 'src' ,
236+ 'styles'
237+ )
238+ } ,
239+ fallback : { path : false }
189240 } ,
190241 devtool : isProduction ? 'cheap-source-map' : 'eval-source-map' ,
191242 devServer : {
0 commit comments