diff --git a/gulpfile.js b/gulpfile.js index 7d0feaad9fc..a0962e1a387 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,167 +1,16 @@ -const fs = require('fs'); -const path = require('path'); -const gulp = require('gulp'); -const ts = require('gulp-typescript'); -const sourcemaps = require('gulp-sourcemaps'); -const clean = require('gulp-clean'); -const deleteEmpty = require('delete-empty'); -const childProcess = require('child_process'); -const log = require('fancy-log'); -const clc = require('cli-color'); -const promiseSeries = require('promise.series'); - -const { promisify } = require('util'); - -const exec = promisify(childProcess.exec); - -const SAMPLE = path.join(__dirname, 'sample'); +'use strict'; +/** + * Load the TypeScript compiler, then load the TypeScript gulpfile which simply loads all + * the tasks. The tasks are really inside tools/gulp/tasks. + */ -const packages = { - common: ts.createProject('packages/common/tsconfig.json'), - core: ts.createProject('packages/core/tsconfig.json'), - microservices: ts.createProject('packages/microservices/tsconfig.json'), - websockets: ts.createProject('packages/websockets/tsconfig.json'), - testing: ts.createProject('packages/testing/tsconfig.json'), - 'platform-express': ts.createProject( - 'packages/platform-express/tsconfig.json', - ), - 'platform-fastify': ts.createProject( - 'packages/platform-fastify/tsconfig.json', - ), - 'platform-socket.io': ts.createProject( - 'packages/platform-socket.io/tsconfig.json', - ), - 'platform-ws': ts.createProject('packages/platform-ws/tsconfig.json'), -}; -const modules = Object.keys(packages); -const source = 'packages'; -const distId = process.argv.indexOf('--dist'); -const dist = distId < 0 ? source : process.argv[distId + 1]; - -gulp.task('default', function() { - modules.forEach(module => { - gulp.watch( - [`${source}/${module}/**/*.ts`, `${source}/${module}/*.ts`], - [module], - ); - }); -}); - -gulp.task('copy-misc', function() { - return gulp - .src(['Readme.md', 'LICENSE', '.npmignore']) - .pipe(gulp.dest(`${source}/common`)) - .pipe(gulp.dest(`${source}/core`)) - .pipe(gulp.dest(`${source}/microservices`)) - .pipe(gulp.dest(`${source}/websockets`)) - .pipe(gulp.dest(`${source}/testing`)) - .pipe(gulp.dest(`${source}/platform-fastify`)) - .pipe(gulp.dest(`${source}/platform-express`)) - .pipe(gulp.dest(`${source}/platform-ws`)) - .pipe(gulp.dest(`${source}/platform-socket.io`)); -}); - -gulp.task('clean:output', function() { - return gulp - .src( - [`${source}/**/*.js`, `${source}/**/*.d.ts`, `${source}/**/*.js.map`], - { - read: false, - }, - ) - .pipe(clean()); -}); - -gulp.task('clean:dirs', function(done) { - deleteEmpty.sync(`${source}/`); - done(); -}); - -gulp.task('clean:bundle', gulp.series('clean:output', 'clean:dirs')); - -modules.forEach(module => { - gulp.task(module, () => { - return packages[module] - .src() - .pipe(packages[module]()) - .pipe(gulp.dest(`${dist}/${module}`)); - }); -}); - -modules.forEach(module => { - gulp.task(module + ':dev', () => { - return packages[module] - .src() - .pipe(sourcemaps.init()) - .pipe(packages[module]()) - .pipe( - sourcemaps.mapSources(sourcePath => './' + sourcePath.split('/').pop()), - ) - .pipe(sourcemaps.write('.')) - .pipe(gulp.dest(`${dist}/${module}`)); - }); -}); - -gulp.task('common:dev', gulp.series(modules.map(module => module + ':dev'))); -gulp.task('build', gulp.series(modules)); -gulp.task('build:dev', gulp.series('common:dev')); - -function getFolders(dir) { - return fs.readdirSync(dir).filter(function(file) { - return fs.statSync(path.join(dir, file)).isDirectory(); - }); -} - -const getDirs = base => getFolders(base).map(path => `${base}/${path}`); - -gulp.task('install:samples', async () => { - const directories = getDirs(SAMPLE); - - const promises = directories.map(async dir => { - const dirName = dir.replace(__dirname, ''); - log.info(`Installing dependencies of ${clc.magenta(dirName)}`); - try { - await exec(`npm install --no-shrinkwrap --prefix ${dir}`); - log.info(`Finished installing ${clc.magenta(dirName)}`); - } catch (err) { - log.error(`Failed installing dependencies of ${dirName}`); - throw err; - } - }); - - return await promiseSeries(promises); -}); - -gulp.task('build:samples', async () => { - const directories = getDirs(SAMPLE); +const path = require('path'); - const promises = directories.map(async dir => { - const dirName = dir.replace(__dirname, ''); - log.info(`Building ${clc.magenta(dirName)}`); - try { - await exec(`npm run build --prefix ${dir}`); - log.info(`Finished building ${clc.magenta(dirName)}`); - } catch (err) { - log.error(`Failed building ${clc.magenta(dirName)}:`); - if (err.stdout) { - log.error(err.stdout); - } - throw err; - } - }); +const projectDir = __dirname; +const tsconfigPath = path.join(projectDir, 'tools/gulp/tsconfig.json'); - return await promiseSeries(promises); +require('ts-node').register({ + project: tsconfigPath }); -gulp.task('move', function() { - const examplesDirs = getDirs('sample'); - const integrationDirs = getDirs('integration'); - const directories = examplesDirs.concat(integrationDirs); - - let stream = gulp.src(['node_modules/@nestjs/**/*']); - - directories.forEach(dir => { - stream = stream.pipe(gulp.dest(dir + '/node_modules/@nestjs')); - }); - return stream; -}); +require('./tools/gulp/gulpfile'); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1c1992f8cfb..60a8e4ccded 100644 --- a/package-lock.json +++ b/package-lock.json @@ -549,6 +549,16 @@ "@types/node": "*" } }, + "@types/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, "@types/graphql": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-14.2.3.tgz", @@ -564,6 +574,17 @@ "@types/koa": "*" } }, + "@types/gulp": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/gulp/-/gulp-4.0.6.tgz", + "integrity": "sha512-0E8/iV/7FKWyQWSmi7jnUvgXXgaw+pfAzEB06Xu+l0iXVJppLbpOye5z7E2klw5akXd+8kPtYuk65YBcZPM4ow==", + "dev": true, + "requires": { + "@types/undertaker": "*", + "@types/vinyl-fs": "*", + "chokidar": "^2.1.2" + } + }, "@types/http-assert": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.0.tgz", @@ -674,6 +695,41 @@ "@types/node": "*" } }, + "@types/undertaker": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/undertaker/-/undertaker-1.2.2.tgz", + "integrity": "sha512-j4iepCSuY2JGW/hShVtUBagic0klYNFIXP7VweavnYnNC2EjiKxJFeaS9uaJmAT0ty9sQSqTS1aagWMZMV0HyA==", + "dev": true, + "requires": { + "@types/undertaker-registry": "*" + } + }, + "@types/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha512-Z4TYuEKn9+RbNVk1Ll2SS4x1JeLHecolIbM/a8gveaHsW0Hr+RQMraZACwTO2VD7JvepgA6UO1A1VrbktQrIbQ==", + "dev": true + }, + "@types/vinyl": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.3.tgz", + "integrity": "sha512-hrT6xg16CWSmndZqOTJ6BGIn2abKyTw0B58bI+7ioUoj3Sma6u8ftZ1DTI2yCaJamOVGLOnQWiPH3a74+EaqTA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/vinyl-fs": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/@types/vinyl-fs/-/vinyl-fs-2.4.11.tgz", + "integrity": "sha512-2OzQSfIr9CqqWMGqmcERE6Hnd2KY3eBVtFaulVo3sJghplUcaeMdL9ZjEiljcQQeHjheWY9RlNmumjIAvsBNaA==", + "dev": true, + "requires": { + "@types/glob-stream": "*", + "@types/node": "*", + "@types/vinyl": "*" + } + }, "@types/ws": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.1.tgz", @@ -12706,12 +12762,6 @@ "resolved": "https://registry.npmjs.org/promise-breaker/-/promise-breaker-5.0.0.tgz", "integrity": "sha512-mgsWQuG4kJ1dtO6e/QlNDLFtMkMzzecsC69aI5hlLEjGHFNpHrvGhFi4LiK5jg2SMQj74/diH+wZliL9LpGsyA==" }, - "promise.series": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz", - "integrity": "sha1-LMfr6Vn8OmYZwEq029yeRS2GS70=", - "dev": true - }, "protobufjs": { "version": "6.8.8", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", diff --git a/package.json b/package.json index 22f78108745..b2d4ba758d9 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "@types/cors": "2.8.5", "@types/express": "4.17.0", "@types/fastify-cors": "2.1.0", + "@types/gulp": "^4.0.6", "@types/kafka-node": "2.0.8", "@types/mocha": "5.2.7", "@types/node": "10.14.13", @@ -121,7 +122,6 @@ "nodemon": "1.19.1", "nyc": "14.1.1", "prettier": "1.18.2", - "promise.series": "0.2.0", "sinon": "7.3.2", "sinon-chai": "3.3.0", "socket.io-client": "2.2.0", diff --git a/sample/02-gateways/tsconfig.json b/sample/02-gateways/tsconfig.json index 52723fb1a50..084f892e42b 100644 --- a/sample/02-gateways/tsconfig.json +++ b/sample/02-gateways/tsconfig.json @@ -11,7 +11,8 @@ "target": "es6", "sourceMap": true, "outDir": "./dist", - "baseUrl": "./" + "baseUrl": "./", + "skipLibCheck": true }, "exclude": ["node_modules"] } diff --git a/sample/05-sql-typeorm/tsconfig.json b/sample/05-sql-typeorm/tsconfig.json index 52723fb1a50..084f892e42b 100644 --- a/sample/05-sql-typeorm/tsconfig.json +++ b/sample/05-sql-typeorm/tsconfig.json @@ -11,7 +11,8 @@ "target": "es6", "sourceMap": true, "outDir": "./dist", - "baseUrl": "./" + "baseUrl": "./", + "skipLibCheck": true }, "exclude": ["node_modules"] } diff --git a/sample/15-mvc/tsconfig.json b/sample/15-mvc/tsconfig.json index 52723fb1a50..084f892e42b 100644 --- a/sample/15-mvc/tsconfig.json +++ b/sample/15-mvc/tsconfig.json @@ -11,7 +11,8 @@ "target": "es6", "sourceMap": true, "outDir": "./dist", - "baseUrl": "./" + "baseUrl": "./", + "skipLibCheck": true }, "exclude": ["node_modules"] } diff --git a/sample/17-mvc-fastify/tsconfig.json b/sample/17-mvc-fastify/tsconfig.json index 52723fb1a50..084f892e42b 100644 --- a/sample/17-mvc-fastify/tsconfig.json +++ b/sample/17-mvc-fastify/tsconfig.json @@ -11,7 +11,8 @@ "target": "es6", "sourceMap": true, "outDir": "./dist", - "baseUrl": "./" + "baseUrl": "./", + "skipLibCheck": true }, "exclude": ["node_modules"] } diff --git a/tools/gulp/config.ts b/tools/gulp/config.ts new file mode 100644 index 00000000000..73c2ee991f9 --- /dev/null +++ b/tools/gulp/config.ts @@ -0,0 +1,8 @@ +import { getDirs } from './util/task-helpers'; + +// All paths are related to the base dir +export const source = 'packages'; +export const integrationPath = 'integration'; +export const samplePath = 'sample'; + +export const packagePaths = getDirs(source); \ No newline at end of file diff --git a/tools/gulp/gulpfile.ts b/tools/gulp/gulpfile.ts new file mode 100644 index 00000000000..de25610c22a --- /dev/null +++ b/tools/gulp/gulpfile.ts @@ -0,0 +1,5 @@ +import './tasks/copy-misc'; +import './tasks/clean'; +import './tasks/packages'; +import './tasks/move'; +import './tasks/samples'; diff --git a/tools/gulp/tasks/clean.ts b/tools/gulp/tasks/clean.ts new file mode 100644 index 00000000000..19b8322ebca --- /dev/null +++ b/tools/gulp/tasks/clean.ts @@ -0,0 +1,33 @@ +import { task, src, series } from 'gulp'; +import { source } from '../config'; +import * as clean from 'gulp-clean'; +import * as deleteEmpty from 'delete-empty'; + +/** + * Cleans the build output assets from the packages folders + */ +function cleanOutput() { + return src( + [ + `${source}/**/*.js`, + `${source}/**/*.d.ts`, + `${source}/**/*.js.map`, + `${source}/**/*.d.ts.map`, + ], + { + read: false, + }, + ).pipe(clean()); +} + +/** + * Cleans empty dirs + */ +function cleanDirs(done: () => void) { + deleteEmpty.sync(`${source}/`); + done(); +} + +task('clean:output', cleanOutput); +task('clean:dirs', cleanDirs); +task('clean:bundle', series('clean:output', 'clean:dirs')); diff --git a/tools/gulp/tasks/copy-misc.ts b/tools/gulp/tasks/copy-misc.ts new file mode 100644 index 00000000000..8c3091f1164 --- /dev/null +++ b/tools/gulp/tasks/copy-misc.ts @@ -0,0 +1,18 @@ +import { task, src, dest } from 'gulp'; +import { packagePaths } from '../config'; + +/** + * Copies assets like Readme.md or LICENSE from the project base path + * to all the packages. + */ +function copyMisc(): NodeJS.ReadWriteStream { + const miscFiles = src(['Readme.md', 'LICENSE', '.npmignore']); + // Since `dest()` does not take a string-array, we have to append it + // ourselves + return packagePaths.reduce( + (stream, packagePath) => stream.pipe(dest(packagePath)), + miscFiles, + ); +} + +task('copy-misc', copyMisc); diff --git a/tools/gulp/tasks/move.ts b/tools/gulp/tasks/move.ts new file mode 100644 index 00000000000..5058a4d86f6 --- /dev/null +++ b/tools/gulp/tasks/move.ts @@ -0,0 +1,23 @@ +import { task, src, dest } from 'gulp'; +import { getDirs } from '../util/task-helpers'; +import { samplePath, integrationPath } from '../config'; +import { join } from 'path'; + +/** + * Moves the compiled nest files into the + * `samples/*` and `integration/*` dirs. + */ +function move() { + const samplesDirs = getDirs(samplePath); + const integrationDirs = getDirs(integrationPath); + const directories = samplesDirs.concat(integrationDirs); + + const distFiles = src(['node_modules/@nestjs/**/*']); + + return directories.reduce( + (distFile, dir) => distFile.pipe(dest(join(dir, '/node_modules/@nestjs'))), + distFiles, + ); +} + +task('move', move); diff --git a/tools/gulp/tasks/packages.ts b/tools/gulp/tasks/packages.ts new file mode 100644 index 00000000000..a125943c419 --- /dev/null +++ b/tools/gulp/tasks/packages.ts @@ -0,0 +1,78 @@ +import { source, packagePaths } from '../config'; +import { task, watch, series, dest } from 'gulp'; +import { createProject } from 'gulp-typescript'; +import * as sourcemaps from 'gulp-sourcemaps'; +import * as log from 'fancy-log'; + +// Has to be a hardcoded object due to build order +const packages = { + 'common': createProject('packages/common/tsconfig.json'), + 'core': createProject('packages/core/tsconfig.json'), + 'microservices': createProject('packages/microservices/tsconfig.json'), + 'websockets': createProject('packages/websockets/tsconfig.json'), + 'testing': createProject('packages/testing/tsconfig.json'), + 'platform-express': createProject('packages/platform-express/tsconfig.json'), + 'platform-fastify': createProject('packages/platform-fastify/tsconfig.json'), + 'platform-socket.io': createProject( + 'packages/platform-socket.io/tsconfig.json', + ), + 'platform-ws': createProject('packages/platform-ws/tsconfig.json'), +}; + +const modules = Object.keys(packages); + +const distId = process.argv.indexOf('--dist'); +const dist = distId < 0 ? source : process.argv[distId + 1]; + +/** + * Watches the packages/* folder and + * builds the package on file change + */ +function defaultTask() { + log.info('Watching files..'); + modules.forEach(packageName => { + watch( + [`${source}/${packageName}/**/*.ts`, `${source}/${packageName}/*.ts`], + series(packageName), + ); + }); +} + +/** + * Builds the given package + * @param packageName The name of the package + */ +function buildPackage(packageName: string) { + return packages[packageName] + .src() + .pipe(packages[packageName]()) + .pipe(dest(`${dist}/${packageName}`)); +} + +/** + * Builds the given package and adds sourcemaps + * @param packageName The name of the package + */ +function buildPackageDev(packageName: string) { + return packages[packageName] + .src() + .pipe(sourcemaps.init()) + .pipe(packages[packageName]()) + .pipe( + sourcemaps.mapSources( + (sourcePath: string) => './' + sourcePath.split('/').pop(), + ), + ) + .pipe(sourcemaps.write('.', {})) + .pipe(dest(`${dist}/${packageName}`)); +} + +modules.forEach(packageName => { + task(packageName, () => buildPackage(packageName)); + task(`${packageName}:dev`, () => buildPackageDev(packageName)); +}); + +task('common:dev', series(modules.map(packageName => `${packageName}:dev`))); +task('build', series(modules)); +task('build:dev', series('common:dev')); +task('default', defaultTask); diff --git a/tools/gulp/tasks/samples.ts b/tools/gulp/tasks/samples.ts new file mode 100644 index 00000000000..05245f77dd5 --- /dev/null +++ b/tools/gulp/tasks/samples.ts @@ -0,0 +1,58 @@ +import { resolve } from 'path'; +import { promisify } from 'util'; +import * as childProcess from 'child_process'; + +import { task } from 'gulp'; + +import * as log from 'fancy-log'; +import * as clc from 'cli-color'; + +import { getDirs } from '../util/task-helpers'; +import { samplePath } from '../config'; + +const exec = promisify(childProcess.exec); + +/** + * Installs all the npm packages in the + * `samples/*` folder + */ +async function installSamples() { + const directories = getDirs(samplePath); + + for await (const dir of directories) { + const dirName = dir.replace(resolve(__dirname, '../../../'), ''); + log.info(`Installing dependencies of ${clc.magenta(dirName)}`); + try { + await exec(`npm install --no-shrinkwrap --prefix ${dir}`); + log.info(`Finished installing ${clc.magenta(dirName)}`); + } catch (err) { + log.error(`Failed installing dependencies of ${dirName}`); + throw err; + } + } +} + +/** + * Builds all the `samples/*` + */ +async function buildSamples() { + const directories = getDirs(samplePath); + + for await (const dir of directories) { + const dirName = dir.replace(__dirname, ''); + log.info(`Building ${clc.magenta(dirName)}`); + try { + await exec(`npm run build --prefix ${dir}`); + log.info(`Finished building ${clc.magenta(dirName)}`); + } catch (err) { + log.error(`Failed building ${clc.magenta(dirName)}:`); + if (err.stdout) { + log.error(err.stdout); + } + process.exit(1); + } + } +} + +task('install:samples', async () => await installSamples()); +task('build:samples', async () => await buildSamples()); diff --git a/tools/gulp/tsconfig.json b/tools/gulp/tsconfig.json new file mode 100644 index 00000000000..6438b3c5aee --- /dev/null +++ b/tools/gulp/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + "noUnusedParameters": false, + "noUnusedLocals": false, + "lib": ["es2015", "dom", "es2016.array.include"], + "module": "commonjs", + "moduleResolution": "node", + "outDir": "../../dist/tools/gulp", + "strictNullChecks": true, + "strictFunctionTypes": true, + "noImplicitThis": true, + "noEmitOnError": true, + "noImplicitAny": false, + "target": "es5", + "types": [ + "node" + ], + "typeRoots": ["./typings", "../../node_modules/@types/"], + "baseUrl": ".", + }, + "files": [ + "gulpfile.ts" + ] +} diff --git a/tools/gulp/util/task-helpers.ts b/tools/gulp/util/task-helpers.ts new file mode 100644 index 00000000000..1f92706c7f3 --- /dev/null +++ b/tools/gulp/util/task-helpers.ts @@ -0,0 +1,14 @@ +import { readdirSync, statSync } from 'fs'; +import { join } from 'path'; + +function isDirectory(path: string) { + return statSync(path).isDirectory(); +} + +export function getFolders(dir: string) { + return readdirSync(dir).filter(file => isDirectory(join(dir, file))); +} + +export function getDirs(base: string) { + return getFolders(base).map(path => `${base}/${path}`); +}