Add tasks for building typescript-code
This commit is contained in:
parent
bdb2e4e02f
commit
f1906b03cd
14 changed files with 2179 additions and 4 deletions
|
@ -2,5 +2,8 @@
|
|||
"name": "SilverStripe Environment",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "silverstripe",
|
||||
"workspaceFolder": "/vscode/src/mantra"
|
||||
"workspaceFolder": "/vscode/src/mantra",
|
||||
"extensions": [
|
||||
"ms-vscode.vscode-typescript-tslint-plugin"
|
||||
]
|
||||
}
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -51,6 +51,9 @@ typings/
|
|||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Output of 'composer archive'
|
||||
*.tar
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
|
@ -77,3 +80,6 @@ vendor/
|
|||
|
||||
# MySQL cache
|
||||
.devcontainer/mysql-data
|
||||
|
||||
# Build files
|
||||
/javascript/
|
||||
|
|
126
.gulp/Settings.ts
Normal file
126
.gulp/Settings.ts
Normal file
|
@ -0,0 +1,126 @@
|
|||
import Path = require("upath");
|
||||
|
||||
/**
|
||||
* Provides settings for building the project.
|
||||
*/
|
||||
export class Settings
|
||||
{
|
||||
/**
|
||||
* A value indicating whether the project should be built in watched mode.
|
||||
*/
|
||||
public Watch = false;
|
||||
|
||||
/**
|
||||
* The target of the project-build.
|
||||
*/
|
||||
public Target: string;
|
||||
|
||||
/**
|
||||
* The path to the source-code root.
|
||||
*/
|
||||
private sourceRoot = "src";
|
||||
|
||||
/**
|
||||
* The path to the root of the typescript-project.
|
||||
*/
|
||||
private typeScriptProjectRoot = "App";
|
||||
|
||||
/**
|
||||
* The path to the root of the typescript-source.
|
||||
*/
|
||||
private typeScriptSourceRoot = "src";
|
||||
|
||||
/**
|
||||
* The path to save the javascript-code to.
|
||||
*/
|
||||
private libraryPath = "javascript";
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the `Settings` class.
|
||||
*
|
||||
* @param target
|
||||
* The target of the project-build.
|
||||
*/
|
||||
public constructor(target: string)
|
||||
{
|
||||
this.Target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* A value indicating whether the debug-mode is enabled.
|
||||
*/
|
||||
public get Debug()
|
||||
{
|
||||
return this.Target === "Debug";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a path relative to the root of the solution.
|
||||
*
|
||||
* @param path
|
||||
* The path to join.
|
||||
*
|
||||
* @return
|
||||
* The joined path.
|
||||
*/
|
||||
public RootPath(...path: string[])
|
||||
{
|
||||
return Path.join(Path.dirname(__dirname), ...path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a path relative to the root of the source-code.
|
||||
*
|
||||
* @param path
|
||||
* The path to join.
|
||||
*
|
||||
* @returns
|
||||
* The joined path.
|
||||
*/
|
||||
public SourceRoot(...path: string[])
|
||||
{
|
||||
return this.RootPath(this.sourceRoot, ...path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a path relative to the root of the typescript-project.
|
||||
*
|
||||
* @param path
|
||||
* The path to join.
|
||||
*
|
||||
* @returns
|
||||
* The joined path.
|
||||
*/
|
||||
public TypeScriptProjectRoot(...path: string[])
|
||||
{
|
||||
return this.SourceRoot(this.typeScriptProjectRoot, ...path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a path relative to the root of the typescript-source.
|
||||
*
|
||||
* @param path
|
||||
* The path to join.
|
||||
*
|
||||
* @returns
|
||||
* The joined path.
|
||||
*/
|
||||
public TypeScriptSourceRoot(...path: string[])
|
||||
{
|
||||
return this.TypeScriptProjectRoot(this.typeScriptSourceRoot, ...path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a path relative to the directory to save the javascript-code to.
|
||||
*
|
||||
* @param path
|
||||
* The path to join.
|
||||
*
|
||||
* @returns
|
||||
* The joined path.
|
||||
*/
|
||||
public LibraryPath(...path: string[])
|
||||
{
|
||||
return this.RootPath(this.libraryPath, ...path);
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import { TaskFunction } from "gulp";
|
|||
*/
|
||||
declare global
|
||||
{
|
||||
// tslint:disable-next-line: completed-docs
|
||||
interface Function extends TaskFunction
|
||||
{ }
|
||||
}
|
||||
|
|
14
.vscode/extensions.json
vendored
Normal file
14
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||
"ms-vscode-remote.remote-containers"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
|
||||
]
|
||||
}
|
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
|
||||
"javascript.format.placeOpenBraceOnNewLineForControlBlocks": true,
|
||||
"javascript.format.placeOpenBraceOnNewLineForFunctions": true,
|
||||
"typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
|
||||
"typescript.format.placeOpenBraceOnNewLineForControlBlocks": true,
|
||||
"typescript.format.placeOpenBraceOnNewLineForFunctions": true
|
||||
}
|
|
@ -36,12 +36,18 @@
|
|||
"archive": {
|
||||
"exclude": [
|
||||
"/*.tar",
|
||||
".devcontainer",
|
||||
".gulp",
|
||||
".gitignore",
|
||||
".vscode/",
|
||||
"gulpfile.ts",
|
||||
"node_modules/",
|
||||
"package-lock.json",
|
||||
"package.json",
|
||||
"test/"
|
||||
"src/",
|
||||
"test/",
|
||||
"tsconfig.json",
|
||||
"tslint.json"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
|
|
280
gulpfile.ts
280
gulpfile.ts
|
@ -1,5 +1,80 @@
|
|||
import browserify = require("browserify");
|
||||
import log = require("fancy-log");
|
||||
import gulp = require("gulp");
|
||||
import { TaskFunction } from "gulp";
|
||||
import gulpIf = require("gulp-if");
|
||||
import terser = require("gulp-terser");
|
||||
import merge = require("merge-stream");
|
||||
import minimist = require("minimist");
|
||||
import { Server, Socket } from "net";
|
||||
import PromiseQueue = require("promise-queue");
|
||||
import { parseArgsStringToArgv } from "string-argv";
|
||||
import Path = require("upath");
|
||||
import buffer = require("vinyl-buffer");
|
||||
import vinylSourceStream = require("vinyl-source-stream");
|
||||
import Watchify = require("watchify");
|
||||
import { Settings } from "./.gulp/Settings";
|
||||
import "./.gulp/TaskFunction";
|
||||
|
||||
/**
|
||||
* The port to listen for stop-requests.
|
||||
*/
|
||||
const watchConnectorPort = 50958;
|
||||
|
||||
/**
|
||||
* The message that is printed when starting the compilation in watch mode.
|
||||
*/
|
||||
const watchStartMessage = "Starting compilation in watch mode...";
|
||||
|
||||
/**
|
||||
* The message that is printed when starting an incremental compilation.
|
||||
*/
|
||||
const incrementalMessage = "File change detected. Starting incremental compilation...";
|
||||
|
||||
/**
|
||||
* Generates the message that is printed after finishing a compilation in watch mode.
|
||||
*
|
||||
* @param errorCount
|
||||
* The number of errors which occurred.
|
||||
*/
|
||||
const watchFinishMessage = (errorCount: number) =>
|
||||
{
|
||||
return `Found ${errorCount} errors. Watching for file changes.`;
|
||||
};
|
||||
|
||||
/**
|
||||
* The arguments passed by the user.
|
||||
*/
|
||||
let options = ParseArgs(process.argv.slice(2));
|
||||
|
||||
/**
|
||||
* Parses the specified arguments.
|
||||
*
|
||||
* @param args
|
||||
* The arguments to parse.
|
||||
*/
|
||||
function ParseArgs(args: string[])
|
||||
{
|
||||
return minimist(
|
||||
args,
|
||||
{
|
||||
string: [
|
||||
"target"
|
||||
],
|
||||
alias: {
|
||||
target: "t"
|
||||
},
|
||||
default: {
|
||||
target: "Debug"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings for building the project.
|
||||
*/
|
||||
let settings = new Settings(options["target"]);
|
||||
|
||||
/**
|
||||
* Initializes the project.
|
||||
*/
|
||||
|
@ -8,4 +83,207 @@ export function Initialize(done: () => void)
|
|||
done();
|
||||
}
|
||||
|
||||
Initialize.description = "Initializes the project.";
|
||||
Initialize.description = "Initializes the project.";
|
||||
|
||||
/**
|
||||
* Builds the project in watched mode.
|
||||
*/
|
||||
export let Watch: TaskFunction = (done) =>
|
||||
{
|
||||
settings.Watch = true;
|
||||
Build();
|
||||
|
||||
let server = new Server(
|
||||
(socket) =>
|
||||
{
|
||||
socket.on(
|
||||
"data",
|
||||
(data) =>
|
||||
{
|
||||
let args = parseArgsStringToArgv(data.toString());
|
||||
socket.destroy();
|
||||
|
||||
if (args[0] === "stop")
|
||||
{
|
||||
let options = ParseArgs(args.slice(1));
|
||||
|
||||
if (options["target"] === settings.Target)
|
||||
{
|
||||
server.close();
|
||||
done();
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(watchConnectorPort);
|
||||
};
|
||||
|
||||
Watch.description = "Builds the project in watched mode.";
|
||||
|
||||
/**
|
||||
* Builds the project.
|
||||
*/
|
||||
export async function Build()
|
||||
{
|
||||
if (settings.Watch)
|
||||
{
|
||||
log.info(watchStartMessage);
|
||||
}
|
||||
|
||||
Library();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the TypeScript- and JavaScript-library.
|
||||
*/
|
||||
export async function Library()
|
||||
{
|
||||
let streams: Array<Promise<NodeJS.ReadWriteStream>> = [];
|
||||
let queue = new PromiseQueue();
|
||||
let tsConfigFile = settings.TypeScriptProjectRoot("tsconfig.json");
|
||||
let tsConfig = require(tsConfigFile);
|
||||
|
||||
let optionBase: browserify.Options = {
|
||||
...Watchify.args,
|
||||
node: true,
|
||||
ignoreMissing: true,
|
||||
debug: settings.Debug
|
||||
};
|
||||
|
||||
{
|
||||
let errorMessages: string[] = [];
|
||||
let files = (tsConfig.files as string[]).map(
|
||||
(file) => Path.relative(settings.TypeScriptSourceRoot(), settings.TypeScriptProjectRoot(file)));
|
||||
|
||||
for (let file of files)
|
||||
{
|
||||
let bundler = browserify(
|
||||
{
|
||||
...optionBase,
|
||||
basedir: settings.LibraryPath(Path.dirname(file)),
|
||||
entries: [
|
||||
settings.TypeScriptSourceRoot(file)
|
||||
],
|
||||
standalone: Path.join(Path.dirname(file), Path.parse(file).name)
|
||||
});
|
||||
|
||||
if (settings.Watch)
|
||||
{
|
||||
bundler = Watchify(bundler);
|
||||
}
|
||||
|
||||
bundler.plugin(
|
||||
require("tsify"),
|
||||
{
|
||||
project: tsConfigFile
|
||||
});
|
||||
|
||||
let bundle = async () =>
|
||||
{
|
||||
return new Promise<NodeJS.ReadWriteStream>(
|
||||
(resolve) =>
|
||||
{
|
||||
let stream = bundler.bundle().on(
|
||||
"error",
|
||||
(error) =>
|
||||
{
|
||||
let message: string = error.message;
|
||||
|
||||
if (!errorMessages.includes(message))
|
||||
{
|
||||
errorMessages.push(message);
|
||||
log.error(message);
|
||||
}
|
||||
}
|
||||
).pipe(
|
||||
vinylSourceStream(Path.changeExt(file, "js"))
|
||||
).pipe(
|
||||
buffer()
|
||||
).pipe(
|
||||
gulpIf(
|
||||
settings.Debug,
|
||||
terser()
|
||||
)
|
||||
).pipe(
|
||||
gulp.dest(settings.LibraryPath())
|
||||
);
|
||||
|
||||
stream.on(
|
||||
"end",
|
||||
() =>
|
||||
{
|
||||
if (settings.Watch && ((queue.getQueueLength() + queue.getPendingLength()) === 1))
|
||||
{
|
||||
log.info(watchFinishMessage(errorMessages.length));
|
||||
}
|
||||
|
||||
errorMessages.splice(0, errorMessages.length);
|
||||
resolve(stream);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (settings.Watch)
|
||||
{
|
||||
bundler.on(
|
||||
"update",
|
||||
() =>
|
||||
{
|
||||
if ((queue.getQueueLength() + queue.getPendingLength()) === 0)
|
||||
{
|
||||
log.info(incrementalMessage);
|
||||
}
|
||||
|
||||
queue.add(
|
||||
async () =>
|
||||
{
|
||||
return bundle();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let build = () => queue.add(bundle);
|
||||
build.displayName = Build.displayName;
|
||||
build.description = Build.description;
|
||||
streams.push(build());
|
||||
}
|
||||
}
|
||||
|
||||
return merge(await Promise.all(streams)) as NodeJS.ReadWriteStream;
|
||||
}
|
||||
|
||||
Library.description = "Builds the TypeScript- and JavaScript-library.";
|
||||
|
||||
/**
|
||||
* Stops a watch-task.
|
||||
*/
|
||||
export async function Stop()
|
||||
{
|
||||
try
|
||||
{
|
||||
await new Promise(
|
||||
(resolve, reject) =>
|
||||
{
|
||||
let client = new Socket();
|
||||
|
||||
client.connect(
|
||||
watchConnectorPort,
|
||||
"localhost",
|
||||
async () =>
|
||||
{
|
||||
client.write(`stop -t ${settings.Target}`);
|
||||
});
|
||||
|
||||
client.on("close", resolve);
|
||||
client.on("error", reject);
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
log.info("The specified task is not running.");
|
||||
}
|
||||
}
|
||||
|
||||
Stop.description = "Stops a watch-task";
|
1660
package-lock.json
generated
1660
package-lock.json
generated
File diff suppressed because it is too large
Load diff
35
package.json
35
package.json
|
@ -5,9 +5,42 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@manuth/tsconfig": "^1.2.2",
|
||||
"@manuth/tslint-presets": "^1.0.4",
|
||||
"@types/bootstrap": "^4.3.1",
|
||||
"@types/browserify": "^12.0.36",
|
||||
"@types/fancy-log": "^1.3.1",
|
||||
"@types/gulp": "^4.0.6",
|
||||
"@types/gulp-if": "0.0.33",
|
||||
"@types/gulp-terser": "^1.2.0",
|
||||
"@types/jquery": "^3.3.31",
|
||||
"@types/merge-stream": "^1.1.2",
|
||||
"@types/minimist": "^1.2.0",
|
||||
"@types/node": "^12.7.11",
|
||||
"@types/promise-queue": "^2.2.0",
|
||||
"@types/vinyl-buffer": "^1.0.0",
|
||||
"@types/vinyl-source-stream": "0.0.30",
|
||||
"@types/watchify": "^3.7.4",
|
||||
"bootstrap": "^4.3.1",
|
||||
"browserify": "^16.5.0",
|
||||
"fancy-log": "^1.3.3",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-if": "^3.0.0",
|
||||
"gulp-terser": "^1.2.0",
|
||||
"jquery": "^3.4.1",
|
||||
"merge-stream": "^2.0.0",
|
||||
"minimist": "^1.2.0",
|
||||
"popper.js": "^1.15.0",
|
||||
"promise-queue": "^2.2.5",
|
||||
"string-argv": "^0.3.1",
|
||||
"ts-node": "^8.4.1",
|
||||
"typescript": "^3.6.3"
|
||||
"tsify": "^4.0.1",
|
||||
"tslint": "^5.20.0",
|
||||
"typescript": "^3.6.3",
|
||||
"typescript-tslint-plugin": "^0.5.4",
|
||||
"upath": "^1.2.0",
|
||||
"vinyl-buffer": "^1.0.1",
|
||||
"vinyl-source-stream": "^2.0.0",
|
||||
"watchify": "^3.11.1"
|
||||
}
|
||||
}
|
||||
|
|
3
src/App/src/main.ts
Normal file
3
src/App/src/main.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import "bootstrap";
|
||||
import "jquery";
|
||||
import "popper.js";
|
13
src/App/tsconfig.json
Normal file
13
src/App/tsconfig.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"files": [
|
||||
"src/main.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"lib": [
|
||||
"es7",
|
||||
"dom"
|
||||
],
|
||||
"target": "es5"
|
||||
}
|
||||
}
|
18
tsconfig.json
Normal file
18
tsconfig.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"extends": "@manuth/tsconfig/recommended",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es7"
|
||||
],
|
||||
"plugins": [
|
||||
{
|
||||
"name": "typescript-tslint-plugin"
|
||||
}
|
||||
],
|
||||
"target": "es5"
|
||||
},
|
||||
"files": [
|
||||
"./gulpfile.ts"
|
||||
]
|
||||
}
|
6
tslint.json
Normal file
6
tslint.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "@manuth/tslint-presets/recommended",
|
||||
"rules": {
|
||||
"interface-name": false
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue