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.
 
 
 
 
 
 

180 line
4.5 KiB

  1. const fs = require('fs');
  2. const path = require('path');
  3. const chalk = require('chalk');
  4. const rollup = require('rollup');
  5. const { execSync } = require('child_process');
  6. const log = console.log; // eslint-disable-line
  7. const {
  8. get_build_json,
  9. get_app_path,
  10. apps_list,
  11. run_serially,
  12. assets_path,
  13. sites_path
  14. } = require('./rollup.utils');
  15. const {
  16. get_options_for,
  17. get_options
  18. } = require('./config');
  19. const skip_frappe = process.argv.includes("--skip_frappe")
  20. if (skip_frappe) {
  21. let idx = apps_list.indexOf("frappe");
  22. if (idx > -1) {
  23. apps_list.splice(idx, 1);
  24. }
  25. }
  26. const exists = (flag) => process.argv.indexOf(flag) != -1
  27. const value = (flag) => (process.argv.indexOf(flag) != -1) ? process.argv[process.argv.indexOf(flag) + 1] : null;
  28. const files = exists("--files") ? value("--files").split(",") : false;
  29. const build_for_app = exists("--app") ? value("--app") : null;
  30. const concat = !exists("--no-concat");
  31. if (!files) show_production_message();
  32. ensure_js_css_dirs();
  33. if (concat) concatenate_files();
  34. create_build_file();
  35. if (files) {
  36. build_files(files);
  37. } else if (build_for_app) {
  38. build_assets_for_app(build_for_app)
  39. .then(() => {
  40. run_build_command_for_app(build_for_app);
  41. })
  42. } else {
  43. build_assets_for_all_apps()
  44. .then(() => {
  45. run_build_command_for_apps()
  46. });
  47. }
  48. function build_assets_for_all_apps() {
  49. return run_serially(
  50. apps_list.map(app => () => build_assets(app))
  51. );
  52. }
  53. function build_assets_for_app(app) {
  54. return build_assets(app)
  55. }
  56. function build_from_(options) {
  57. const promises = options.map(({ inputOptions, outputOptions, output_file}) => {
  58. return build(inputOptions, outputOptions)
  59. .then(() => {
  60. log(`${chalk.green('✔')} Built ${output_file}`);
  61. });
  62. });
  63. const start = Date.now();
  64. return Promise.all(promises)
  65. .then(() => {
  66. const time = Date.now() - start;
  67. log(chalk.green(`✨ Done in ${time / 1000}s`));
  68. });
  69. }
  70. function build_assets(app) {
  71. const options = get_options_for(app);
  72. if (!options.length) return Promise.resolve();
  73. log(chalk.yellow(`\nBuilding ${app} assets...\n`));
  74. return build_from_(options);
  75. }
  76. function build_files(files, app="frappe") {
  77. let ret;
  78. for (let file of files) {
  79. let options = get_options(file, app);
  80. if (!options.length) return Promise.resolve();
  81. ret += build_from_(options);
  82. }
  83. return ret;
  84. }
  85. function build(inputOptions, outputOptions) {
  86. return rollup.rollup(inputOptions)
  87. .then(bundle => bundle.write(outputOptions))
  88. .catch(err => {
  89. log(chalk.red(err));
  90. // Kill process to fail in a CI environment
  91. if (process.env.CI) {
  92. process.kill(process.pid)
  93. }
  94. });
  95. }
  96. function concatenate_files() {
  97. // only concatenates files, not processed through rollup
  98. const files_to_concat = Object.keys(get_build_json('frappe'))
  99. .filter(filename => filename.startsWith('concat:'));
  100. files_to_concat.forEach(output_file => {
  101. const input_files = get_build_json('frappe')[output_file];
  102. const file_content = input_files.map(file_name => {
  103. let prefix = get_app_path('frappe');
  104. if (file_name.startsWith('node_modules/')) {
  105. prefix = path.resolve(get_app_path('frappe'), '..');
  106. }
  107. const full_path = path.resolve(prefix, file_name);
  108. return `/* ${file_name} */\n` + fs.readFileSync(full_path);
  109. }).join('\n\n');
  110. const output_file_path = output_file.slice('concat:'.length);
  111. const target_path = path.resolve(assets_path, output_file_path);
  112. fs.writeFileSync(target_path, file_content);
  113. log(`${chalk.green('✔')} Built ${output_file_path}`);
  114. });
  115. }
  116. function create_build_file() {
  117. const touch = require('touch');
  118. touch(path.join(sites_path, '.build'), { force: true });
  119. }
  120. function run_build_command_for_apps() {
  121. let cwd = process.cwd();
  122. apps_list.map(app => run_build_command_for_app(app))
  123. process.chdir(cwd);
  124. }
  125. function run_build_command_for_app(app) {
  126. if (app === 'frappe') return;
  127. let root_app_path = path.resolve(get_app_path(app), '..');
  128. let package_json = path.resolve(root_app_path, 'package.json');
  129. if (fs.existsSync(package_json)) {
  130. let package = require(package_json);
  131. if (package.scripts && package.scripts.build) {
  132. console.log('\nRunning build command for', chalk.bold(app));
  133. process.chdir(root_app_path);
  134. execSync('yarn build', { encoding: 'utf8', stdio: 'inherit' });
  135. }
  136. }
  137. }
  138. function ensure_js_css_dirs() {
  139. const paths = [
  140. path.resolve(assets_path, 'js'),
  141. path.resolve(assets_path, 'css')
  142. ];
  143. paths.forEach(path => {
  144. if (!fs.existsSync(path)) {
  145. fs.mkdirSync(path);
  146. }
  147. });
  148. }
  149. function show_production_message() {
  150. const production = process.env.FRAPPE_ENV === 'production';
  151. log(chalk.yellow(`${production ? 'Production' : 'Development'} mode`));
  152. }