1import execa = require('execa'); 2import { promises as fs } from 'fs'; 3import * as path from 'path'; 4import chalk from 'chalk'; 5import { useSpinner } from '../utils/useSpinner'; 6import { Task, TaskRunner } from './task'; 7import { cloneDeep } from 'lodash'; 8import globby from 'globby'; 9 10const clean = (cwd: string) => useSpinner('Cleaning', () => execa('npm', ['run', 'clean'], { cwd })); 11 12const compile = (cwd: string) => 13 useSpinner('Compiling sources', () => execa('tsc', ['-p', './tsconfig.build.json'], { cwd })); 14 15const bundle = (cwd: string) => useSpinner('Bundling', () => execa('npm', ['run', 'bundle'], { cwd })); 16 17const preparePackage = async (packageDist: string, pkg: any) => { 18 pkg = cloneDeep(pkg); // avoid mutations 19 20 pkg.main = 'index.js'; 21 pkg.types = 'index.d.ts'; 22 23 const version: string = pkg.version; 24 const name: string = pkg.name; 25 const deps: any = pkg.dependencies; 26 27 // Below we are adding cross-dependencies to Grafana's packages 28 // with the version being published 29 if (name.endsWith('/ui')) { 30 deps['@grafana/data'] = version; 31 } else if (name.endsWith('/runtime')) { 32 deps['@grafana/data'] = version; 33 deps['@grafana/ui'] = version; 34 } else if (name.endsWith('/toolkit')) { 35 deps['@grafana/data'] = version; 36 deps['@grafana/ui'] = version; 37 } 38 39 await useSpinner('Updating package.json', () => 40 fs.writeFile(`${packageDist}/package.json`, JSON.stringify(pkg, null, 2)) 41 ); 42}; 43 44const moveFiles = (fromPath: string, toPath: string) => { 45 const files = ['README.md', 'CHANGELOG.md', 'index.js']; 46 47 return useSpinner(`Moving ${files.join(', ')} files`, () => { 48 const promises = files.map((file) => fs.copyFile(`${fromPath}/${file}`, `${toPath}/${file}`)); 49 return Promise.all(promises); 50 }); 51}; 52 53const moveStaticFiles = async (packageRoot: string, pkg: any) => { 54 if (pkg.name.endsWith('/ui')) { 55 return useSpinner('Moving static files', async () => { 56 const staticFiles = await globby(`${packageRoot}/src/**/*.{png,svg,gif,jpg}`); 57 const pathSearch = new RegExp(`^${packageRoot}/src`); 58 const pathReplace = `${packageRoot}/compiled`; 59 const promises = staticFiles.map((file) => fs.copyFile(file, file.replace(pathSearch, pathReplace))); 60 await Promise.all(promises); 61 }); 62 } 63}; 64 65interface PackageBuildOptions { 66 scope: string; 67} 68 69const buildTaskRunner: TaskRunner<PackageBuildOptions> = async ({ scope }) => { 70 if (!scope) { 71 throw new Error('Provide packages with -s, --scope <packages>'); 72 } 73 74 const scopes = scope.split(',').map(async (s) => { 75 const packageRoot = path.resolve(__dirname, `../../../../grafana-${s}`); 76 const packageDist = `${packageRoot}/dist`; 77 const pkg = require(`${packageRoot}/package.json`); 78 console.log(chalk.yellow(`Building ${pkg.name} (package.json version: ${pkg.version})`)); 79 await clean(packageRoot); 80 await compile(packageRoot); 81 await moveStaticFiles(packageRoot, pkg); 82 await bundle(packageRoot); 83 await preparePackage(packageDist, pkg); 84 await moveFiles(packageRoot, packageDist); 85 }); 86 87 await Promise.all(scopes); 88}; 89 90export const buildPackageTask = new Task<PackageBuildOptions>('Package build', buildTaskRunner); 91