populate.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import { INestApplication } from '@nestjs/common';
  2. import fs from 'fs-extra';
  3. import path from 'path';
  4. import ProgressBar from 'progress';
  5. import { tap } from 'rxjs/operators';
  6. import { Connection } from 'typeorm';
  7. import { logColored } from './cli-utils';
  8. // tslint:disable-next-line:no-var-requires
  9. const { Populator, Importer } = require('@vendure/core');
  10. // tslint:disable:no-console
  11. export async function populate() {
  12. logColored('\nPopulating... (this may take a minute or two)\n');
  13. const app = await getApplicationRef();
  14. if (app) {
  15. const initialData = require('./assets/initial-data.json');
  16. await populateInitialData(app, initialData);
  17. await populateProducts(app, initialData);
  18. logColored('\nDone!');
  19. await app.close();
  20. process.exit(0);
  21. }
  22. }
  23. export async function importProducts(csvPath: string, languageCode: string) {
  24. logColored(`\nImporting from "${csvPath}"...\n`);
  25. const app = await getApplicationRef();
  26. if (app) {
  27. await importProductsFromFile(app, csvPath, languageCode);
  28. logColored('\nDone!');
  29. await app.close();
  30. process.exit(0);
  31. }
  32. }
  33. async function getApplicationRef(): Promise<INestApplication | undefined> {
  34. const tsConfigFile = path.join(process.cwd(), 'vendure-config.ts');
  35. const jsConfigFile = path.join(process.cwd(), 'vendure-config.js');
  36. let isTs = false;
  37. let configFile: string | undefined;
  38. if (fs.existsSync(tsConfigFile)) {
  39. configFile = tsConfigFile;
  40. isTs = true;
  41. } else if (fs.existsSync(jsConfigFile)) {
  42. configFile = jsConfigFile;
  43. }
  44. if (!configFile) {
  45. console.error(`Could not find a config file`);
  46. console.error(`Checked "${tsConfigFile}", "${jsConfigFile}"`);
  47. process.exit(1);
  48. return;
  49. }
  50. if (isTs) {
  51. // we expect ts-node to be available
  52. const tsNode = require('ts-node');
  53. if (!tsNode) {
  54. console.error(`For "populate" to work with TypeScript projects, you must have ts-node installed`);
  55. process.exit(1);
  56. return;
  57. }
  58. require('ts-node').register();
  59. }
  60. const index = require(configFile);
  61. if (!index) {
  62. console.error(`Could not read the contents of "${configFile}"`);
  63. process.exit(1);
  64. return;
  65. }
  66. if (!index.config) {
  67. console.error(`The file "${configFile}" does not export a "config" object`);
  68. process.exit(1);
  69. return;
  70. }
  71. const config = index.config;
  72. config.silent = true;
  73. // Force the sync mode on, so that all the tables are created
  74. // on this initial run.
  75. config.dbConnectionOptions.synchronize = true;
  76. const { bootstrap } = require('@vendure/core');
  77. console.log('Bootstrapping Vendure server...');
  78. const app = await bootstrap(config);
  79. return app;
  80. }
  81. async function populateInitialData(app: INestApplication, initialData: any) {
  82. const populator = app.get(Populator);
  83. try {
  84. await populator.populateInitialData(initialData);
  85. } catch (err) {
  86. console.error(err.message);
  87. }
  88. }
  89. async function populateProducts(app: INestApplication, initialData: any) {
  90. // copy the images to the import folder
  91. const images = path.join(__dirname, 'assets', 'images');
  92. const destination = path.join(process.cwd(), 'vendure', 'import-assets');
  93. await fs.copy(images, destination);
  94. // import the csv of same product data
  95. const sampleProductsFile = path.join(__dirname, 'assets', 'sample-products.csv');
  96. await importProductsFromFile(app, sampleProductsFile, initialData.defaultLanguage);
  97. }
  98. async function importProductsFromFile(app: INestApplication, csvPath: string, languageCode: string) {
  99. // import the csv of same product data
  100. const importer = app.get(Importer);
  101. const productData = await fs.readFile(csvPath, 'utf-8');
  102. let bar: ProgressBar | undefined;
  103. const importResult = await importer
  104. .parseAndImport(productData, languageCode)
  105. .pipe(
  106. tap((progress: any) => {
  107. if (!bar) {
  108. bar = new ProgressBar(' importing [:bar] :percent :etas Importing: :prodName', {
  109. complete: '=',
  110. incomplete: ' ',
  111. total: progress.processed,
  112. width: 40,
  113. });
  114. }
  115. bar.tick({ prodName: progress.currentProduct });
  116. }),
  117. )
  118. .toPromise();
  119. if (importResult.errors.length) {
  120. const errorFile = path.join(process.cwd(), 'vendure-import-error.log');
  121. console.log(
  122. `${importResult.errors.length} errors encountered when importing product data. See: ${errorFile}`,
  123. );
  124. await fs.writeFile(errorFile, importResult.errors.join('\n'));
  125. }
  126. logColored(`\nImported ${importResult.imported} products`);
  127. }