@@ -21,8 +21,10 @@ module.exports = function () {
2121 let CssWatchRebuildPlugin = require ( 'engine/webpack/cssWatchRebuildPlugin' ) ;
2222 const CopyWebpackPlugin = require ( 'copy-webpack-plugin' )
2323 const MiniCssExtractPlugin = require ( "mini-css-extract-plugin" ) ;
24- const UglifyJsPlugin = require ( 'uglifyjs-webpack-plugin' ) ;
25- const OptimizeCSSAssetsPlugin = require ( "optimize-css-assets-webpack-plugin" ) ;
24+
25+ const TerserPlugin = require ( 'terser-webpack-plugin' ) ;
26+ const CssMinimizerPlugin = require ( "css-minimizer-webpack-plugin" ) ;
27+
2628 const fse = require ( 'fs-extra' ) ;
2729
2830
@@ -91,6 +93,7 @@ module.exports = function () {
9193
9294 let webpackConfig = {
9395 output : {
96+ devtoolNamespace : 'wp' ,
9497 // fs path
9598 path : path . join ( config . publicRoot , 'pack' ) ,
9699 // path as js sees it
@@ -120,8 +123,11 @@ module.exports = function () {
120123
121124 watch : devMode ,
122125
123- devtool : devMode ? "cheap-inline-module-source-map" : // try "eval" ?
124- process . env . NODE_ENV == 'production' ? 'source-map' : false ,
126+ devtool : devMode
127+ ? 'inline-cheap-module-source-map' // try "eval" ?
128+ : process . env . NODE_ENV === 'production'
129+ ? 'source-map'
130+ : false ,
125131
126132 profile : Boolean ( process . env . WEBPACK_STATS ) ,
127133
@@ -139,36 +145,52 @@ module.exports = function () {
139145 rules : [
140146 {
141147 test : / \. y m l $ / ,
142- use : [ 'json-loader' , ' yaml-loader']
148+ use : ' yaml-loader'
143149 } ,
144150 {
145- test : / \. p u g $ / ,
151+ // make t global, so that it will not be defined in the compiled template function
152+ // and i18n plugin will substitute
153+ test : / \. p u g / ,
146154 use : 'pug-loader?root=' + config . projectRoot + '/templates&globals=__'
147155 } ,
148156 {
149157 test : / \. j s $ / ,
150158 // babel shouldn't process modules which contain ws/browser.js,
151159 // which must not be run in strict mode (global becomes undefined)
152160 // babel would make all modules strict!
153- exclude : noProcessModulesRegExp ,
161+ exclude ( path ) {
162+ return noProcessModulesRegExp . test ( path ) || path . includes ( 'node_modules/monaco-editor' ) || devMode ;
163+ } ,
154164 use : [
155165 // babel will work first
156166 {
157167 loader : 'babel-loader' ,
158168 options : {
169+ plugins : [
170+ require . resolve ( '@babel/plugin-proposal-object-rest-spread' )
171+ ] ,
159172 presets : [
160- // use require.resolve here to build files from symlinks
161- [ require . resolve ( 'babel-preset-env' ) , {
173+ [ require . resolve ( '@babel/preset-env' ) , {
162174 //useBuiltIns: true,
163175 targets : {
164- browsers : "> 3%"
176+ // not ie11, don't want regenerator-runtime and @babel/plugin-transform-runtime
177+ browsers : '> 3%'
165178 }
166179 } ]
167180 ]
168181 }
169182 }
170183 ]
171184 } ,
185+ {
186+ test : / \. c s s $ / ,
187+ use : [
188+ MiniCssExtractPlugin . loader ,
189+ {
190+ loader : 'css-loader' ,
191+ } ,
192+ ] ,
193+ } ,
172194 {
173195 test : / \. s t y l $ / ,
174196 // MiniCssExtractPlugin breaks HMR for CSS
@@ -183,36 +205,43 @@ module.exports = function () {
183205 {
184206 loader : 'postcss-loader' ,
185207 options : {
186- plugins : [
187- require ( 'autoprefixer' )
188- ]
208+ postcssOptions : {
209+ plugins : [
210+ require ( 'autoprefixer' )
211+ ]
212+ }
189213 }
190214 } ,
191215 'engine/webpack/hover-loader' ,
192216 {
193217 loader : 'stylus-loader' ,
194218 options : {
195- linenos : true ,
196- 'resolve url' : true ,
197- use : [
198- rupture ( ) ,
199- nib ( ) ,
200- function ( style ) {
201- style . define ( 'lang' , config . lang ) ;
202- style . define ( 'isRTL' , [ 'ar' , 'fa' , 'he' ] . includes ( process . env . TUTORIAL_LANG ) ) ;
203- style . define ( 'env' , config . env ) ;
204- }
205- ]
219+ stylusOptions : {
220+ linenos : true ,
221+ 'resolve url' : true ,
222+ use : [
223+ rupture ( ) ,
224+ nib ( ) ,
225+ function ( style ) {
226+ style . define ( 'lang' , config . lang ) ;
227+ style . define ( 'isRTL' , [ 'ar' , 'fa' , 'he' ] . includes ( process . env . TUTORIAL_LANG ) ) ;
228+ style . define ( 'env' , config . env ) ;
229+ }
230+ ]
231+ }
206232 } ,
207233 }
208234 ]
209235 } ,
210236 {
211- test : / \. ( p n g | j p g | g i f | w o f f | e o t | o t f | t t f | s v g ) $ / ,
212- use : extHash ( 'file-loader?name=[path][name]' , '[ext]' )
237+ test : / \. ( p n g | j p g | g i f | w o f f | w o f f 2 | e o t | o t f | t t f | s v g ) $ / ,
238+ type : 'asset/resource' ,
239+ generator : {
240+ filename : extHash ( '[name]' , '[ext]' ) , // Keeps the original file name and extension
241+ } ,
213242 }
214243 ] ,
215- noParse : function ( path ) {
244+ noParse ( path ) {
216245 /*
217246 if (path.indexOf('!') != -1) {
218247 path = path.slice(path.lastIndexOf('!') + 1);
@@ -227,11 +256,16 @@ module.exports = function () {
227256 resolve : {
228257 // allow require('styles') which looks for styles/index.styl
229258 extensions : [ '.js' , '.styl' ] ,
230- alias : {
259+ alias : {
231260 'entities/maps/entities.json' : 'engine/markit/emptyEntities' ,
232- config : 'client/config'
261+ 'entities/lib/maps/entities.json' : 'engine/markit/emptyEntities' ,
262+ config : 'client/config' ,
263+ } ,
264+ fallback : {
265+ fs : false , // Replace 'empty' with 'false' in Webpack 5 to exclude it
233266 } ,
234- modules : modulesDirectories
267+ modules : modulesDirectories ,
268+ mainFields : [ 'browser' , 'main' , 'module' ] // maybe not needed, from eslint webpack
235269 } ,
236270
237271
@@ -240,21 +274,19 @@ module.exports = function () {
240274 extensions : [ '.js' ]
241275 } ,
242276
243- node : {
244- fs : 'empty'
245- } ,
246-
247277 performance : {
248278 maxEntrypointSize : 350000 ,
249279 maxAssetSize : 350000 , // warning if asset is bigger than 300k
250- assetFilter ( assetFilename ) { // only check js/css
280+ assetFilter ( assetFilename ) {
281+ // only check js/css
251282 // ignore assets copied by CopyWebpackPlugin
252- if ( assetFilename . startsWith ( '..' ) ) { // they look like ../courses/achievements/course-complete.svg
283+ if ( assetFilename . startsWith ( '..' ) ) {
284+ // they look like ../courses/achievements/course-complete.svg
253285 // built assets do not have ..
254286 return false ;
255287 }
256288 return assetFilename . endsWith ( '.js' ) || assetFilename . endsWith ( '.css' ) ;
257- }
289+ } ,
258290 } ,
259291
260292 plugins : [
@@ -268,43 +300,43 @@ module.exports = function () {
268300 _ : 'lodash'
269301 } ) ,
270302
271- // ignore all locales except current lang
303+
272304 new webpack . IgnorePlugin ( {
273- checkResource ( arg ) {
305+ resourceRegExp : / f s - e x t r a $ /
306+ } ) ,
307+
308+ // ignore all moment.js locales except current lang
309+ new webpack . IgnorePlugin ( {
310+ checkResource ( resource , context ) {
274311 // locale requires that file back from it, need to keep it
275- if ( arg === '../moment' ) return false ; // don't ignore this
276- if ( arg === './' + config . lang || arg === './' + config . lang + '.js' ) return false ; // don't ignore current locale
277- tmp = arg ; // for logging only
278- return true ;
279- } ,
280- // under dirs like: ../locales/..
281- checkContext ( arg ) {
282- let ignore = arg . endsWith ( path . join ( 'node_modules' , 'moment' , 'locale' ) ) ;
312+ if ( resource === '../moment' ) return false ; // don't ignore this
313+ if ( resource . startsWith ( './' + config . lang ) ) return false ; // don't ignore current locale ./ru ./ru.js ./zh ./zh-cn.js
314+
315+ let ignore = context . endsWith ( path . join ( 'node_modules' , 'moment' , 'locale' ) ) ;
316+
283317 if ( ignore ) {
284- // console.log("ignore moment locale ", tmp, arg );
318+ // console.log("Ignore ", resource, context );
285319 return true ;
286320 }
287- }
321+ return false ;
322+ } ,
288323 } ) ,
289324
290-
291325 // ignore site locale files except the lang
292326 new webpack . IgnorePlugin ( {
293- checkResource ( arg ) {
294- let result = arg . endsWith ( '.yml' ) && ! arg . endsWith ( '/' + config . lang + '.yml' ) ;
295- tmp = arg ; // for logging
296- return result ;
297- } ,
298- // under dirs like: ../locales/..
299- checkContext ( arg ) {
300- let ignore = / \/ l o c a l e s ( \/ | $ ) / . test ( arg ) ;
301- // console.log("ignore yml", tmp, arg);
302- return ignore ;
327+
328+ checkResource ( resource , context ) {
329+ let isYmlForAnotherLanguage = resource . endsWith ( '.yml' ) && ! resource . endsWith ( '/' + config . lang + '.yml' ) ;
330+ let isUnderLocales = / \/ l o c a l e s ( \/ | $ ) / . test ( context ) ;
331+ if ( isYmlForAnotherLanguage && isUnderLocales ) return true ;
332+
333+ // console.log("checkResource", resource, context);
334+ return false ;
303335 }
304336 } ) ,
305337
306338
307- new WriteVersionsPlugin ( path . join ( config . cacheRoot , 'webpack. versions.json' ) ) ,
339+ new WriteVersionsPlugin ( path . join ( config . buildRoot , 'webpack' , ' versions' , 'all .json') ) ,
308340
309341 new MiniCssExtractPlugin ( {
310342 filename : extHash ( "[name]" , 'css' ) ,
@@ -313,26 +345,29 @@ module.exports = function () {
313345
314346 new CssWatchRebuildPlugin ( ) ,
315347
316- new CopyWebpackPlugin (
317- assetPaths . map ( path => {
348+ new CopyWebpackPlugin ( {
349+ patterns : assetPaths . map ( ( path ) => {
318350 return {
319351 from : path ,
320- to : config . publicRoot
321- }
322- } ) ,
323- { debug : 'warning' }
324- ) ,
352+ to : config . publicRoot ,
353+ info : ( file ) => ( { minimized : true } ) ,
354+ noErrorOnMissing : true
355+ } ;
356+ } )
357+ } ) ,
325358
326359 {
327- apply : function ( compiler ) {
360+ apply ( compiler ) {
328361 if ( process . env . WEBPACK_STATS ) {
329- compiler . plugin ( " done" , function ( stats ) {
362+ compiler . hooks . done . tap ( 'MyStats' , ( stats ) => {
330363 stats = stats . toJson ( ) ;
331- fs . writeFileSync ( `${ config . tmpRoot } /stats.json` , JSON . stringify ( stats ) ) ;
364+ let dir = path . join ( config . buildRoot , 'webpack' , 'stats' ) ;
365+ fs . ensureDirSync ( dir ) ;
366+ fs . writeFileSync ( path . join ( dir , entryName + '.json' ) , JSON . stringify ( stats ) ) ;
332367 } ) ;
333368 }
334- }
335- }
369+ } ,
370+ } ,
336371 ] ,
337372
338373 recordsPath : path . join ( config . tmpRoot , 'webpack.json' ) ,
@@ -349,30 +384,30 @@ module.exports = function () {
349384
350385 optimization : {
351386 minimizer : [
352- new UglifyJsPlugin ( {
353- cache : true ,
354- parallel : 2 ,
355- uglifyOptions : {
356- ecma : 8 ,
387+ new TerserPlugin ( {
388+ parallel : 2 ,
389+ terserOptions : {
390+ ecma : 2022 ,
357391 warnings : false ,
358392 compress : {
359- drop_console : true ,
360- drop_debugger : true
393+ drop_console : true ,
394+ drop_debugger : true ,
361395 } ,
362- output : {
363- beautify : true ,
364- indent_level : 0 // for error reporting, to see which line actually has the problem
396+ output : {
397+ beautify : true ,
398+ indent_level : 0 , // for error reporting, to see which line actually has the problem
365399 // source maps actually didn't work in Qbaka that's why I put it here
366- }
367- }
400+ } ,
401+ } ,
368402 } ) ,
369- new OptimizeCSSAssetsPlugin ( { } )
370- ]
403+ new CssMinimizerPlugin ( { } ) ,
404+ ] ,
371405 }
372406 } ;
373407
374408
375409//if (process.env.NODE_ENV != 'development') { // production, ebook
410+ /*
376411 if (process.env.NODE_ENV == 'production') { // production, ebook
377412 webpackConfig.plugins.push(
378413 function clearBeforeRun() {
@@ -388,6 +423,6 @@ module.exports = function () {
388423 }
389424 );
390425 }
391-
426+ */
392427 return webpackConfig ;
393428} ;
0 commit comments