2
votes

I have a TypeScript project in Visual Studio Code.

After TypeScript is compiled to JavaScript, I'd like the compiled JavaScript to automatically be minified and obfuscated.

They are many minifiers out there, but I'd like to integrate one into the workflow without having to manually run it every time.

The most ideal solution would be a Visual Studio Code extension for that, however I wasn't able to find any - only Minify JavaScript extensions that don't take into account compiling TypeScript beforehand, to the best of my understanding.

Otherwise, I'd like to integrate Gulp into the process, possibly using tasks.json provided by Visual Studio Code. If that's the only way to go, an explanation on how to do that would be great.

I read this article, but I can't say I fully understood how to integrate Gulp with Visual Studio Code in the most appropriate way for what I'm trying to do. I never worked with Gulp before.

https://code.visualstudio.com/docs/editor/tasks

1

1 Answers

3
votes

Indeed gulp - in this case - is what you need. There are some other javascript task automators but I guess gulp is a good choice. With gulp you are able to compile your typescript and scss files, copy resources like images and so on.

First you need to install gulp via npm

npm install gulp --save-dev

furthermore you need "gulp sourcemaps" for compiling typescript "gulp-typescript", for compiling scss "gulp-sass", and "gulp-minify" for minifying:

npm install gulp-sourcemaps gulp-typescript gulp-sass gulp-minify

My source (typescript files) are in "/src/client" and the compiled project should be in "/dist/client", also I delete the dist folder every time before building the project again. I think its cleaner. For this you will also need the "del" module

npm install del

Now its time to build your gulpfile.js with your tasks, this badass should start with importing your modules:

var _gulp = require('gulp')
var _sourcemaps = require('gulp-sourcemaps')
var _typescript = require('gulp-typescript')
var _sass = require("gulp-sass")
var _minify = require('gulp-minify');

Then, the first task should be cleaning:

_gulp.task('clean-frontend', function(done) {
    return _del(['./dist/client'], done);
});

Here you create a gulp task called "clean-frontend". All you do here is to remove the "dist/client" directory.

The Next task is to copy your frontend resources like images, or stuff like that in our client directory - in short: everything that is no scss, or typescript file. You call your task "copy-frontend-resources" and create it with:

_gulp.task('copy-frontend-resources', () => {
     _gulp.src([config.frontend.sourceFolder + '/**/*', "!**/*.ts", "!**/*.scss"]).pipe(_gulp.dest('./dist/client'))
})

The next step is to copy your javascript libraries you use like underscore, angular, jquery, systemjs, and what ever you need. If you need a library like underscore in the browser frontend you simply install it with npm like:

npm install underscore

after that you can import it in your typescript files (import * as _ from "underscore") and use it in development. The browser has no access to your /node_modules folder in the project root directory, because his root directory is /dist/client and because of this you will need to copy your libraries as well. For that you create an array of npm modules you use like:

let usedLibs = [
    'systemjs/dist/*.js',
    '@angular/**/bundles/**',
    'rxjs/**/*.js',
    'zone.js/dist/*.js',
    'reflect-metadata/*.js',
    'jquery/dist/*.js',
    'underscore/*.js'
]

You just have to check for every library where its javascript files are located, as you can see systemjs has his in /dist, while underscore has his in his root. Okay, now let's do the task which will copy all of the libraries of the node_modules to the "/dist/client/lib" folder:

_gulp.task('copy-frontend-libraries', () => {
    _gulp.src(usedLibs, {
        cwd: "node_modules/**"
    }).pipe(_gulp.dest('./dist/client/lib'));
})

The Next task is pretty simple, it compiles all scss in our "src/client" folder to css files:

_gulp.task('build-frontend-css', () => {
    _gulp.src(['src/client/**/*.scss'])
        .pipe(_sass({ style: 'expanded' }))
        .pipe(_gulp.dest('./dist/client'));
})

The last task is compiling the typescript files, you can adjust the compiler properties to your needs:

let compilerOptions = {
    removeComments: true,
    target: "es6",
    moduleResolution: "node",
    module: "commonjs", // you can choose "AMD" too
    experimentalDecorators : true,
    allowSyntheticDefaultImports : true
}

And create the task:

_gulp.task('build-frontend-angular', () => {
    var typescriptProject = _typescript.createProject(compilerOptions);
    var typescriptResult = _gulp.src(['./src/client/**/*.ts'])
        .pipe(_sourcemaps.init())
        .pipe(typescriptProject())
        .pipe(_sourcemaps.write())
        .pipe(_gulp.dest('./dist/client_debug'))
})

Note, that you copy your files here to "client_debug" directory, because you want to minify them before copying in the client folder. The minifier does its job with:

_gulp.task('compress-frontend', function() {
  _gulp.src('./dist/client_debug/*.js')
    .pipe(_minify({
        ext:{
            src:'-debug.js',
            min:'.js'
        },
    }))
    .pipe(_gulp.dest('./dist/client'))
});

Now we have all our tasks complete and need a function to run all of them at once and we do that with creating a root task called "build". Note, that the "clean-frontend" is not inside the gulp.start array, it caused an error (gulp.start runs all at once and not one after another):

_gulp.task('build', [
    'clean-frontend',
], (done) => {
    // Alles gecleaned, weiter mit build
    _gulp.start(
        [
            'copy-frontend-resources', 
            'copy-frontend-libraries',
            'build-frontend-css',
            'build-frontend-angular',
            'compress-frontend'
        ], () => {
            done()
        }
    )
});

Okay! Puh, long way, but now we want to test it! Lets go into the command line and cd in your project directory. Here you can run now every gulp task from the gulpfile.js with gulp NAMEOFTASK in our example: gulp build but you could also run one of the single tasks like gulp compress-frontend.

The last step would be adding a watcher, which does all the stuff above automated if you change a file in your src directory. For this case you would add another task like:

_gulp.task('watch', function () {
    // Watch frontend
    _gulp.watch(
        ['./src/**/*'], 
        [
            'copy-frontend-resources', 
            'build-frontend-css',
            'build-frontend-angular',
            'compress-frontend'
        ]
    ).on('change', function (e) {
        console.log('File ' + e.path + ' has been changed. Updating/Compiling.');
    });
});

The task "copy-frontend-libraries" won't be needed here, because I guess you did not changed something inside the npm modules. You can run the watch task with

gulp watch

You see, there is no really "integrating" in VS studio code, all you do is to use the terminal of it and run "gulp watch", or "gulp build". That's all.

BUT! There's more! More cooler is it when you modify your package.json to something linke that:

(...)
"scripts": {
    "build": "gulp build",
    "watch": "gulp watch",
}
(...)

Now you can run "npm run build" or "npm run watch". instead of the gulp command.

I hope I could help!