Left file: appwork-v1_2_2/src/webpack.config.js  
Right file: appwork-v1_3_0/src/webpack.config.js  
1 const path = require('path') = 1 const path = require('path')
2 const glob = require('glob')   2 const glob = require('glob')
3     3  
4 // -------------------------------------------------------------------------------   4 // -------------------------------------------------------------------------------
5 // Config   5 // Config
6     6  
7 const conf = (() => {   7 const conf = (() => {
8   const _conf = require('./build-config')   8   const _conf = require('./build-config')
9   return require('deepmerge').all([{}, _conf.base || {}, _conf[process.env.NODE_ENV] || {}])   9   return require('deepmerge').all([{}, _conf.base || {}, _conf[process.env.NODE_ENV] || {}])
10 })()   10 })()
11     11  
12 conf.buildPath = path.resolve(__dirname, conf.buildPath)   12 conf.buildPath = path.resolve(__dirname, conf.buildPath)
13     13  
14 // -------------------------------------------------------------------------------   14 // -------------------------------------------------------------------------------
15 // Modules   15 // Modules
16     16  
17 const webpack = require('webpack')   17 const webpack = require('webpack')
18 const StringReplacePlugin = require('string-replace-webpack-plugin')   18 const StringReplacePlugin = require('string-replace-webpack-plugin')
19 const UglifyJsPlugin = require('uglifyjs-webpack-plugin')   19 const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
20     20  
21 // -------------------------------------------------------------------------------   21 // -------------------------------------------------------------------------------
22 // Custom template   22 // Custom template
23     23  
24 const ConcatSource = require('webpack-sources').ConcatSource   24 const ConcatSource = require('webpack-sources').ConcatSource
25     25  
26 class CustomTemplatePlugin {   26 class CustomTemplatePlugin {
27   apply(compilation) {   27   apply(compilation) {
28     const { mainTemplate, chunkTemplate } = compilation;   28     const { mainTemplate, chunkTemplate } = compilation;
29     29  
30     const onRenderWithEntry = (source, chunk, hash) => {   30     const onRenderWithEntry = (source, chunk, hash) => {
31       return new ConcatSource(`   31       return new ConcatSource(`
32 (function(r,f) {   32 (function(r,f) {
33   var a=f();   33   var a=f();
34   if(typeof a!=='object')return;   34   if(typeof a!=='object')return;
35   var e=[typeof module==='object'&&typeof module.exports==='object'?module.exports:null,typeof window!=='undefined'?window:null,r&&r!==window?r:null];   35   var e=[typeof module==='object'&&typeof module.exports==='object'?module.exports:null,typeof window!=='undefined'?window:null,r&&r!==window?r:null];
36   for(var i in a){e[0]&&(e[0][i]=a[i]);e[1]&&i!=='__esModule'&&(e[1][i] = a[i]);e[2]&&(e[2][i]=a[i]);}   36   for(var i in a){e[0]&&(e[0][i]=a[i]);e[1]&&i!=='__esModule'&&(e[1][i] = a[i]);e[2]&&(e[2][i]=a[i]);}
37 })(this,function(){   37 })(this,function(){
38   return `, source, `;   38   return `, source, `;
39 });`)   39 });`)
40     };   40     };
41     41  
42     for (const template of [mainTemplate, chunkTemplate]) {   42     for (const template of [mainTemplate, chunkTemplate]) {
43       template.hooks.renderWithEntry.tap(   43       template.hooks.renderWithEntry.tap(
44         'CustomTemplatePlugin',   44         'CustomTemplatePlugin',
45         onRenderWithEntry   45         onRenderWithEntry
46       );   46       );
47     }   47     }
48     48  
49     mainTemplate.hooks.globalHashPaths.tap("CustomTemplatePlugin", paths => {   49     mainTemplate.hooks.globalHashPaths.tap("CustomTemplatePlugin", paths => {
50       return paths;   50       return paths;
51     });   51     });
52     52  
53     mainTemplate.hooks.hash.tap("CustomTemplatePlugin", hash => {   53     mainTemplate.hooks.hash.tap("CustomTemplatePlugin", hash => {
54       hash.update('CustomTemplatePlugin');   54       hash.update('CustomTemplatePlugin');
55       hash.update('2');   55       hash.update('2');
56     });   56     });
57   }   57   }
58 }   58 }
59     59  
60 class CustomLibraryTemplatePlugin {   60 class CustomLibraryTemplatePlugin {
61   apply(compiler) {   61   apply(compiler) {
62     compiler.hooks.thisCompilation.tap('CustomLibraryTemplatePlugin', compilation => {   62     compiler.hooks.thisCompilation.tap('CustomLibraryTemplatePlugin', compilation => {
63       new CustomTemplatePlugin().apply(compilation);   63       new CustomTemplatePlugin().apply(compilation);
64     });   64     });
65   }   65   }
66 }   66 }
67     67  
68 // -------------------------------------------------------------------------------   68 // -------------------------------------------------------------------------------
69 // Build config   69 // Build config
70     70  
71 const webpackConfig = {   71 const webpackConfig = {
72   target: 'web',   72   target: 'web',
73   mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',   73   mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
74     74  
75   // Collect entries   75   // Collect entries
76   entry: (glob.sync(`!(${conf.exclude.join('|')})/**/!(_)*.@(js|es6)`) || [])   76   entry: (glob.sync(`!(${conf.exclude.join('|')})/**/!(_)*.@(js|es6)`) || [])
77     .reduce((entries, file) => {   77     .reduce((entries, file) => {
    <> 78       const filePath = file.replace(/\\/g, '/')
78       entries[file.replace(/\.(?:js|es6)$/, '')] = `./${file.replace(/\\/g, '/')}`   79       entries[filePath.replace(/\.(?:js|es6)$/, '')] = `./${filePath}`
79       return entries = 80       return entries
80     }, {}),   81     }, {}),
81     82  
82   output: {   83   output: {
83     path: conf.buildPath,   84     path: conf.buildPath,
84     filename: '[name].js'   85     filename: '[name].js'
85   },   86   },
86     87  
87   module: {   88   module: {
88     89  
89     rules: [{   90     rules: [{
90       test: /(?:\.es6|\.es6\.js)$|(?:node_modules(?:\\|\/)bootstrap(?:\\|\/)js(?:\\|\/)src(?:\\|\/)\w+\.js$)|(?:bootstrap-sweetalert(?:\/|\\)dev.+?\.js)$|(?:bootstrap-slider\.js)$|(?:popper\.js)$/, <> 91       test: /(?:\.es6|\.es6\.js)$|(?:node_modules(?:\\|\/)bootstrap(?:\\|\/)js(?:\\|\/).+?\.js$)|(?:bootstrap-sweetalert(?:\/|\\)dev.+?\.js)$|(?:bootstrap-slider\.js)$|(?:popper\.js)$|(?:bootstrap-table(?:\\|\/).+?\.js$)|(?:shepherd\.js)|(?:fullcalendar\.js)|(?:sweetalert2\.js)/,
91       use: [ = 92       use: [
92         {   93         {
93           loader: 'babel-loader',   94           loader: 'babel-loader',
94           options: {   95           options: {
95             presets: [['@babel/preset-env', {   96             presets: [['@babel/preset-env', {
96                 targets: 'last 2 versions, ie >= 10' <> 97               targets: 'last 2 versions, ie >= 10'
97             }]], = 98             }]],
98             plugins: ['@babel/plugin-transform-destructuring', '@babel/plugin-proposal-object-rest-spread', '@babel/plugin-transform-template-literals'],   99             plugins: ['@babel/plugin-transform-destructuring', '@babel/plugin-proposal-object-rest-spread', '@babel/plugin-transform-template-literals'],
99             babelrc: false   100             babelrc: false
100           }   101           }
101         }   102         }
102       ]   103       ]
103     }, {   104     }, {
104       test: /\.css$/,   105       test: /\.css$/,
105       use: [{   106       use: [{
106         loader: 'style-loader',   107         loader: 'style-loader',
107         options: {   108         options: {
108           hmr: false   109           hmr: false
109         }   110         }
110       }, {   111       }, {
111         loader: 'css-loader', <> 112         loader: 'css-loader'
112         options: {      
113           minimize: true      
114         }      
115       }] = 113       }]
116     }, {   114     }, {
117       test: /\.scss$/,   115       test: /\.scss$/,
118       use: [{   116       use: [{
119         loader: 'style-loader',   117         loader: 'style-loader',
120         options: {   118         options: {
121           hmr: false   119           hmr: false
122         }   120         }
123       }, {   121       }, {
124         loader: 'css-loader', <> 122         loader: 'css-loader'
125         options: {      
126           minimize: true      
127         }      
128       }, { = 123       }, {
129           loader: 'sass-loader'   124           loader: 'sass-loader'
130       }]   125       }]
131     }, {   126     }, {
132       test: /\.html$/,   127       test: /\.html$/,
133       use: [{   128       use: [{
134         loader: 'html-loader',   129         loader: 'html-loader',
135         options: {   130         options: {
136           minimize: true   131           minimize: true
137         }   132         }
138       }]   133       }]
139     }, { // Remove imports   134     }, { // Remove imports
140       test: /node_modules(?:\\|\/)bootstrap(?:\\|\/)js(?:\\|\/)src(?:\\|\/)\w+\.js$/,   135       test: /node_modules(?:\\|\/)bootstrap(?:\\|\/)js(?:\\|\/)src(?:\\|\/)\w+\.js$/,
141       use: {   136       use: {
142         loader: StringReplacePlugin.replace({   137         loader: StringReplacePlugin.replace({
143           replacements: [{   138           replacements: [{
144             pattern: /import.+?from\s+['"](.+?)['"];?\n/ig,   139             pattern: /import.+?from\s+['"](.+?)['"];?\n/ig,
145             replacement: (m, $1) => $1.toLowerCase() !== './tooltip' ? '' : 'import Tooltip from \'./tooltip\'\n'   140             replacement: (m, $1) => $1.toLowerCase() !== './tooltip' ? '' : 'import Tooltip from \'./tooltip\'\n'
146           }]   141           }]
147         })   142         })
148       }   143       }
149     }, { // Fix flot.resize plugin   144     }, { // Fix flot.resize plugin
150       test: /node_modules.+jquery\.flot\.resize\.js$/,   145       test: /node_modules.+jquery\.flot\.resize\.js$/,
151       use: {   146       use: {
152         loader: StringReplacePlugin.replace({   147         loader: StringReplacePlugin.replace({
153           replacements: [{   148           replacements: [{
154             pattern: /\(\s*jQuery\s*,\s*this\s*\)/ig,   149             pattern: /\(\s*jQuery\s*,\s*this\s*\)/ig,
155             replacement: () => '(jQuery,window)'   150             replacement: () => '(jQuery,window)'
156           }]   151           }]
157         })   152         })
158       }   153       }
159     }, { // Fix markdown plugin   154     }, { // Fix markdown plugin
160       test: /node_modules(?:\\|\/)markdown(?:\\|\/).+\.js$/,   155       test: /node_modules(?:\\|\/)markdown(?:\\|\/).+\.js$/,
161       use: {   156       use: {
162         loader: StringReplacePlugin.replace({   157         loader: StringReplacePlugin.replace({
163           replacements: [{   158           replacements: [{
164             pattern: /if \(typeof define !== 'function'\) \{ var define = require\('amdefine'\)\(module\) \}/ig,   159             pattern: /if \(typeof define !== 'function'\) \{ var define = require\('amdefine'\)\(module\) \}/ig,
165             replacement: () => ''   160             replacement: () => ''
166           }]   161           }]
167         })   162         })
168       }   163       }
169     }]   164     }]
170     165  
171   },   166   },
172     167  
173   plugins: [   168   plugins: [
174     new webpack.DefinePlugin({   169     new webpack.DefinePlugin({
175       'process.env': process.env.NODE_ENV   170       'process.env': process.env.NODE_ENV
176     }),   171     }),
177     new webpack.IgnorePlugin(/codemirror/),   172     new webpack.IgnorePlugin(/codemirror/),
178     new CustomLibraryTemplatePlugin()   173     new CustomLibraryTemplatePlugin()
179   ],   174   ],
180     175  
181   externals: {   176   externals: {
182     'jquery': 'window.jQuery',   177     'jquery': 'window.jQuery',
183     'moment': 'window.moment',   178     'moment': 'window.moment',
184     'datatables.net': '$.fn.dataTable',   179     'datatables.net': '$.fn.dataTable',
185     'spin.js': 'window.Spinner',   180     'spin.js': 'window.Spinner',
186     'jsdom': 'window.jsdom',   181     'jsdom': 'window.jsdom',
187     'd3': 'window.d3',   182     'd3': 'window.d3',
188     'eve': 'window.eve',   183     'eve': 'window.eve',
189     'velocity': 'window.Velocity',   184     'velocity': 'window.Velocity',
190     'hammer': 'window.Hammer',   185     'hammer': 'window.Hammer',
191     'raphael': 'window.Raphael',   186     'raphael': 'window.Raphael',
192     'jquery-mapael': 'window.Mapael',   187     'jquery-mapael': 'window.Mapael',
193     'pace': '"pace-progress"',   188     'pace': '"pace-progress"',
194     189  
195     // blueimp-file-upload plugin   190     // blueimp-file-upload plugin
196     'canvas-to-blob': 'window.blueimpDataURLtoBlob',   191     'canvas-to-blob': 'window.blueimpDataURLtoBlob',
197     'blueimp-tmpl': 'window.blueimpTmpl',   192     'blueimp-tmpl': 'window.blueimpTmpl',
198     'load-image': 'window.blueimpLoadImage',   193     'load-image': 'window.blueimpLoadImage',
199     'load-image-meta': 'null',   194     'load-image-meta': 'null',
200     'load-image-scale': 'null',   195     'load-image-scale': 'null',
201     'load-image-exif': 'null',   196     'load-image-exif': 'null',
202     'jquery-ui/ui/widget': 'null',   197     'jquery-ui/ui/widget': 'null',
203     './jquery.fileupload': 'null',   198     './jquery.fileupload': 'null',
204     './jquery.fileupload-process': 'null',   199     './jquery.fileupload-process': 'null',
205     './jquery.fileupload-image': 'null',   200     './jquery.fileupload-image': 'null',
206     './jquery.fileupload-video': 'null',   201     './jquery.fileupload-video': 'null',
207     './jquery.fileupload-validate': 'null',   202     './jquery.fileupload-validate': 'null',
208     203  
209     // blueimp-gallery plugin   204     // blueimp-gallery plugin
210     './blueimp-helper': 'window.jQuery',   205     './blueimp-helper': 'window.jQuery',
211     './blueimp-gallery': 'window.blueimpGallery',   206     './blueimp-gallery': 'window.blueimpGallery',
212     './blueimp-gallery-video': 'window.blueimpGallery'   207     './blueimp-gallery-video': 'window.blueimpGallery'
213   }   208   }
214 }   209 }
215     210  
216 // -------------------------------------------------------------------------------   211 // -------------------------------------------------------------------------------
217 // Sourcemaps   212 // Sourcemaps
218     213  
219 if (conf.sourcemaps) {   214 if (conf.sourcemaps) {
220   webpackConfig.devtool = conf.devtool   215   webpackConfig.devtool = conf.devtool
221 }   216 }
222     217  
223 // -------------------------------------------------------------------------------   218 // -------------------------------------------------------------------------------
224 // Minify   219 // Minify
225     220  
226 // Minifies sources by default in production mode   221 // Minifies sources by default in production mode
227 if (process.env.NODE_ENV !== 'production' && conf.minify) {   222 if (process.env.NODE_ENV !== 'production' && conf.minify) {
228   webpackConfig.plugins.push(   223   webpackConfig.plugins.push(
229     new UglifyJsPlugin({   224     new UglifyJsPlugin({
230       uglifyOptions: {   225       uglifyOptions: {
231         compress: {   226         compress: {
232           warnings: false   227           warnings: false
233         }   228         }
234       },   229       },
235       sourceMap: conf.sourcemaps,   230       sourceMap: conf.sourcemaps,
236       parallel: true   231       parallel: true
237     })   232     })
238   )   233   )
239 }   234 }
240     235  
241 module.exports = webpackConfig   236 module.exports = webpackConfig