Detect release / debug in gulp using Visual Studio 2015

让人想犯罪 __ 提交于 2019-11-28 18:37:08

In Visual Studio 2015, with the gulp integration, I like @edo limburg and @RamenChef's answer the best.

I have a single page angular app in the same solution as my web api. When building the SPA, I just wanted to replace the URLs to the API and OAuth2 (OIDC) authority servers in an html and a couple of JavaScript files.

I created a gulpfile.js with both a Debug and Release task. Note the case-sensitive spelling:

gulp.task('Debug', function () { 
 gulp.src("./callback.html")
    .pipe(replace(uatAuthority,
                    debugAuthority))
    .pipe(gulp.dest('./'));
...
}
gulp.task('Release', function () {
 gulp.src("./callback.html")
    .pipe(replace(debugAuthority,
                    uatAuthority))
    .pipe(gulp.dest('./'));
)
}

FYI, I included gulp-string-replace to handle the replace tasks:

var replace = require('gulp-string-replace');

After I tested the tasks in the Task Runner Explorer, I unloaded the project file and edited it, adding the following code right before the end project tag:

<Target Name="BeforeBuild">
    <Exec Command="gulp $(Configuration)" />
  </Target>

I know this has been around for awhile but I recently ran into the same issue and was unhappy with the other solutions and workarounds that I found in answers here on SO. I found a very nice solution that we went with in the comments on the aspnet github page: https://github.com/aspnet/Home/issues/1231#issuecomment-182017985

I hope that it helps someone get to a solution they're happier with faster than I did.

Simply, add the following line to your pre-build event in project config

echo {"config" : "$(ConfigurationName)"} > ../buildConfig.json

With that little beauty sitting around you can read it in your tasks and react accordingly. I use it to prevent minifying files when I'm in debug mode like so:

gulp.task("min:js:bundlesFolder", function ()
    {
        var json = fs.readFileSync("./buildConfig.json", "utf8");
        var host = JSON.parse(json.replace(/^\uFEFF/, ''));
        host.isDebug = host.config == "Debug";
        console.log(host.isDebug);
        if (host.isDebug === true)
        {
            return;
        }
        return gulp.src([paths.jsbundleFolder + "/**/*.js", "!" + paths.jsbundleFolder + "/**/*.min.js"])
        .pipe(uglify())
        .pipe(gulp.dest(paths.jsbundleFolder));
    });

In visual studio,

  • create a new console project
  • Install the nugget package 'MSBuild.NodeTools' in your project
  • Unload your .csproj file and edit it by adding the line in the after build target

       <Target Name="AfterBuild">
           <MSBuild.Gulp   GulpFile="path to your gulpfile"/>   
       </Target>
    

Here there is all property you can use :

  • GulpFile: Path to gulpfile. Defaults to $(MSBuildProjectDirectory)\gulpfile.[js|coffee].
  • GulpWorkingDirectory: Directory in which context the gulp task gets executed. Defaults to $(MSBuildProjectDirectory).
  • GulpBuildTask: Gulp task that gets executed on build. Defaults to build-$(Configuration).
  • GulpCleanTask: Gulp task that gets executed on clean. Defaults to unset.

As you can see the task executed takes the name of the configuration in visual studio, so if you build your project in "debug", the task "build-debug" will be executed

You can also doing like this, if you want a custom task :

<Target Name="AfterBuild">
<MSBuild.Gulp  Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"  GulpFile="path to your gulpfile"  GulpBuildTask="CustomDebug"/>
<MSBuild.Gulp  Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU'"  GulpFile="path to your gulpfile"  GulpBuildTask="CustomRelease"/>
</Target>

Disclaimer: I am entirely new to npm, grunt or gulp. However, I think that I found a simple solution using pre-build events.

Add the following line to your pre-build event command line in the project that contains the grunt (or gulp) files:

npm update && grunt $(ConfigurationName)

Now as long as you have grunt tasks with the same name as your build configuration, you should be all set.

grunt.registerTask('Debug', ['sass', 'concat']);
grunt.registerTask('Release', ['sass', 'concat', 'cssmin', 'removelogging', 'uglify']);

You'll need the usual pre-requisites on the machine that is running the build. Remember to restart VS after installing all of this stuff. Visual Studio needs to be run as Administrator in order to execute all all grunt tasks

  • Visual Studio Extenstions - Search for and install through Tools -> Extensions and Updates:
    • Node JS Tools
    • Web Essentials
  • NPM - https://nodejs.org/en/download/
  • Ruby - Installer found here http://rubyinstaller.org/downloads/
    • IMPORTANT: In the installer check off "Add Ruby Executables To Your PATH"
  • Grunt and Sass - Both of these are installed through command prompt (Run as admin)
    • gem install sass
    • npm install -g grunt-cli

The easiest way I've found:

  1. Get your grunt/gulp tasks running using the Task Runner Explorer first by following this guide. Do not set any bindings though.

grunt - https://docs.microsoft.com/en-us/aspnet/core/client-side/using-grunt

gulp - https://docs.microsoft.com/en-us/aspnet/core/client-side/using-gulp

  1. Create Debug and Release grunt/gulp tasks.
  2. Once running with the Task Runner Explorer, copy the command that Visual Studio uses to run your task from the output window of Task Runner Explorer. (Ignore the bindings, do not set these)

  1. Change the paths so that they are relative to the bin folder, and to work with whichever mode is set in Visual Studio. From the image above, you would change the command to:

cmd.exe /c gulp -b ".\.." --color --gulpfile ".\..\Gulpfile.js" $(ConfigurationName)

  1. Paste this command as a pre-build task in your project.

When you're using Visual Studio and your project template is a Blank App (Apache Cordova) and you cannot see any Build Events when you right-click on ProjectName in Solution Explorer and go to Properties like below:

You can then manage your Solution Configuration using Cordova hooks. These are the special scripts injected in your solution to customize cordova commands and are executed with your solution activities/events. For more information, see this.

Steps to follow:

  1. In the root directory of your project, create a new folder (say, 'hooks') containing the hook javascript file (say 'solutionConfigHook.js') as follows:

    "use strict";
    
    // function to run the '_default' task in 'gulpfile.js'
    // based on solution configuration (DEBUG or RELEASE) prior to building the solution
    module.exports = function (context) {
        var config = getConfig(context.cmdLine);
        if (!config) {
            console.log('Unable to determine build environment!');
            return;
        }
        else {
            var exec = require('child_process').exec, child;
            console.log('Runnung Gulp tasks now...');
    
            // 'solutionConfig' is the command line argument for config value passed to the gulpfile
            // '_default' is the task name in *gulpfile.js* that will have access to 'solutionConfig'
            var gulpCommand = 'gulp _default --solutionConfig ' + config.toString(); 
            console.log(gulpCommand);
    
            child = exec(gulpCommand, function (error, stdout, stderr) {
                console.log('stdout: ' + stdout);
                console.log('stderr: ' + stderr);
                if (error !== null) {
                    console.log('exec error: ' + error);
                }
            });
        }
    }    
    
    // function to get the solution configuration using CLI
    function getConfig(cmdLine) {
        var matches = /--configuration (\w+)/.exec(cmdLine);
        if (matches && matches.length > 1) {
            return matches[1];
        }
        return null;
    }
    
  2. Add this hook in your config.xml file as follows for each platform against the desired hook type.

    (For your reference, the code snipped here is for windows platform alone and is called for 'before_build' hook type.)

    <platform name="android">
        ... // other resources or attributes
        <hook src="hooks/solutionConfigHook.js" type="before_build" />
    </platform>
    
  3. In your gulpfile.js, remove the binding of the task(s) by either deleting the reference on top or by going to the Task Runner Explorer and then right-clicking each task and unchecking all bindings.

  4. Add a task in your gulpfile.js that will be called by the hook itself on the activity defined as hook type in config.xml.

    gulp.task('_default', function (solutionConfig) {
        if (solutionConfig == "Release") {
            // perform desired task here
        }
        else if (solutionConfig == "Debug" {
            // perform desired task here
        }
    });
    
Figurys

I'm using the Exec Build task to run a gulp task:

<Target Name="BeforeBuild">
   <Exec Command="gulp beforeBuild --c $(Configuration) --p $(Platform)" />
</Target>

Here is another solution that allows you to pass the configuration as a flag to your gulp task, instead of running the configuration as the task itself. This would allow you to use gulp-if to trigger different procedures from within the task.

Note: This answer assumes that gulp isn't installed globally.

  1. Install gulp as a dev dependency

    npm install gulp --save-dev
    
  2. Register gulp as an npm script

    {
        "name": "vs-build-test",
        ...
        "scripts": {
            "gulp": "gulp"
        }
    }
    
  3. Install yargs to handle custom flags

    npm install yargs --save-dev
    
  4. Require yargs in gulpfiles.js with a default for the configuration flag

    var argv = require('yargs').default('configuration', 'Debug').argv
    
  5. Create a build task in gulpfile.js

    gulp.task('build', function () {
        console.log(`Build Configuration: ${argv.configuration}`);
    });
    
  6. Add a pre-build event to run gulp [Project Properties -> Build Events -> Pre-build Event]

    cmd.exe /c npm run gulp build -- --configuration $(ConfigurationName)
    

The reason this can be useful is so that you can use the same tasks but conditionally run only portions of the process. Take for example a task that builds javascript:

gulp.task('build:js', function () {
    let isProduction = ${argv.configuration} === 'Release';

    ...

    return gulp.src(source)
            .pipe(gulpif(!isProduction, sourcemaps.init()))
            .pipe(concat(outputFile, { newLine: ';' }))
            .pipe(gulpif(isProduction, closure(closureFlags)))
            .pipe(gulpif(!isProduction, sourcemaps.write()))
            .pipe(gulp.dest(basePath));
});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!