builder.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. /**
  7. * A CKEditor 5 release builder.
  8. *
  9. * @class Builder
  10. */
  11. class Builder {
  12. constructor( target ) {
  13. /**
  14. * The target directory where to create the build.
  15. *
  16. * **Warning**: if existing, this directory will be deleted before processing.
  17. *
  18. * @property {String}
  19. */
  20. this.target = target || 'build';
  21. /**
  22. * The temporary directory to use for build processing.
  23. *
  24. * **Warning**: if existing, this directory will be deleted before processing.
  25. *
  26. * @property {String}
  27. */
  28. this.tmp = 'build-tmp';
  29. /**
  30. * The list of tasks to be executed by the `build()` method. Each entry is an Array containing the name of the
  31. * method inside `tasks` to execute and the message to show to the end user when executing it.
  32. *
  33. * @property {Array}
  34. */
  35. this.taskList = [
  36. [ 'cleanUp', 'Cleaning the "' + this.target + '" directory...' ],
  37. [ 'copyToTmp', 'Copying source files for manipulation...' ],
  38. [ 'removeAmdNamespace', 'AMD cleanup...' ],
  39. [ 'optimize', 'Creating the optimized code...' ],
  40. [ 'cleanUpTmp', 'Removing the "' + this.tmp + '" directory...' ]
  41. ];
  42. }
  43. /**
  44. * Builds a CKEditor release based on the current development code.
  45. *
  46. * @param {Function} [callback] Function to be called when build finishes. It receives `false` on error.
  47. */
  48. build( callback ) {
  49. const that = this;
  50. let stepCounter = 0;
  51. // Before starting, run the initial checkups.
  52. if ( !this.checkUp() ) {
  53. console.error( 'Build operation aborted.' );
  54. callback( false );
  55. return;
  56. }
  57. console.log( 'Building CKEditor into the "' + this.target + '" directory:' );
  58. runNext();
  59. function runNext() {
  60. const next = that.taskList.shift();
  61. if ( next ) {
  62. stepCounter++;
  63. console.log( stepCounter + '. ' + next[ 1 ] );
  64. Builder.tasks[ next[ 0 ] ].call( that, runNext );
  65. } else {
  66. if ( callback ) {
  67. callback();
  68. }
  69. }
  70. }
  71. }
  72. checkUp() {
  73. const fs = require( 'fs' );
  74. // Stop if the tmp folder already exists.
  75. if ( fs.existsSync( this.tmp ) ) {
  76. console.error( 'The "' + this.tmp + '" directory already exists. Delete it and try again.' );
  77. return false;
  78. }
  79. return true;
  80. }
  81. }
  82. /**
  83. * Holds individual methods for each task executed by the builder.
  84. *
  85. * All methods here MUST be called in the builder context by using
  86. * `builder.tasks.someMethod.call( builder, callback )`.
  87. */
  88. Builder.tasks = {
  89. /**
  90. * Deletes the `target` and `tmp` directories.
  91. *
  92. * @param {Function} callback Function to be called when the task is done.
  93. * @returns {Object} The callback returned value.
  94. */
  95. cleanUp( callback ) {
  96. const del = require( 'del' );
  97. del.sync( this.target );
  98. del.sync( this.tmp );
  99. return callback();
  100. },
  101. /**
  102. * Copy the local source code of CKEditor and its dependencies to the `tmp` directory for processing.
  103. *
  104. * @param {Function} callback Function to be called when the task is done.
  105. * @returns {Object} The callback returned value.
  106. */
  107. copyToTmp( callback ) {
  108. const ncp = require( 'ncp' ).ncp;
  109. const path = require( 'path' );
  110. const fs = require( 'fs' );
  111. const tmp = this.tmp;
  112. const deps = require( '../../../package.json' ).dependencies;
  113. const toCopy = Object.keys( deps ).filter( function( name ) {
  114. return name.indexOf( 'ckeditor5-' ) === 0;
  115. } );
  116. fs.mkdirSync( tmp );
  117. function copy() {
  118. const module = toCopy.shift();
  119. if ( !module ) {
  120. return callback();
  121. }
  122. const dest = path.join( tmp + '/', module );
  123. if ( !fs.existsSync( dest ) ) {
  124. fs.mkdirSync( dest );
  125. }
  126. // Copy the "src" directory only.
  127. ncp( path.join( 'node_modules', module, 'src' ), path.join( dest, 'src' ), {
  128. dereference: true
  129. }, function( err ) {
  130. if ( err ) {
  131. throw err;
  132. }
  133. copy();
  134. } );
  135. }
  136. copy();
  137. },
  138. /**
  139. * Removes the `CKEDITOR` namespace from AMD calls in the `tmp` copy of the source code.
  140. *
  141. * @param {Function} callback Function to be called when the task is done.
  142. * @returns {Object} The callback returned value.
  143. */
  144. removeAmdNamespace( callback ) {
  145. const replace = require( 'replace' );
  146. replace( {
  147. regex: /^\s*CKEDITOR\.(define|require)/mg,
  148. replacement: '$1',
  149. paths: [ this.tmp ],
  150. recursive: true,
  151. silent: true
  152. } );
  153. callback();
  154. },
  155. /**
  156. * Creates the optimized release version of `ckeditor.js` in the `target` directory out of the `tmp` copy of the
  157. * source code.
  158. *
  159. * @param {Function} callback Function to be called when the task is done.
  160. * @returns {Object} The callback returned value.
  161. */
  162. optimize( callback ) {
  163. const requirejs = require( 'requirejs' );
  164. const config = {
  165. out: this.target + '/ckeditor.js',
  166. baseUrl: this.tmp + '/ckeditor5-core/src/',
  167. paths: {
  168. 'ckeditor': '../../../ckeditor',
  169. 'ckeditor-dev': '../../../src/ckeditor-dev',
  170. 'ckeditor-core': 'ckeditor'
  171. },
  172. include: [ 'ckeditor' ],
  173. stubModules: [ 'ckeditor-dev' ],
  174. // optimize: 'none',
  175. optimize: 'uglify2',
  176. preserveLicenseComments: false,
  177. wrap: {
  178. startFile: [ 'src/build/start.frag', require.resolve( 'almond' ) ],
  179. endFile: 'src/build/end.frag'
  180. }
  181. };
  182. requirejs.optimize( config, callback );
  183. },
  184. /**
  185. * Deletes `tmp` directory.
  186. *
  187. * @param {Function} callback Function to be called when the task is done.
  188. * @returns {Object} The callback returned value.
  189. */
  190. cleanUpTmp( callback ) {
  191. const del = require( 'del' );
  192. del.sync( this.tmp );
  193. return callback();
  194. }
  195. };
  196. module.exports = Builder;