@@ -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,31 @@ 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+ new RegExp (
103+ `(node_modules\\/(?!chaire-lib-frontend)|${ path
104+ . join ( chaireLibFrontendRoot , 'lib' , 'styles' )
105+ . replace ( / \\ / g, '/' )
106+ . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) } |${ path
107+ . join ( transitionFrontendRoot , 'lib' , 'styles' )
108+ . replace ( / \\ / g, '/' )
109+ . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) } )`
110+ ) ,
82111 aggregateTimeout : 600
83112 } ,
84113 module : {
85114 rules : [
86115 {
87116 test : / \. t s x ? $ / ,
88117 use : 'ts-loader' ,
89- exclude : / n o d e _ m o d u l e s / ,
118+ exclude : / n o d e _ m o d u l e s /
90119 } ,
91120 {
92121 use : 'json-loader' ,
@@ -104,7 +133,7 @@ module.exports = (env) => {
104133 {
105134 test : / \. s ? c s s $ / ,
106135 use : [
107- MiniCssExtractPlugin . loader ,
136+ styleLoader , // In dev, style-loader injects CSS via <style> so SCSS changes apply after reload without a separate .css file
108137 {
109138 loader : 'css-loader' ,
110139 options : {
@@ -124,7 +153,7 @@ module.exports = (env) => {
124153 loader : '@alienfast/i18next-loader' ,
125154 options : {
126155 basenameAsNamespace : true ,
127- overrides : ( fs . existsSync ( './' + customLocalesFilePath ) ? [ '../' + customLocalesFilePath ] : [ ] )
156+ overrides : fs . existsSync ( './' + customLocalesFilePath ) ? [ '../' + customLocalesFilePath ] : [ ]
128157 }
129158 }
130159 ]
@@ -133,32 +162,38 @@ module.exports = (env) => {
133162 new CleanWebpackPlugin ( {
134163 dry : ! isProduction ,
135164 verbose : true ,
136- cleanAfterEveryBuildPatterns : [ '**/*' , '!images/**' , '!*.html' ] ,
165+ cleanAfterEveryBuildPatterns : [ '**/*' , '!images/**' , '!*.html' ]
137166 } ) ,
138167 new HtmlWebpackPlugin ( {
139168 filename : htmlFileName ,
140- template : path . join ( publicDirectory , 'index.html' ) ,
169+ template : path . join ( publicDirectory , 'index.html' )
141170 } ) ,
142171 new MiniCssExtractPlugin ( {
143172 filename : styleFileName
144173 } ) ,
145174 new webpack . DefinePlugin ( {
146175 '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 )
176+ IS_BROWSER : JSON . stringify ( true ) ,
177+ HOST : JSON . stringify ( process . env . HOST ) ,
178+ TRROUTING_HOST : JSON . stringify ( process . env . TRROUTING_HOST ) ,
179+ PROJECT_SOURCE : JSON . stringify ( process . env . PROJECT_SOURCE ) ,
180+ IS_TESTING : JSON . stringify ( process . env . NODE_ENV === 'test' ) ,
181+ GOOGLE_API_KEY : JSON . stringify ( process . env . GOOGLE_API_KEY ) ,
182+ CUSTOM_RASTER_TILES_XYZ_URL : JSON . stringify (
183+ process . env . CUSTOM_RASTER_TILES_XYZ_URL || config . customRasterTilesXyzUrl
184+ ) ,
185+ CUSTOM_RASTER_TILES_MIN_ZOOM : JSON . stringify (
186+ process . env . CUSTOM_RASTER_TILES_MIN_ZOOM || config . customRasterTilesMinZoom
187+ ) ,
188+ CUSTOM_RASTER_TILES_MAX_ZOOM : JSON . stringify (
189+ process . env . CUSTOM_RASTER_TILES_MAX_ZOOM || config . customRasterTilesMaxZoom
190+ )
156191 } ,
157- ' __CONFIG__' : JSON . stringify ( {
192+ __CONFIG__ : JSON . stringify ( {
158193 ...config
159194 } )
160195 } ) ,
161- new webpack . optimize . AggressiveMergingPlugin ( ) , //Merge chunks
196+ new webpack . optimize . AggressiveMergingPlugin ( ) , //Merge chunks
162197 new CompressionPlugin ( {
163198 filename : '[path][base].gz[query]' ,
164199 algorithm : 'gzip' ,
@@ -168,24 +203,37 @@ module.exports = (env) => {
168203 } ) ,
169204 new webpack . ContextReplacementPlugin ( / m o m e n t [ \/ \\ ] l o c a l e $ / , new RegExp ( languagesFilter ) ) ,
170205 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- )
206+ new CopyWebpackPlugin ( {
207+ patterns : [
208+ {
209+ context : path . join ( __dirname , 'lib' , 'assets' ) ,
210+ from : '**/*' ,
211+ to : '' ,
212+ noErrorOnMissing : true
213+ }
214+ ]
215+ } )
183216 ] ,
184217 resolve : {
185218 mainFields : [ 'browser' , 'main' , 'module' ] ,
186219 modules : [ 'node_modules' ] ,
187220 extensions : [ '.json' , '.js' , '.ts' , '.tsx' ] ,
188- fallback : { path : false } ,
221+ // In dev, read SCSS from chaire-lib-frontend and transition-frontend source so changes apply without running copy-files
222+ alias : isProduction
223+ ? { }
224+ : {
225+ [ path . join ( chaireLibFrontendRoot , 'lib' , 'styles' ) ] : path . join (
226+ chaireLibFrontendRoot ,
227+ 'src' ,
228+ 'styles'
229+ ) ,
230+ [ path . join ( transitionFrontendRoot , 'lib' , 'styles' ) ] : path . join (
231+ transitionFrontendRoot ,
232+ 'src' ,
233+ 'styles'
234+ )
235+ } ,
236+ fallback : { path : false }
189237 } ,
190238 devtool : isProduction ? 'cheap-source-map' : 'eval-source-map' ,
191239 devServer : {
0 commit comments