Gruntfile.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*eslint-env node*/
  2. 'use strict';
  3. const fs = require('fs');
  4. const path = require('path');
  5. const semver = require('semver');
  6. const liveEditor = require('@gfxfundamentals/live-editor');
  7. const liveEditorPath = path.dirname(require.resolve('@gfxfundamentals/live-editor'));
  8. module.exports = function(grunt) {
  9. require('load-grunt-tasks')(grunt);
  10. const s_ignoreRE = /\.(md|py|sh|enc)$/i;
  11. function noMds(filename) {
  12. return !s_ignoreRE.test(filename);
  13. }
  14. const s_isMdRE = /\.md$/i;
  15. function mdsOnly(filename) {
  16. return s_isMdRE.test(filename);
  17. }
  18. function notFolder(filename) {
  19. return !fs.statSync(filename).isDirectory();
  20. }
  21. function noMdsNoFolders(filename) {
  22. return noMds(filename) && notFolder(filename);
  23. }
  24. grunt.initConfig({
  25. eslint: {
  26. lib: {
  27. src: [
  28. 'threejs/resources/*.js',
  29. ],
  30. },
  31. support: {
  32. src: [
  33. 'Gruntfile.js',
  34. 'build/js/build.js',
  35. ],
  36. },
  37. examples: {
  38. src: [
  39. 'threejs/*.html',
  40. 'threejs/lessons/resources/*.js',
  41. '!threejs/lessons/resources/prettify.js',
  42. 'threejs/lessons/resources/*.html',
  43. ],
  44. },
  45. },
  46. copy: {
  47. main: {
  48. files: [
  49. { expand: false, src: '*', dest: 'out/', filter: noMdsNoFolders, },
  50. { expand: true, cwd: `${liveEditor.monacoEditor}/`, src: 'min/**', dest: 'out/monaco-editor/', nonull: true, },
  51. { expand: true, cwd: `${liveEditorPath}/src/`, src: '**', dest: 'out/threejs/resources/', nonull: true, },
  52. { expand: true, src: 'threejs/**', dest: 'out/', filter: noMds, },
  53. { expand: true, src: '3rdparty/**', dest: 'out/', },
  54. ],
  55. },
  56. },
  57. clean: [
  58. 'out/**/*',
  59. ],
  60. buildlesson: {
  61. main: {
  62. files: [],
  63. },
  64. },
  65. watch: {
  66. main: {
  67. files: [
  68. 'threejs/**',
  69. '3rdparty/**',
  70. 'node_modules/@gfxfundamentals/live-editor/src/**',
  71. ],
  72. tasks: ['copy'],
  73. options: {
  74. spawn: false,
  75. },
  76. },
  77. lessons: {
  78. files: [
  79. 'threejs/lessons/**/threejs*.md',
  80. ],
  81. tasks: ['buildlesson'],
  82. options: {
  83. spawn: false,
  84. },
  85. },
  86. },
  87. });
  88. let changedFiles = {};
  89. const onChange = grunt.util._.debounce(function() {
  90. grunt.config('copy.main.files', Object.keys(changedFiles).filter(noMds).map((file) => {
  91. const copy = {
  92. src: file,
  93. dest: 'out/',
  94. };
  95. if (file.indexOf('live-editor') >= 0) {
  96. copy.cwd = `${path.dirname(file)}/`;
  97. copy.src = path.basename(file);
  98. copy.expand = true;
  99. copy.dest = 'out/threejs/resources/';
  100. }
  101. return copy;
  102. }));
  103. grunt.config('buildlesson.main.files', Object.keys(changedFiles).filter(mdsOnly).map((file) => {
  104. return {
  105. src: file,
  106. };
  107. }));
  108. changedFiles = {};
  109. }, 200);
  110. grunt.event.on('watch', function(action, filepath) {
  111. changedFiles[filepath] = action;
  112. onChange();
  113. });
  114. const buildSettings = {
  115. outDir: 'out',
  116. baseUrl: 'https://threejsfundamentals.org',
  117. rootFolder: 'threejs',
  118. lessonGrep: 'threejs*.md',
  119. siteName: 'ThreeJSFundamentals',
  120. siteThumbnail: 'threejsfundamentals.jpg', // in rootFolder/lessons/resources
  121. templatePath: 'build/templates',
  122. };
  123. // just the hackiest way to get this working.
  124. grunt.registerMultiTask('buildlesson', 'build a lesson', function() {
  125. const filenames = new Set();
  126. this.files.forEach((files) => {
  127. files.src.forEach((filename) => {
  128. filenames.add(filename);
  129. });
  130. });
  131. const buildStuff = require('@gfxfundamentals/lesson-builder');
  132. const settings = Object.assign({}, buildSettings, {
  133. filenames,
  134. });
  135. const finish = this.async();
  136. buildStuff(settings).finally(finish);
  137. });
  138. grunt.registerTask('buildlessons', function() {
  139. const buildStuff = require('@gfxfundamentals/lesson-builder');
  140. const finish = this.async();
  141. buildStuff(buildSettings).finally(finish);
  142. });
  143. grunt.task.registerMultiTask('fixthreepaths', 'fix three paths', function() {
  144. const options = this.options({});
  145. const oldVersionRE = new RegExp(`/${options.oldVersionStr}/`, 'g');
  146. const newVersionReplacement = `/${options.newVersionStr}/`;
  147. this.files.forEach((files) => {
  148. files.src.forEach((filename) => {
  149. const oldContent = fs.readFileSync(filename, {encoding: 'utf8'});
  150. const newContent = oldContent.replace(oldVersionRE, newVersionReplacement);
  151. if (oldContent !== newContent) {
  152. grunt.log.writeln(`updating ${filename} to ${options.newVersionStr}`);
  153. fs.writeFileSync(filename, newContent);
  154. }
  155. });
  156. });
  157. });
  158. grunt.registerTask('bumpthree', function() {
  159. const lessonInfo = JSON.parse(fs.readFileSync('package.json', {encoding: 'utf8'}));
  160. const oldVersion = lessonInfo.threejsfundamentals.threeVersion;
  161. const oldVersionStr = `r${oldVersion}`;
  162. const threePath = path.join(__dirname, '..', 'three.js');
  163. const threeInfo = JSON.parse(fs.readFileSync(path.join(threePath, 'package.json'), {encoding: 'utf8'}));
  164. const newVersion = semver.minor(threeInfo.version);
  165. const newVersionStr = `r${newVersion}`;
  166. const basePath = path.join('threejs', 'resources', 'threejs', newVersionStr);
  167. grunt.config.merge({
  168. copy: {
  169. threejs: {
  170. files: [
  171. { expand: true, cwd: `${threePath}/build/`, src: 'three.js', dest: `${basePath}/`, },
  172. { expand: true, cwd: `${threePath}/build/`, src: 'three.min.js', dest: `${basePath}/`, },
  173. { expand: true, cwd: `${threePath}/build/`, src: 'three.module.js', dest: `${basePath}/`, },
  174. { expand: true, cwd: `${threePath}/examples/js/`, src: '**', dest: `${basePath}/js/`, },
  175. { expand: true, cwd: `${threePath}/examples/jsm/`, src: '**', dest: `${basePath}/jsm/`, },
  176. ],
  177. },
  178. },
  179. fixthreepaths: {
  180. options: {
  181. oldVersionStr,
  182. newVersionStr,
  183. },
  184. src: [
  185. 'threejs/**/*.html',
  186. 'threejs/**/*.md',
  187. 'threejs/**/*.js',
  188. '!threejs/resources/threejs/**',
  189. ],
  190. },
  191. });
  192. lessonInfo.threejsfundamentals.threeVersion = newVersion;
  193. fs.writeFileSync('package.json', JSON.stringify(lessonInfo, null, 2));
  194. grunt.task.run(['copy:threejs', 'fixthreepaths']);
  195. });
  196. grunt.registerTask('build', ['clean', 'copy:main', 'buildlessons']);
  197. grunt.registerTask('buildwatch', ['build', 'watch']);
  198. grunt.registerTask('default', ['eslint', 'build']);
  199. };