Gruntfile.js 7.3 KB

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