Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 39509
1
# CoCalc, by SageMath, Inc., (c) 2016, 2017 -- License: AGPLv3
2
3
###
4
# Webpack configuration file
5
6
Run dev server with source maps:
7
8
npm run webpack-watch
9
10
Then visit (say)
11
12
https://dev0.sagemath.com/
13
14
or for smc-in-smc project, info.py URL, e.g.
15
16
https://cloud.sagemath.com/14eed217-2d3c-4975-a381-b69edcb40e0e/port/56754/
17
18
This is far from ready to use yet, e.g., we need to properly serve primus websockets, etc.:
19
20
webpack-dev-server --port=9000 -d
21
22
Resources for learning webpack:
23
24
- https://github.com/petehunt/webpack-howto
25
- http://webpack.github.io/docs/tutorials/getting-started/
26
27
---
28
29
## Information for developers
30
31
This webpack config file might look scary, but it only consists of a few moving parts.
32
33
1. There is the "main" SMC application, which is split into "css", "lib" and "smc":
34
1. css: a collection of all static styles from various locations. It might be possible
35
to use the text extraction plugin to make this a .css file, but that didn't work out.
36
Some css is inserted, but it doesn't work and no styles are applied. In the end,
37
it doesn't matter to load it one way or the other. Furthermore, as .js is even better,
38
because the initial page load is instant and doesn't require to get the compiled css styles.
39
2. lib: this is a compilation of the essential js files in webapp-lib (via webapp-lib.coffee)
40
3. smc: the core smc library. besides this, there are also chunks ([number]-hash.js) that are
41
loaded later on demand (read up on `require.ensure`).
42
For example, such a chunkfile contains latex completions, the data for the wizard, etc.
43
2. There are static html files for the policies.
44
The policy files originate in webapp-lib/policies, where at least one file is generated by update_react_static.
45
That script runs part of the smc application in node.js to render to html.
46
Then, that html output is included into the html page and compiled.
47
It's not possible to automate this fully, because during the processing of these templates,
48
the "css" chunk from point 1.1 above is injected, too.
49
In the future, also other elements from the website (e.g. <Footer/>) will be rendered as
50
separate static html template elements and included there.
51
3. There are auxiliary files for the "video chat" functionality. That might be redone differently, but
52
for now rendering to html only works via the html webpack plugin in such a way,
53
that it rewrites paths and post processes the files correctly to work.
54
55
The remaining configuration deals with setting up variables (misc_node contains the centralized
56
information about where the page is getting rendered to, because also the hub.coffee needs to know
57
about certain file locations)
58
59
Development vs. Production: There are two variables DEVMODE and PRODMODE.
60
* Prodmode:
61
* additional compression is enabled (do *not* add the -p switch to webpack, that's done here explicitly!)
62
* all output filenames, except for the essential .html files, do have hashes and a rather flat hierarchy.
63
* Devmode:
64
* Apply as little additional plugins as possible (compiles faster).
65
* File names have no hashes, or hashes are deterministically based on the content.
66
This means, when running webpack-watch, you do not end up with a growing pile of
67
thousands of files in the output directory.
68
69
MathJax: It lives in its own isolated world. This means, don't mess with the MathJax.js ...
70
It needs to know from where it is loaded (the path in the URL), to retrieve many additional files on demand.
71
That's also the main reason why it is slow, because for each file a new SSL connection has to be setup!
72
(unless, http/2 or spdy do https pipelining).
73
How do we help MathJax a little bit by caching it, when the file names aren't hashed?
74
The trick is to add the MathJax version number to the path, such that it is unique and will definitely
75
trigger a reload after an update of MathJax.
76
The MathjaxVersionedSymlink below (in combination with misc_node.MATHJAX_LIB)
77
does extract the MathJax version number, computes the path, and symlinks to its location.
78
Why in misc_node? The problem is, that also the jupyter server (in its isolated iframe),
79
needs to know about the MathJax URL.
80
That way, the hub can send down the URL to the jupyter server (there is no webapp client in between).
81
###
82
83
'use strict'
84
85
_ = require('lodash')
86
webpack = require('webpack')
87
path = require('path')
88
fs = require('fs')
89
glob = require('glob')
90
child_process = require('child_process')
91
misc = require('smc-util/misc')
92
misc_node = require('smc-util-node/misc_node')
93
async = require('async')
94
program = require('commander')
95
96
SMC_VERSION = require('smc-util/smc-version').version
97
theme = require('smc-util/theme')
98
99
git_head = child_process.execSync("git rev-parse HEAD")
100
GIT_REV = git_head.toString().trim()
101
TITLE = theme.SITE_NAME
102
DESCRIPTION = theme.APP_TAGLINE
103
SMC_REPO = 'https://github.com/sagemathinc/cocalc'
104
SMC_LICENSE = 'AGPLv3'
105
WEBAPP_LIB = misc_node.WEBAPP_LIB
106
INPUT = path.resolve(__dirname, WEBAPP_LIB)
107
OUTPUT = misc_node.OUTPUT_DIR
108
DEVEL = "development"
109
NODE_ENV = process.env.NODE_ENV || DEVEL
110
PRODMODE = NODE_ENV != DEVEL
111
CDN_BASE_URL = process.env.CDN_BASE_URL # CDN_BASE_URL must have a trailing slash
112
DEVMODE = not PRODMODE
113
MINIFY = !! process.env.WP_MINIFY
114
DEBUG = '--debug' in process.argv
115
SOURCE_MAP = !! process.env.SOURCE_MAP
116
STATICPAGES = !! process.env.CC_STATICPAGES # special mode where just the landing page is built
117
date = new Date()
118
BUILD_DATE = date.toISOString()
119
BUILD_TS = date.getTime()
120
GOOGLE_ANALYTICS = misc_node.GOOGLE_ANALYTICS
121
122
# create a file base_url to set a base url
123
BASE_URL = misc_node.BASE_URL
124
125
# check and sanitiziation (e.g. an exising but empty env variable is ignored)
126
# CDN_BASE_URL must have a trailing slash
127
if not CDN_BASE_URL? or CDN_BASE_URL.length == 0
128
CDN_BASE_URL = null
129
else
130
if CDN_BASE_URL[-1..] isnt '/'
131
throw new Error("CDN_BASE_URL must be an URL-string ending in a '/' -- but it is #{CDN_BASE_URL}")
132
133
# output build environment variables of webpack
134
console.log "SMC_VERSION = #{SMC_VERSION}"
135
console.log "SMC_GIT_REV = #{GIT_REV}"
136
console.log "NODE_ENV = #{NODE_ENV}"
137
console.log "BASE_URL = #{BASE_URL}"
138
console.log "CDN_BASE_URL = #{CDN_BASE_URL}"
139
console.log "DEBUG = #{DEBUG}"
140
console.log "MINIFY = #{MINIFY}"
141
console.log "INPUT = #{INPUT}"
142
console.log "OUTPUT = #{OUTPUT}"
143
console.log "GOOGLE_ANALYTICS = #{GOOGLE_ANALYTICS}"
144
145
# mathjax version → symlink with version info from package.json/version
146
if CDN_BASE_URL?
147
# the CDN url does not have the /static/... prefix!
148
MATHJAX_URL = CDN_BASE_URL + path.join(misc_node.MATHJAX_SUBDIR, 'MathJax.js')
149
else
150
MATHJAX_URL = misc_node.MATHJAX_URL # from where the files are served
151
MATHJAX_ROOT = misc_node.MATHJAX_ROOT # where the symlink originates
152
MATHJAX_LIB = misc_node.MATHJAX_LIB # where the symlink points to
153
console.log "MATHJAX_URL = #{MATHJAX_URL}"
154
console.log "MATHJAX_ROOT = #{MATHJAX_ROOT}"
155
console.log "MATHJAX_LIB = #{MATHJAX_LIB}"
156
157
# adds a banner to each compiled and minified source .js file
158
banner = new webpack.BannerPlugin(
159
"""\
160
This file is part of #{TITLE}.
161
It was compiled #{BUILD_DATE} at revision #{GIT_REV} and version #{SMC_VERSION}.
162
See #{SMC_REPO} for its #{SMC_LICENSE} code.
163
""")
164
165
# webpack plugin to do the linking after it's "done"
166
class MathjaxVersionedSymlink
167
apply: (compiler) ->
168
# make absolute path to the mathjax lib (lives in node_module of smc-webapp)
169
symto = path.resolve(__dirname, "#{MATHJAX_LIB}")
170
console.log("mathjax symlink: pointing to #{symto}")
171
mksymlink = (dir, cb) ->
172
fs.exists dir, (exists, cb) ->
173
if not exists
174
fs.symlink(symto, dir, cb)
175
compiler.plugin "done", (compilation, cb) ->
176
async.concat([MATHJAX_ROOT, misc_node.MATHJAX_NOVERS], mksymlink, -> cb())
177
178
mathjaxVersionedSymlink = new MathjaxVersionedSymlink()
179
180
# deterministic hashing for assets
181
# TODO this sha-hash lib sometimes crashes. switch to https://github.com/erm0l0v/webpack-md5-hash and try if that works!
182
#WebpackSHAHash = require('webpack-sha-hash')
183
#webpackSHAHash = new WebpackSHAHash()
184
185
# cleanup like "make distclean"
186
# otherwise, compiles create an evergrowing pile of files
187
CleanWebpackPlugin = require('clean-webpack-plugin')
188
cleanWebpackPlugin = new CleanWebpackPlugin [OUTPUT],
189
verbose: true
190
dry: false
191
192
# assets.json file
193
AssetsPlugin = require('assets-webpack-plugin')
194
assetsPlugin = new AssetsPlugin
195
filename : path.join(OUTPUT, 'assets.json')
196
fullPath : no
197
prettyPrint: true
198
metadata:
199
git_ref : GIT_REV
200
version : SMC_VERSION
201
built : BUILD_DATE
202
timestamp : BUILD_TS
203
204
# https://www.npmjs.com/package/html-webpack-plugin
205
HtmlWebpackPlugin = require('html-webpack-plugin')
206
# we need our own chunk sorter, because just by dependency doesn't work
207
# this way, we can be 100% sure
208
smcChunkSorter = (a, b) ->
209
order = ['css', 'lib', 'smc']
210
if order.indexOf(a.names[0]) < order.indexOf(b.names[0])
211
return -1
212
else
213
return 1
214
215
# https://github.com/kangax/html-minifier#options-quick-reference
216
htmlMinifyOpts =
217
empty: true
218
removeComments: true
219
minifyJS : true
220
minifyCSS : true
221
collapseWhitespace : true
222
conservativeCollapse : true
223
224
# when base_url_html is set, it is hardcoded into the index page
225
# it mimics the logic of the hub, where all trailing slashes are removed
226
# i.e. the production page has a base url of '' and smc-in-smc has '/.../...'
227
base_url_html = BASE_URL # do *not* modify BASE_URL, it's needed with a '/' down below
228
while base_url_html and base_url_html[base_url_html.length-1] == '/'
229
base_url_html = base_url_html.slice(0, base_url_html.length-1)
230
231
# this is the main app.html file, which should be served without any caching
232
# config: https://github.com/jantimon/html-webpack-plugin#configuration
233
pug2app = new HtmlWebpackPlugin(
234
date : BUILD_DATE
235
title : TITLE
236
description : DESCRIPTION
237
BASE_URL : base_url_html
238
theme : theme
239
git_rev : GIT_REV
240
mathjax : MATHJAX_URL
241
filename : 'app.html'
242
chunksSortMode : smcChunkSorter
243
inject : 'body'
244
hash : PRODMODE
245
template : path.join(INPUT, 'app.pug')
246
minify : htmlMinifyOpts
247
GOOGLE_ANALYTICS : GOOGLE_ANALYTICS
248
)
249
250
# static html pages
251
# they only depend on the css chunk
252
staticPages = []
253
# in the root directory (doc/ and policies/ is below)
254
for [fn_in, fn_out] in [['index.pug', 'index.html']]
255
staticPages.push(new HtmlWebpackPlugin(
256
date : BUILD_DATE
257
title : TITLE
258
description : DESCRIPTION
259
BASE_URL : base_url_html
260
theme : theme
261
git_rev : GIT_REV
262
mathjax : MATHJAX_URL
263
filename : fn_out
264
chunks : ['css']
265
inject : 'head'
266
hash : PRODMODE
267
template : path.join(INPUT, fn_in)
268
minify : htmlMinifyOpts
269
GOOGLE_ANALYTICS : GOOGLE_ANALYTICS
270
PREFIX : ''
271
SCHEMA : require('smc-util/schema')
272
PREFIX : if fn_in == 'index.pug' then '' else '../'
273
))
274
275
# doc pages
276
for dp in (x for x in glob.sync('webapp-lib/doc/*.pug') when path.basename(x)[0] != '_')
277
output_fn = "doc/#{misc.change_filename_extension(path.basename(dp), 'html')}"
278
staticPages.push(new HtmlWebpackPlugin(
279
filename : output_fn
280
date : BUILD_DATE
281
title : TITLE
282
theme : theme
283
template : dp
284
chunks : ['css']
285
inject : 'head'
286
minify : htmlMinifyOpts
287
GOOGLE_ANALYTICS : GOOGLE_ANALYTICS
288
hash : PRODMODE
289
BASE_URL : base_url_html
290
PREFIX : '../'
291
))
292
293
# the following renders the policy pages
294
for pp in (x for x in glob.sync('webapp-lib/policies/*.pug') when path.basename(x)[0] != '_')
295
output_fn = "policies/#{misc.change_filename_extension(path.basename(pp), 'html')}"
296
staticPages.push(new HtmlWebpackPlugin(
297
filename : output_fn
298
date : BUILD_DATE
299
title : TITLE
300
theme : theme
301
template : pp
302
chunks : ['css']
303
inject : 'head'
304
minify : htmlMinifyOpts
305
GOOGLE_ANALYTICS : GOOGLE_ANALYTICS
306
hash : PRODMODE
307
BASE_URL : base_url_html
308
PREFIX : '../'
309
))
310
311
#video chat is done differently, this is kept for reference.
312
## video chat: not possible to render to html, while at the same time also supporting query parameters for files in the url
313
## maybe at some point https://github.com/webpack/webpack/issues/536 has an answer
314
#videoChatSide = new HtmlWebpackPlugin
315
# filename : "webrtc/group_chat_side.html"
316
# inject : 'head'
317
# template : 'webapp-lib/webrtc/group_chat_side.html'
318
# chunks : ['css']
319
# minify : htmlMinifyOpts
320
#videoChatCell = new HtmlWebpackPlugin
321
# filename : "webrtc/group_chat_cell.html"
322
# inject : 'head'
323
# template : 'webapp-lib/webrtc/group_chat_cell.html'
324
# chunks : ['css']
325
# minify : htmlMinifyOpts
326
327
# global css loader configuration
328
cssConfig = JSON.stringify(minimize: true, discardComments: {removeAll: true}, mergeLonghand: true, sourceMap: true)
329
330
###
331
# ExtractText for CSS should work, but doesn't. Also not necessary for our purposes ...
332
# Configuration left as a comment for future endeavours.
333
334
# https://webpack.github.io/docs/stylesheets.html
335
ExtractTextPlugin = require("extract-text-webpack-plugin")
336
337
# merge + minify of included CSS files
338
extractCSS = new ExtractTextPlugin("styles-[hash].css")
339
extractTextCss = ExtractTextPlugin.extract("style", "css?sourceMap&#{cssConfig}")
340
extractTextSass = ExtractTextPlugin.extract("style", "css?#{cssConfig}!sass?sourceMap&indentedSyntax")
341
extractTextScss = ExtractTextPlugin.extract("style", "css?#{cssConfig}!sass?sourceMap")
342
extractTextLess = ExtractTextPlugin.extract("style", "css?#{cssConfig}!less?sourceMap")
343
###
344
345
# Custom plugin, to handle the quirky situation of extra *.html files.
346
# It was originally used to copy auxiliary .html files, but since there is
347
# no processing of the included style/js files (hashing them), it cannot be used.
348
# maybe it will be useful for something else in the future...
349
class LinkFilesIntoTargetPlugin
350
constructor: (@files, @target) ->
351
352
apply: (compiler) ->
353
compiler.plugin "done", (comp) =>
354
#console.log('compilation:', _.keys(comp.compilation))
355
_.forEach @files, (fn) =>
356
if fn[0] != '/'
357
src = path.join(path.resolve(__dirname, INPUT), fn)
358
dst = path.join(@target, fn)
359
else
360
src = fn
361
fnrelative = fn[INPUT.length + 1 ..]
362
dst = path.join(@target, fnrelative)
363
dst = path.resolve(__dirname, dst)
364
console.log("hard-linking file:", src, "→", dst)
365
dst_dir = path.dirname(dst)
366
if not fs.existsSync(dst_dir)
367
fs.mkdir(dst_dir)
368
fs.linkSync(src, dst) # mysteriously, that doesn't work
369
370
#policies = glob.sync(path.join(INPUT, 'policies', '*.html'))
371
#linkFilesIntoTargetPlugin = new LinkFilesToTargetPlugin(policies, OUTPUT)
372
373
###
374
CopyWebpackPlugin = require('copy-webpack-plugin')
375
copyWebpackPlugin = new CopyWebpackPlugin []
376
###
377
378
# this is like C's #ifdef for the source code. It is particularly useful in the
379
# source code of SMC, such that it knows about itself's version and where
380
# mathjax is. The version&date is shown in the hover-title in the footer (year).
381
setNODE_ENV = new webpack.DefinePlugin
382
'process.env' :
383
'NODE_ENV' : JSON.stringify(NODE_ENV)
384
'MATHJAX_URL' : JSON.stringify(MATHJAX_URL)
385
'SMC_VERSION' : JSON.stringify(SMC_VERSION)
386
'SMC_GIT_REV' : JSON.stringify(GIT_REV)
387
'BUILD_DATE' : JSON.stringify(BUILD_DATE)
388
'BUILD_TS' : JSON.stringify(BUILD_TS)
389
'DEBUG' : JSON.stringify(DEBUG)
390
391
# This is not used, but maybe in the future.
392
# Writes a JSON file containing the main webpack-assets and their filenames.
393
{StatsWriterPlugin} = require("webpack-stats-plugin")
394
statsWriterPlugin = new StatsWriterPlugin(filename: "webpack-stats.json")
395
396
# https://webpack.github.io/docs/shimming-modules.html
397
# do *not* require('jquery') but $ = window.$
398
# this here doesn't work, b/c some modifications/plugins simply do not work when this is set
399
# rather, webapp-lib.coffee defines the one and only global jquery instance!
400
#provideGlobals = new webpack.ProvidePlugin
401
# '$' : 'jquery'
402
# 'jQuery' : 'jquery'
403
# "window.jQuery" : "jquery"
404
# "window.$" : "jquery"
405
406
# this is for debugging: adding it prints out a long long json of everything
407
# that ends up inside the chunks. that way, one knows exactly where which part did end up.
408
# (i.e. if require.ensure really creates chunkfiles, etc.)
409
class PrintChunksPlugin
410
apply: (compiler) ->
411
compiler.plugin 'compilation', (compilation, params) ->
412
compilation.plugin 'after-optimize-chunk-assets', (chunks) ->
413
console.log(chunks.map (c) ->
414
id: c.id
415
name: c.name
416
includes: c.modules.map (m) -> m.request
417
)
418
419
420
plugins = [
421
cleanWebpackPlugin,
422
#provideGlobals,
423
setNODE_ENV,
424
banner
425
]
426
427
if STATICPAGES
428
plugins = plugins.concat(staticPages)
429
entries =
430
css : 'webapp-css.coffee'
431
else
432
# ATTN don't alter or add names here, without changing the sorting function above!
433
entries =
434
css : 'webapp-css.coffee'
435
lib : 'webapp-lib.coffee'
436
smc : 'webapp-smc.coffee'
437
plugins = plugins.concat([
438
pug2app,
439
#commonsChunkPlugin,
440
#extractCSS,
441
#copyWebpackPlugin
442
#webpackSHAHash,
443
#new PrintChunksPlugin(),
444
mathjaxVersionedSymlink,
445
#linkFilesIntoTargetPlugin,
446
])
447
448
plugins = plugins.concat(staticPages)
449
plugins = plugins.concat([assetsPlugin, statsWriterPlugin])
450
# video chat plugins would be added here
451
452
if PRODMODE
453
console.log "production mode: enabling compression"
454
# https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
455
# plugins.push new webpack.optimize.CommonsChunkPlugin(name: "lib")
456
plugins.push new webpack.optimize.DedupePlugin()
457
plugins.push new webpack.optimize.OccurenceOrderPlugin()
458
# configuration for the number of chunks and their minimum size
459
plugins.push new webpack.optimize.LimitChunkCountPlugin(maxChunks: 5)
460
plugins.push new webpack.optimize.MinChunkSizePlugin(minChunkSize: 30000)
461
462
if PRODMODE or MINIFY
463
# to get source maps working in production mode, one has to figure out how
464
# to get inSourceMap/outSourceMap working here.
465
plugins.push new webpack.optimize.UglifyJsPlugin
466
sourceMap: false
467
minimize: true
468
output:
469
comments: new RegExp("This file is part of #{TITLE}","g") # to keep the banner inserted above
470
mangle:
471
except : ['$super', '$', 'exports', 'require']
472
screw_ie8 : true
473
compress:
474
screw_ie8 : true
475
warnings : false
476
properties : true
477
sequences : true
478
dead_code : true
479
conditionals : true
480
comparisons : true
481
evaluate : true
482
booleans : true
483
unused : true
484
loops : true
485
hoist_funs : true
486
cascade : true
487
if_return : true
488
join_vars : true
489
drop_debugger: true
490
negate_iife : true
491
unsafe : true
492
side_effects : true
493
494
495
# tuning generated filenames and the configs for the aux files loader.
496
# FIXME this setting isn't picked up properly
497
if PRODMODE
498
hashname = '[sha256:hash:base62:33].cacheme.[ext]' # don't use base64, it's not recommended for some reason.
499
else
500
hashname = '[path][name].nocache.[ext]'
501
pngconfig = "name=#{hashname}&limit=16000&mimetype=image/png"
502
svgconfig = "name=#{hashname}&limit=16000&mimetype=image/svg+xml"
503
icoconfig = "name=#{hashname}&mimetype=image/x-icon"
504
woffconfig = "name=#{hashname}&mimetype=application/font-woff"
505
506
# publicPath: either locally, or a CDN, see https://github.com/webpack/docs/wiki/configuration#outputpublicpath
507
# In order to use the CDN, copy all files from the `OUTPUT` directory over there.
508
# Caching: files ending in .html (like index.html or those in /policies/) and those matching '*.nocache.*' shouldn't be cached
509
# all others have a hash and can be cached long-term (especially when they match '*.cacheme.*')
510
if CDN_BASE_URL?
511
publicPath = CDN_BASE_URL
512
else
513
publicPath = path.join(BASE_URL, OUTPUT) + '/'
514
515
module.exports =
516
cache: true
517
518
# https://webpack.github.io/docs/configuration.html#devtool
519
# **do** use cheap-module-eval-source-map; it produces too large files, but who cares since we are not
520
# using this in production. DO NOT use 'source-map', which is VERY slow.
521
devtool: if SOURCE_MAP then '#cheap-module-eval-source-map'
522
523
entry: entries
524
525
output:
526
path : OUTPUT
527
publicPath : publicPath
528
filename : if PRODMODE then '[name]-[hash].cacheme.js' else '[name].nocache.js'
529
chunkFilename : if PRODMODE then '[id]-[hash].cacheme.js' else '[id].nocache.js'
530
hashFunction : 'sha256'
531
532
module:
533
loaders: [
534
{ test: /pnotify.*\.js$/, loader: "imports?define=>false,global=>window" },
535
{ test: /\.cjsx$/, loaders: ['coffee-loader', 'cjsx-loader'] },
536
{ test: /\.coffee$/, loader: 'coffee-loader' },
537
{ test: /\.less$/, loaders: ["style-loader", "css-loader", "less?#{cssConfig}"]}, #loader : extractTextLess }, #
538
{ test: /\.scss$/, loaders: ["style-loader", "css-loader", "sass?#{cssConfig}"]}, #loader : extractTextScss }, #
539
{ test: /\.sass$/, loaders: ["style-loader", "css-loader", "sass?#{cssConfig}&indentedSyntax"]}, # ,loader : extractTextSass }, #
540
{ test: /\.json$/, loaders: ['json-loader'] },
541
{ test: /\.png$/, loader: "file-loader?#{pngconfig}" },
542
{ test: /\.ico$/, loader: "file-loader?#{icoconfig}" },
543
{ test: /\.svg(\?[a-z0-9\.-=]+)?$/, loader: "url-loader?#{svgconfig}" },
544
{ test: /\.(jpg|jpeg|gif)$/, loader: "file-loader?name=#{hashname}"},
545
# .html only for files in smc-webapp!
546
{ test: /\.html$/, include: [path.resolve(__dirname, 'smc-webapp')], loader: "raw!html-minify?conservativeCollapse"},
547
# { test: /\.html$/, include: [path.resolve(__dirname, 'webapp-lib')], loader: "html-loader"},
548
{ test: /\.hbs$/, loader: "handlebars-loader" },
549
{ test: /\.woff(2)?(\?[a-z0-9\.-=]+)?$/, loader: "url-loader?#{woffconfig}" },
550
# this is the previous file-loader config for ttf and eot fonts -- but see #1974 which for me looks like a webpack sillyness
551
#{ test: /\.(ttf|eot)(\?[a-z0-9\.-=]+)?$/, loader: "file-loader?name=#{hashname}" },
552
#{ test: /\.(ttf|eot)$/, loader: "file-loader?name=#{hashname}" },
553
{ test: /\.ttf(\?[a-z0-9\.-=]+)?$/, loader: "url-loader?limit=10000&mimetype=application/octet-stream" },
554
{ test: /\.eot(\?[a-z0-9\.-=]+)?$/, loader: "file-loader?name=#{hashname}" },
555
# ---
556
{ test: /\.css$/, loaders: ["style-loader", "css-loader?#{cssConfig}"]}, # loader: extractTextCss }, #
557
{ test: /\.pug$/, loader: 'pug-loader' },
558
]
559
560
resolve:
561
# So we can require('file') instead of require('file.coffee')
562
extensions : ['', '.js', '.json', '.coffee', '.cjsx', '.scss', '.sass']
563
root : [path.resolve(__dirname),
564
path.resolve(__dirname, WEBAPP_LIB),
565
path.resolve(__dirname, 'smc-util'),
566
path.resolve(__dirname, 'smc-util/node_modules'),
567
path.resolve(__dirname, 'smc-webapp'),
568
path.resolve(__dirname, 'smc-webapp/node_modules')]
569
#alias:
570
# "jquery-ui": "jquery-ui/jquery-ui.js", # bind version of jquery-ui
571
# modules: path.join(__dirname, "node_modules") # bind to modules;
572
573
plugins: plugins
574
575
'html-minify-loader':
576
empty : true # KEEP empty attributes
577
cdata : true # KEEP CDATA from scripts
578
comments : false
579
removeComments : true
580
minifyJS : true
581
minifyCSS : true
582
collapseWhitespace : true
583
conservativeCollapse : true # absolutely necessary, also see above in module.loaders/.html
584
585
586