Skip to content
This repository has been archived by the owner on Mar 31, 2024. It is now read-only.

Commit

Permalink
[typescript] add typescript support for the server and browser (elast…
Browse files Browse the repository at this point in the history
…ic#19104)

* [typescript] add typescript support for the server and browser

* [ts-jest] upgrade to latest version

* [jest] support test.tsx files

* [jest/ts] modify `ts-jest.tsConfigFile` config based on filePath

* [types] use correct major version of minimatch types

* [jest] add ts support to x-pack jest config

* [ts/projects] fix tsconfig.json not found error message

* [optimizer/ts] use lowercase jsx option

* [tsconfig] remove ui/* alias

* [plguin-helpers] remove mention of `buildSourcePatterns`

* [plugin-helpers] expect typescript to be a devDep

* [dev/build] place transpile tasks next to each other

* [ts/x-pack] add common and server directories to ts project

* [dev/ts/project] use a limited set of globs to find tsconfig files
  • Loading branch information
Spencer committed May 18, 2018
1 parent 2a2ccd1 commit f811ba5
Show file tree
Hide file tree
Showing 37 changed files with 636 additions and 307 deletions.
22 changes: 21 additions & 1 deletion docs/development/plugin/development-plugin-resources.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,24 @@ The Kibana directory must be named `kibana`, and your plugin directory must be l
If you're developing a plugin that has a user interface, take a look at our https://elastic.github.io/eui[Elastic UI Framework].
It documents the CSS and React components we use to build Kibana's user interface.

You're welcome to use these components, but be aware that they are rapidly evolving and we might introduce breaking changes that will disrupt your plugin's UI.
You're welcome to use these components, but be aware that they are rapidly evolving and we might introduce breaking changes that will disrupt your plugin's UI.

[float]
==== TypeScript Support
Plugin code can be written in http://www.typescriptlang.org/[TypeScript] if desired. To enable TypeScript support create a `tsconfig.json` file at the root of your plugin that looks something like this:

["source","js"]
-----------
{
// extend Kibana's tsconfig, or use your own settings
"extends": "../../kibana/tsconfig.json",
// tell the TypeScript compiler where to find your source files
"include": [
"server/**/*",
"public/**/*"
]
}
-----------

TypeScript code is automatically converted into JavaScript during development, but not in the distributable version of Kibana. If you use the {repo}blob/{branch}/packages/kbn-plugin-helpers[@kbn/plugin-helpers] to build your plugin then your `.ts` and `.tsx` files will be permanently transpiled before your plugin is archived. If you have your own build process, make sure to run the TypeScript compiler on your source files and ship the compilation output so that your plugin will work with the distributable version of Kibana.
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@
"validate-npm-package-name": "2.2.2",
"vega-lib": "^3.3.1",
"vega-lite": "^2.4.0",
"vega-tooltip": "^0.9.14",
"vega-schema-url-parser": "1.0.0",
"vega-tooltip": "^0.9.14",
"vision": "4.1.0",
"webpack": "3.6.0",
"webpack-merge": "4.1.0",
Expand All @@ -225,6 +225,8 @@
"@kbn/eslint-plugin-license-header": "link:packages/kbn-eslint-plugin-license-header",
"@kbn/plugin-generator": "link:packages/kbn-plugin-generator",
"@kbn/test": "link:packages/kbn-test",
"@types/globby": "^6.1.0",
"@types/minimatch": "^2.0.29",
"angular-mocks": "1.4.7",
"babel-eslint": "8.1.2",
"babel-jest": "^22.4.3",
Expand Down Expand Up @@ -298,8 +300,10 @@
"supertest": "3.0.0",
"supertest-as-promised": "4.0.2",
"tree-kill": "^1.1.0",
"ts-jest": "^22.4.3",
"typescript": "^2.8.1",
"ts-jest": "^22.4.6",
"ts-loader": "^3.5.0",
"ts-node": "^6.0.3",
"typescript": "^2.8.3",
"vinyl-fs": "^3.0.2",
"xml2js": "^0.4.19",
"xmlbuilder": "9.0.4"
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-dev-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "@kbn/dev-utils",
"main": "./target/index.js",
"types": "./index.d.ts",
"version": "1.0.0",
"license": "Apache-2.0",
"private": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ function tryNodeResolver(importRequest, file, config) {
return nodeResolver.resolve(
importRequest,
file,
// we use Object.assign so that this file is compatible with slightly older
// versions of node.js used by IDEs (eg. resolvers are run in the Electron
// process in Atom)
Object.assign({}, config, {
extensions: ['.js', '.json'],
extensions: ['.js', '.json', '.ts', '.tsx'],
isFile,
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ exports.getWebpackConfig = function(kibanaPath, projectRoot, config) {
return {
context: kibanaPath,
resolve: {
extensions: ['.js', '.json'],
extensions: ['.js', '.json', '.ts', '.tsx'],
mainFields: ['browser', 'main'],
modules: [
'webpackShims',
Expand Down
17 changes: 17 additions & 0 deletions packages/kbn-plugin-helpers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,20 @@ Setting | Description
`skipInstallDependencies` | Don't install dependencies defined in package.json into build output
`buildVersion` | Version for the build output
`kibanaVersion` | Kibana version for the build output (added to package.json)

## TypeScript support

Plugin code can be written in [TypeScript](http://www.typescriptlang.org/) if desired. To enable TypeScript support create a `tsconfig.json` file at the root of your plugin that looks something like this:

```js
{
// extend Kibana's tsconfig, or use your own settings
"extends": "../../kibana/tsconfig.json",

// tell the TypeScript compiler where to find your source files
"include": [
"server/**/*",
"public/**/*"
]
}
```
1 change: 1 addition & 0 deletions packages/kbn-plugin-helpers/lib/plugin_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module.exports = function (root) {

const buildSourcePatterns = [
'yarn.lock',
'tsconfig.json',
'package.json',
'index.js',
'{lib,public,server,webpackShims,translations}/**/*',
Expand Down
65 changes: 63 additions & 2 deletions packages/kbn-plugin-helpers/tasks/build/create_build.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const join = require('path').join;
const relative = require('path').relative;
const unlinkSync = require('fs').unlinkSync;
const { readFileSync, writeFileSync, unlinkSync, existsSync } = require('fs');
const execFileSync = require('child_process').execFileSync;
const del = require('del');
const vfs = require('vinyl-fs');
Expand Down Expand Up @@ -29,7 +29,29 @@ function removeSymlinkDependencies(root) {
});
}

module.exports = function createBuild(plugin, buildTarget, buildVersion, kibanaVersion, files) {
// parse a ts config file
function parseTsconfig(pluginSourcePath, configPath) {
const ts = require(join(pluginSourcePath, 'node_modules', 'typescript'));

const { error, config } = ts.parseConfigFileTextToJson(
configPath,
readFileSync(configPath, 'utf8')
);

if (error) {
throw error;
}

return config;
}

module.exports = function createBuild(
plugin,
buildTarget,
buildVersion,
kibanaVersion,
files
) {
const buildSource = plugin.root;
const buildRoot = join(buildTarget, 'kibana', plugin.id);

Expand Down Expand Up @@ -65,6 +87,45 @@ module.exports = function createBuild(plugin, buildTarget, buildVersion, kibanaV

execFileSync(winCmd('yarn'), ['install', '--production', '--pure-lockfile'], options);
})
.then(function () {
const buildConfigPath = join(buildRoot, 'tsconfig.json');

if (!existsSync(buildConfigPath)) {
return;
}

if (!plugin.pkg.devDependencies.typescript) {
throw new Error(
'Found tsconfig.json file in plugin but typescript is not a devDependency.'
);
}

// attempt to patch the extends path in the tsconfig file
const buildConfig = parseTsconfig(buildSource, buildConfigPath);

if (buildConfig.extends) {
buildConfig.extends = join(
relative(buildRoot, buildSource),
buildConfig.extends
);

writeFileSync(buildConfigPath, JSON.stringify(buildConfig));
}

execFileSync(
join(buildSource, 'node_modules', '.bin', 'tsc'),
['--pretty', 'true'],
{
cwd: buildRoot,
stdio: ['ignore', 'pipe', 'pipe'],
}
);

del.sync([
join(buildRoot, '**', '*.{ts,tsx,d.ts}'),
join(buildRoot, 'tsconfig.json'),
]);
})
.then(function () {
const buildFiles = [relative(buildTarget, buildRoot) + '/**/*'];

Expand Down
6 changes: 6 additions & 0 deletions packages/kbn-pm/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ module.exports = {
},
{
loader: 'ts-loader',
options: {
compilerOptions: {
// enable esnext modules so webpack can do its thing better
module: 'esnext',
},
},
},
],
exclude: /node_modules/,
Expand Down
2 changes: 0 additions & 2 deletions packages/kbn-system-loader/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"declaration": true,
"outDir": "./target"
},
Expand Down
10 changes: 10 additions & 0 deletions src/babel-register/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// unless we are running a prebuilt/distributable version of
// kibana, automatically transpile typescript to js before babel
if (!global.__BUILT_WITH_BABEL__) {
const { resolve } = require('path');
require('ts-node').register({
transpileOnly: true,
cacheDirectory: resolve(__dirname, '../../optimize/.cache/ts-node')
});
}

// register and polyfill need to happen in this
// order and in separate files. Checkout each file
// for a much more detailed explaination
Expand Down
8 changes: 6 additions & 2 deletions src/dev/build/build_distributables.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CleanExtraBinScriptsTask,
CleanExtraFilesFromModulesTask,
CleanPackagesTask,
CleanTypescriptTask,
CleanTask,
CopySourceTask,
CreateArchivesSourcesTask,
Expand All @@ -21,7 +22,8 @@ import {
InstallDependenciesTask,
OptimizeBuildTask,
RemovePackageJsonDepsTask,
TranspileSourceTask,
TranspileBabelTask,
TranspileTypescriptTask,
UpdateLicenseFileTask,
VerifyEnvTask,
VerifyExistingNodeBuildsTask,
Expand Down Expand Up @@ -76,10 +78,12 @@ export async function buildDistributables(options) {
await run(CopySourceTask);
await run(CreateEmptyDirsAndFilesTask);
await run(CreateReadmeTask);
await run(TranspileSourceTask);
await run(TranspileBabelTask);
await run(TranspileTypescriptTask);
await run(BuildPackagesTask);
await run(CreatePackageJsonTask);
await run(InstallDependenciesTask);
await run(CleanTypescriptTask);
await run(CleanPackagesTask);
await run(CreateNoticeFileTask);
await run(UpdateLicenseFileTask);
Expand Down
24 changes: 24 additions & 0 deletions src/dev/build/lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import fs from 'fs';
import { createHash } from 'crypto';
import { resolve, dirname, isAbsolute } from 'path';
import { createGunzip } from 'zlib';
import { inspect } from 'util';

import vfs from 'vinyl-fs';
import { promisify } from 'bluebird';
import mkdirpCb from 'mkdirp';
import del from 'del';
import { createPromiseFromStreams, createMapStream } from '../../../utils';

import { Extract } from 'tar';
Expand All @@ -26,6 +28,12 @@ function assertAbsolute(path) {
}
}

function longInspect(value) {
return inspect(value, {
maxArrayLength: Infinity
});
}

export async function mkdirp(path) {
assertAbsolute(path);
await mkdirpAsync(path);
Expand Down Expand Up @@ -67,6 +75,22 @@ export async function copy(source, destination) {
await chmodAsync(destination, stat.mode);
}

export async function deleteAll(log, patterns) {
if (!Array.isArray(patterns)) {
throw new TypeError('Expected patterns to be an array');
}

log.debug('Deleting patterns:', longInspect(patterns));

for (const pattern of patterns) {
assertAbsolute(pattern.startsWith('!') ? pattern.slice(1) : pattern);
}

const files = await del(patterns);
log.debug('Deleted %d files/directories', files.length);
log.verbose('Deleted:', longInspect(files));
}

export async function copyAll(sourceDir, destination, options = {}) {
const {
select = ['**/*'],
Expand Down
1 change: 1 addition & 0 deletions src/dev/build/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export {
copyAll,
getFileHash,
untar,
deleteAll,
} from './fs';
38 changes: 29 additions & 9 deletions src/dev/build/tasks/clean_tasks.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import del from 'del';
import { deleteAll } from '../lib';

export const CleanTask = {
global: true,
description: 'Cleaning artifacts from previous builds',

async run(config) {
await del([
async run(config, log) {
await deleteAll(log, [
config.resolveFromRepo('build'),
config.resolveFromRepo('target'),
]);
Expand All @@ -16,15 +16,29 @@ export const CleanPackagesTask = {
description: 'Cleaning source for packages that are now installed in node_modules',

async run(config, log, build) {
await del([build.resolvePath('packages'), build.resolvePath('x-pack')]);
await deleteAll(log, [
build.resolvePath('packages'),
build.resolvePath('x-pack')
]);
},
};

export const CleanTypescriptTask = {
description: 'Cleaning typescript source files that have been transpiled to JS',

async run(config, log, build) {
await deleteAll(log, [
build.resolvePath('**/*.{ts,tsx,d.ts}'),
build.resolvePath('**/tsconfig.json'),
]);
},
};

export const CleanExtraFilesFromModulesTask = {
description: 'Cleaning tests, examples, docs, etc. from node_modules',

async run(config, log, build) {
await del([
await deleteAll(log, [
build.resolvePath('node_modules/**/test/**/*'),
build.resolvePath('node_modules/**/tests/**/*'),
build.resolvePath('node_modules/**/example/**/*'),
Expand All @@ -38,10 +52,16 @@ export const CleanExtraBinScriptsTask = {

async run(config, log, build) {
for (const platform of config.getPlatforms()) {
const patterns = platform.isWindows() ? ['*', '!*.bat'] : ['*.bat'];
await del(patterns, {
cwd: build.resolvePathForPlatform(platform, 'bin')
});
if (platform.isWindows()) {
await deleteAll(log, [
build.resolvePathForPlatform(platform, 'bin', '*'),
`!${build.resolvePathForPlatform(platform, 'bin', '*.bat')}`
]);
} else {
await deleteAll(log, [
build.resolvePathForPlatform(platform, 'bin', '*.bat'),
]);
}
}
}
};
Loading

0 comments on commit f811ba5

Please sign in to comment.