Gruntfile.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. thumbnailOptions: {
  123. thumbnailBackground: 'threejsfundamentals-background.jpg',
  124. text: [
  125. {
  126. font: 'bold 100px lesson-font',
  127. verticalSpacing: 100,
  128. offset: [100, 120],
  129. textAlign: 'left',
  130. shadowOffset: [15, 15],
  131. strokeWidth: 15,
  132. textWrapWidth: 1000,
  133. },
  134. {
  135. font: 'bold 60px lesson-font',
  136. text: 'threejsfundamentals.org',
  137. verticalSpacing: 100,
  138. offset: [-100, -90],
  139. textAlign: 'right',
  140. shadowOffset: [8, 8],
  141. strokeWidth: 15,
  142. textWrapWidth: 1000,
  143. color: 'hsl(340, 100%, 70%)',
  144. },
  145. ],
  146. },
  147. };
  148. // just the hackiest way to get this working.
  149. grunt.registerMultiTask('buildlesson', 'build a lesson', function() {
  150. const filenames = new Set();
  151. this.files.forEach((files) => {
  152. files.src.forEach((filename) => {
  153. filenames.add(filename);
  154. });
  155. });
  156. const buildStuff = require('@gfxfundamentals/lesson-builder');
  157. const settings = {...buildSettings, filenames};
  158. const finish = this.async();
  159. buildStuff(settings).finally(finish);
  160. });
  161. grunt.registerTask('buildlessons', function() {
  162. const buildStuff = require('@gfxfundamentals/lesson-builder');
  163. const finish = this.async();
  164. buildStuff(buildSettings).finally(finish);
  165. });
  166. grunt.task.registerMultiTask('fixthreepaths', 'fix three paths', function() {
  167. const options = this.options({});
  168. const oldVersionRE = new RegExp(`/${options.oldVersionStr}/`, 'g');
  169. const newVersionReplacement = `/${options.newVersionStr}/`;
  170. this.files.forEach((files) => {
  171. files.src.forEach((filename) => {
  172. const oldContent = fs.readFileSync(filename, {encoding: 'utf8'});
  173. const newContent = oldContent.replace(oldVersionRE, newVersionReplacement);
  174. if (oldContent !== newContent) {
  175. grunt.log.writeln(`updating ${filename} to ${options.newVersionStr}`);
  176. fs.writeFileSync(filename, newContent);
  177. }
  178. });
  179. });
  180. });
  181. grunt.registerTask('bumpthree', function() {
  182. const lessonInfo = JSON.parse(fs.readFileSync('package.json', {encoding: 'utf8'}));
  183. const oldVersion = lessonInfo.threejsfundamentals.threeVersion;
  184. const oldVersionStr = `r${oldVersion}`;
  185. const threePath = path.dirname(path.dirname(require.resolve('three')));
  186. const threeInfo = JSON.parse(fs.readFileSync(path.join(threePath, 'package.json'), {encoding: 'utf8'}));
  187. const newVersion = semver.minor(threeInfo.version);
  188. const newVersionStr = `r${newVersion}`;
  189. const basePath = path.join('threejs', 'resources', 'threejs', newVersionStr);
  190. grunt.config.merge({
  191. copy: {
  192. threejs: {
  193. files: [
  194. { expand: true, cwd: `${threePath}/build/`, src: 'three.js', dest: `${basePath}/build/`, },
  195. { expand: true, cwd: `${threePath}/build/`, src: 'three.min.js', dest: `${basePath}/build/`, },
  196. { expand: true, cwd: `${threePath}/build/`, src: 'three.module.js', dest: `${basePath}/build/`, },
  197. { expand: true, cwd: `${threePath}/examples/js/`, src: '**', dest: `${basePath}/examples/js/`, },
  198. { expand: true, cwd: `${threePath}/examples/jsm/`, src: '**', dest: `${basePath}/examples/jsm/`, },
  199. ],
  200. },
  201. },
  202. fixthreepaths: {
  203. options: {
  204. oldVersionStr,
  205. newVersionStr,
  206. },
  207. src: [
  208. 'threejs/**/*.html',
  209. 'threejs/**/*.md',
  210. 'threejs/**/*.js',
  211. '!threejs/resources/threejs/**',
  212. ],
  213. },
  214. });
  215. lessonInfo.threejsfundamentals.threeVersion = newVersion;
  216. fs.writeFileSync('package.json', JSON.stringify(lessonInfo, null, 2));
  217. grunt.task.run(['copy:threejs', 'fixthreepaths']);
  218. });
  219. grunt.registerTask('build', ['clean', 'copy:main', 'buildlessons']);
  220. grunt.registerTask('buildwatch', ['build', 'watch']);
  221. grunt.registerTask('default', ['eslint', 'build']);
  222. };