forked from ucfopen/Materia-Widget-Dev-Kit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebpack-widget.js
388 lines (363 loc) · 10.4 KB
/
webpack-widget.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
const fs = require('fs')
const path = require('path')
const webpack = require('webpack')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ZipPlugin = require('zip-webpack-plugin')
const MateriaDevServer = require('./express');
const GenerateWidgetHash = require('./webpack-generate-widget-hash')
// creators and players may reference materia core files directly
// To do so rather than hard-coding the actual location of those files
// the build process will replace those references with the current relative paths to those files
const packagedJSPath = 'src=\\"../../../js/$3\\"'
const devServerJSPath = 'src=\\"/mwdk/assets/js/$3\\"'
const isRunningDevServer = process.argv.find((v) => {return v.includes('webpack-dev-server')} )
const replaceTarget = isRunningDevServer ? devServerJSPath : packagedJSPath
// common paths used here
const srcPath = path.join(process.cwd(), 'src') + path.sep
const outputPath = path.join(process.cwd(), 'build') + path.sep
// list of supported browsers for use in autoprefixer
const browserList = [
'Explorer >= 11',
'last 3 Chrome versions',
'last 3 ChromeAndroid versions',
'last 3 Android versions',
'last 3 Firefox versions',
'last 3 FirefoxAndroid versions',
'last 3 iOS versions',
'last 3 Safari versions',
'last 3 Edge versions'
]
// when copying files, always ignore these
const copyIgnore = [
'.gitkeep'
]
// regex rules needed for replacing scripts loaded from materia
const materiaJSReplacements = [
{ search: /src=(\\?("|')?)(materia.enginecore.js)(\\?("|')?)/g, replace: replaceTarget },
{ search: /src=(\\?("|')?)(materia.scorecore.js)(\\?("|')?)/g, replace: replaceTarget },
{ search: /src=(\\?("|')?)(materia.creatorcore.js)(\\?("|')?)/g, replace: replaceTarget },
{ search: /src=(\\?("|')?)(materia.scorecore.js)(\\?("|')?)/g, replace: replaceTarget },
];
// webpack entries
const getDefaultEntries = () => ({
'creator.js': [
`${srcPath}creator.coffee`
],
'player.js': [
`${srcPath}player.coffee`
],
'creator.css': [
`${srcPath}creator.html`,
`${srcPath}creator.scss`
],
'player.css': [
`${srcPath}player.html`,
`${srcPath}player.scss`
]
})
// Load the materia configuration settings from the package.json file
const configFromPackage = () => {
let packagePath = path.join(process.cwd(), 'package.json')
let packageJson = require(packagePath)
return {
cleanName : packageJson.materia.cleanName.toLowerCase(),
}
}
// Provides a default config option
const combineConfig = (extras = {}) => {
const rules = getDefaultRules()
const orderedRules = [
rules.loaderDoNothingToJs,
rules.loaderCompileCoffee,
rules.loadAndCompileMarkdown,
rules.copyImages,
rules.loadHTMLAndReplaceMateriaScripts,
rules.loadAndPrefixCSS,
rules.loadAndPrefixSASS
]
const pkgConfig = configFromPackage()
const defaultCfg = {
cleanName: pkgConfig.cleanName,
copyList: getDefaultCopyList(),
entries: getDefaultEntries(),
moduleRules: orderedRules
}
return Object.assign({}, defaultCfg, extras)
}
// list of files and directories to copy into widget
const getDefaultCopyList = () => {
const copyList = [
{
flatten: true,
from: `${srcPath}demo.json`,
to: `${outputPath}demo.json`,
},
{
flatten: true,
from: `${srcPath}install.yaml`,
to: outputPath,
},
{
from: `${srcPath}_icons`,
to: `${outputPath}img`,
toType: 'dir'
},
{
flatten: true,
from: `${srcPath}_score`,
to: `${outputPath}_score-modules`,
toType: 'dir'
},
{
from: `${srcPath}_screen-shots`,
to: `${outputPath}img/screen-shots`,
toType: 'dir'
}
]
// assets directory is built in , but optional
let assetsPath = `${srcPath}assets`
if (fs.existsSync(assetsPath)) {
copyList.push({
from: assetsPath,
to: `${outputPath}assets`,
toType: 'dir'
})
}
// optionally use demo_dev.json to replace demo.json
// when running the dev server
const devDemo = 'demo_dev.json'
const devDemoPath = `${srcPath}${devDemo}`
if (isRunningDevServer && fs.existsSync(devDemoPath)) {
console.log(`===== USING ${devDemo} ====`)
copyList.push({
flatten: true,
from: devDemoPath,
to: `${outputPath}demo.json`,
force: true
})
}
return copyList
}
// Rules needed for common builds
const getDefaultRules = () => ({
// process regular javascript files
// SKIPS the default webpack Javascript functionality
// that evaluates js code and processes module imports
loaderDoNothingToJs: {
test: /\.js$/i,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
use: ['raw-loader']
})
},
// process coffee files by translating them to js
// SKIPS the default webpack Javascript functionality
// that evaluates js code and processes module imports
loaderCompileCoffee: {
test: /\.coffee$/i,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
use: [
'raw-loader',
{
loader: 'coffee-loader',
options: {
transpile:{
presets: [
'@babel/preset-env'
]
}
}
}
]
})
},
// webpack is going to look at all the images, fonts, etc
// in the src of the html files, this will tell webpack
// how to deal with those files
copyImages: {
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'file-loader',
query: {
emitFile: false, // keeps this plugin from renaming the file to an md5 hash
useRelativePath: true, // keeps path of img/src/imag.png intact
name: '[name].[ext]'
}
},
// Loads the html files and minifies their contents
// Rewrites the paths to our materia core libs provided by materia server
//
loadHTMLAndReplaceMateriaScripts: {
test: /\.html$/i,
exclude: /node_modules|_guides|guides/,
use: [
{
loader: 'file-loader',
options: { name: '[name].html' }
},
{
loader: 'extract-loader'
},
{
loader: 'string-replace-loader',
options: { multiple: materiaJSReplacements }
},
'html-loader'
]
},
// Process CSS Files
// Adds autoprefixer
loadAndPrefixCSS: {
test: /\.css$/i,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
use: [
'raw-loader',
{
// postcss-loader is needed to run autoprefixer
loader: 'postcss-loader',
options: {
// add autoprefixer, tell it what to prefix
plugins: [require('autoprefixer')({browsers: browserList})]
}
},
]
})
},
// Process SASS/SCSS Files
// Adds autoprefixer
loadAndPrefixSASS: {
test: /\.s[ac]ss$/i,
exclude: /node_modules\/(?!(materia-widget-development-kit\/templates)\/).*/,
loader: ExtractTextPlugin.extract({
use: [
'raw-loader',
{
// postcss-loader is needed to run autoprefixer
loader: 'postcss-loader',
options: {
// add autoprefixer, tell it what to prefix
plugins: [require('autoprefixer')({browsers: browserList})]
}
},
'sass-loader'
]
})
},
loadAndCompileMarkdown: {
test: /\.md$/,
exclude: /node_modules/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].html',
outputPath: 'guides/'
}
},
'extract-loader','html-loader','markdown-loader']
}
})
// This is a base config for building legacy widgets
// It will skip webpack's javascript functionality
// to avoid having to make changes to the source code of those widgets
// the config argument allows you to override some settings
// you can update the return from this method to modify or alter
// the base configuration
const getLegacyWidgetBuildConfig = (config = {}) => {
// load and combine the config
let cfg = combineConfig(config)
let build = {
stats: {children: false},
devServer: {
contentBase: outputPath,
headers:{
// allow iframes to talk to their parent containers
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
},
port: process.env.PORT || 8118,
setup: MateriaDevServer,
stats: {children: false},
},
// These are the default js and css files
entry: cfg.entries,
// write files to the outputPath (default = ./build) using the object keys from 'entry' above
output: {
path: outputPath,
filename: '[name]',
publicPath: ''
},
module: {rules: cfg.moduleRules},
plugins: [
// clear the build directory
new CleanWebpackPlugin(),
// copy all the common resources to the build directory
new CopyPlugin(cfg.copyList, {ignore: copyIgnore}),
// extract css from the webpack output
new ExtractTextPlugin({filename: '[name]'}),
// zip everything in the build path to zip dir
new ZipPlugin({
path: `${outputPath}_output`,
filename: cfg.cleanName,
extension: 'wigt'
}),
new GenerateWidgetHash({
widget: `_output/${cfg.cleanName}.wigt`,
output: `_output/${cfg.cleanName}-build-info.yml`
})
]
}
// conditionally add plugins to handle guides if the directory exists in /src
if (fs.existsSync(`${srcPath}_guides`))
{
// attach the guideStyles css to the default entry, if used
build.entry['guides/guideStyles.css'] = [
'./node_modules/materia-widget-development-kit/templates/guideStyles.scss'
]
build.plugins.unshift(
// explicitly remove the creator.temp.html and player.temp.html files created as part of the markdown conversion process
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: [`${outputPath}guides/creator.temp.html`, `${outputPath}guides/player.temp.html`]
})
)
// inject the compiled guides markdown into the templates and re-emit the guides
if (fs.existsSync(`${srcPath}_guides/creator.md`))
{
build.plugins.unshift(
new HtmlWebpackPlugin({
chunks: [],
template: 'node_modules/materia-widget-development-kit/templates/guide-template',
filename: 'guides/creator.html',
htmlTitle: 'Widget Creator Guide'
})
)
}
if (fs.existsSync(`${srcPath}_guides/player.md`))
{
build.plugins.unshift(
new HtmlWebpackPlugin({
chunks: [],
template: 'node_modules/materia-widget-development-kit/templates/guide-template',
filename: 'guides/player.html',
htmlTitle: 'Widget Player Guide'
})
)
}
}
else {
console.warn("No helper docs found, skipping plugins")
}
return build
}
module.exports = {
materiaJSReplacements: materiaJSReplacements,
configFromPackage: configFromPackage,
getLegacyWidgetBuildConfig: getLegacyWidgetBuildConfig,
getDefaultRules: getDefaultRules,
getDefaultCopyList: getDefaultCopyList,
getDefaultEntries: getDefaultEntries
}