You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
8.8 KiB

  1. 'use strict'
  2. /**
  3. * FUSEBOX
  4. *
  5. * Client & Server compiler / bundler / watcher
  6. */
  7. const _ = require('lodash')
  8. const Promise = require('bluebird')
  9. const colors = require('colors/safe')
  10. const fs = Promise.promisifyAll(require('fs-extra'))
  11. const fsbx = require('fuse-box')
  12. const nodemon = require('nodemon')
  13. const path = require('path')
  14. const uglify = require('uglify-js')
  15. // ======================================================
  16. // Parse cmd arguments
  17. // ======================================================
  18. const args = require('yargs')
  19. .option('d', {
  20. alias: 'dev',
  21. describe: 'Start in Developer mode',
  22. type: 'boolean'
  23. })
  24. .option('c', {
  25. alias: 'dev-configure',
  26. describe: 'Start in Configure Developer mode',
  27. type: 'boolean'
  28. })
  29. .help('h')
  30. .alias('h', 'help')
  31. .argv
  32. let mode = 'build'
  33. if (args.d) {
  34. console.info(colors.bgWhite.black(' Starting Fuse in DEVELOPER mode... '))
  35. mode = 'dev'
  36. } else if (args.c) {
  37. console.info(colors.bgWhite.black(' Starting Fuse in CONFIGURE DEVELOPER mode... '))
  38. mode = 'dev-configure'
  39. } else {
  40. console.info(colors.bgWhite.black(' Starting Fuse in BUILD mode... '))
  41. }
  42. // ======================================================
  43. // Define aliases / shims
  44. // ======================================================
  45. const ALIASES = {
  46. 'brace-ext-modelist': 'brace/ext/modelist.js',
  47. 'simplemde': 'simplemde/dist/simplemde.min.js',
  48. 'socket.io-client': 'socket.io-client/dist/socket.io.min.js',
  49. 'vue': 'vue/dist/vue.min.js'
  50. }
  51. const SHIMS = {
  52. _preinit: {
  53. source: '.build/_preinit.js',
  54. exports: '_preinit'
  55. },
  56. jquery: {
  57. source: 'node_modules/jquery/dist/jquery.js',
  58. exports: '$'
  59. },
  60. mathjax: {
  61. source: 'node_modules/mathjax/MathJax.js',
  62. exports: 'MathJax'
  63. }
  64. }
  65. // ======================================================
  66. // Global Tasks
  67. // ======================================================
  68. console.info(colors.white('└── ') + colors.green('Running global tasks...'))
  69. let preInitContent = ''
  70. let globalTasks = Promise.mapSeries([
  71. /**
  72. * ACE Modes
  73. */
  74. () => {
  75. return fs.accessAsync('./assets/js/ace').then(() => {
  76. console.info(colors.white(' └── ') + colors.magenta('ACE modes directory already exists. Task aborted.'))
  77. return true
  78. }).catch(err => {
  79. if (err.code === 'ENOENT') {
  80. console.info(colors.white(' └── ') + colors.green('Copy + Minify ACE modes to assets...'))
  81. return fs.ensureDirAsync('./assets/js/ace').then(() => {
  82. return fs.readdirAsync('./node_modules/brace/mode').then(modeList => {
  83. return Promise.map(modeList, mdFile => {
  84. console.info(colors.white(' mode-' + mdFile))
  85. let result = uglify.minify(path.join('./node_modules/brace/mode', mdFile), { output: { 'max_line_len': 1000000 } })
  86. return fs.writeFileAsync(path.join('./assets/js/ace', 'mode-' + mdFile), result.code)
  87. })
  88. })
  89. })
  90. } else {
  91. throw err
  92. }
  93. })
  94. },
  95. /**
  96. * MathJax
  97. */
  98. () => {
  99. return fs.accessAsync('./assets/js/mathjax').then(() => {
  100. console.info(colors.white(' └── ') + colors.magenta('MathJax directory already exists. Task aborted.'))
  101. return true
  102. }).catch(err => {
  103. if (err.code === 'ENOENT') {
  104. console.info(colors.white(' └── ') + colors.green('Copy MathJax dependencies to assets...'))
  105. return fs.ensureDirAsync('./assets/js/mathjax').then(() => {
  106. return fs.copyAsync('./node_modules/mathjax', './assets/js/mathjax', { filter: (src, dest) => {
  107. let srcNormalized = src.replace(/\\/g, '/')
  108. let shouldCopy = false
  109. console.log(srcNormalized)
  110. _.forEach([
  111. '/node_modules/mathjax',
  112. '/node_modules/mathjax/jax',
  113. '/node_modules/mathjax/jax/input',
  114. '/node_modules/mathjax/jax/output'
  115. ], chk => {
  116. if (srcNormalized.endsWith(chk)) {
  117. shouldCopy = true
  118. }
  119. })
  120. _.forEach([
  121. '/node_modules/mathjax/extensions',
  122. '/node_modules/mathjax/MathJax.js',
  123. '/node_modules/mathjax/jax/element',
  124. '/node_modules/mathjax/jax/input/MathML',
  125. '/node_modules/mathjax/jax/input/TeX',
  126. '/node_modules/mathjax/jax/output/SVG'
  127. ], chk => {
  128. if (srcNormalized.indexOf(chk) > 0) {
  129. shouldCopy = true
  130. }
  131. })
  132. if (shouldCopy && srcNormalized.indexOf('/fonts/') > 0 && srcNormalized.indexOf('/STIX-Web') <= 1) {
  133. shouldCopy = false
  134. }
  135. return shouldCopy
  136. }})
  137. })
  138. } else {
  139. throw err
  140. }
  141. })
  142. },
  143. /**
  144. * Bundle pre-init scripts
  145. */
  146. () => {
  147. console.info(colors.white(' └── ') + colors.green('Bundling pre-init scripts...'))
  148. return fs.readdirAsync('./client/js/pre-init').map(f => {
  149. let fPath = path.join('./client/js/pre-init/', f)
  150. return fs.readFileAsync(fPath, 'utf8').then(fContent => {
  151. preInitContent += fContent + ';\n'
  152. })
  153. }).then(() => {
  154. return fs.outputFileAsync('./.build/_preinit.js', preInitContent, 'utf8')
  155. })
  156. }
  157. ], f => { return f() })
  158. // ======================================================
  159. // Fuse Tasks
  160. // ======================================================
  161. let fuse
  162. globalTasks.then(() => {
  163. switch (mode) {
  164. // =============================================
  165. // DEVELOPER MODE
  166. // =============================================
  167. case 'dev':
  168. // Client
  169. fuse = fsbx.FuseBox.init({
  170. homeDir: './client',
  171. outFile: './assets/js/bundle.min.js',
  172. alias: ALIASES,
  173. shim: SHIMS,
  174. plugins: [
  175. [ fsbx.SassPlugin({ includePaths: ['../core'] }), fsbx.CSSPlugin() ],
  176. fsbx.BabelPlugin({ comments: false, presets: ['es2015'] }),
  177. fsbx.JSONPlugin()
  178. ],
  179. debug: false,
  180. log: true
  181. })
  182. fuse.devServer('>index.js', {
  183. port: 4444,
  184. httpServer: false,
  185. hmr: false
  186. })
  187. // Server
  188. _.delay(() => {
  189. nodemon({
  190. script: './server.js',
  191. args: [],
  192. ignore: ['assets/', 'client/', 'data/', 'repo/', 'tests/'],
  193. ext: 'js json',
  194. watch: [
  195. 'controllers',
  196. 'libs',
  197. 'locales',
  198. 'middlewares',
  199. 'models',
  200. 'agent.js',
  201. 'server.js'
  202. ],
  203. env: { 'NODE_ENV': 'development' }
  204. })
  205. }, 1000)
  206. break
  207. // =============================================
  208. // CONFIGURE - DEVELOPER MODE
  209. // =============================================
  210. case 'dev-configure':
  211. // Client
  212. fuse = fsbx.FuseBox.init({
  213. homeDir: './client',
  214. outFile: './assets/js/configure.min.js',
  215. alias: ALIASES,
  216. shim: SHIMS,
  217. plugins: [
  218. [ fsbx.SassPlugin({ includePaths: ['../core'] }), fsbx.CSSPlugin() ],
  219. fsbx.BabelPlugin({ comments: false, presets: ['es2015'] }),
  220. fsbx.JSONPlugin()
  221. ],
  222. debug: false,
  223. log: true
  224. })
  225. fuse.devServer('>configure.js', {
  226. port: 4444,
  227. httpServer: false
  228. })
  229. // Server
  230. _.delay(() => {
  231. nodemon({
  232. exec: 'node wiki configure',
  233. ignore: ['assets/', 'client/', 'data/', 'repo/', 'tests/'],
  234. ext: 'js json',
  235. watch: [
  236. 'configure.js'
  237. ],
  238. env: { 'NODE_ENV': 'development' }
  239. })
  240. }, 1000)
  241. break
  242. // =============================================
  243. // BUILD ONLY MODE
  244. // =============================================
  245. case 'build':
  246. fuse = fsbx.FuseBox.init({
  247. homeDir: './client',
  248. alias: ALIASES,
  249. shim: SHIMS,
  250. plugins: [
  251. fsbx.EnvPlugin({ NODE_ENV: 'production' }),
  252. fsbx.BannerPlugin(preInitContent),
  253. [ fsbx.SassPlugin({ outputStyle: 'compressed', includePaths: ['./node_modules/requarks-core'] }), fsbx.CSSPlugin() ],
  254. fsbx.BabelPlugin({
  255. config: {
  256. comments: false,
  257. presets: ['es2015']
  258. }
  259. }),
  260. fsbx.JSONPlugin(),
  261. fsbx.UglifyJSPlugin({
  262. compress: { unused: false },
  263. output: { 'max_line_len': 1000000 }
  264. })
  265. ],
  266. debug: false,
  267. log: true
  268. })
  269. fuse.bundle({
  270. './assets/js/bundle.min.js': '>index.js',
  271. './assets/js/configure.min.js': '>configure.js'
  272. }).then(() => {
  273. console.info(colors.green.bold('\nAssets compilation + bundling completed.'))
  274. }).catch(err => {
  275. console.error(colors.red(' X Bundle compilation failed! ' + err.message))
  276. process.exit(1)
  277. })
  278. break
  279. }
  280. })