2

How to setup a web project with elm in visual studio 2015?

We started a new project and we need it in visual studio for the continuous integration and build deploy to a certain server.

My issue is that I didn't found a elm project template and I've only heard about elm these days, so it's something new for me also.

Any help would be appreciated.

Buda Gavril
  • 21,409
  • 40
  • 127
  • 196

2 Answers2

2

We came up with a structure where our UI is a separate project and completely written in Elm while the backend is in ASP.NET. The whole thing is in one Visual Studio solution and can be compiled using VS2015 or MSBuild in TeamCity.

We use VS Code for developing the UI though. I do not know of any Visual Studio support for Elm.

This is the project file (YourUI.csproj) that is included in the UI project:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ProjectGuid>{B9D43DC2-6337-4605-BBE2-7C7C765EDC20}</ProjectGuid>
    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <BuildTask>build:dev</BuildTask>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <BuildTask>build:release</BuildTask>
  </PropertyGroup>
  <Target Name="Build">
    <Exec Command="echo Executing npm install..." Condition="!Exists('$(ProjectDir)node_modules')" />
    <Exec Command="npm install" Condition="!Exists('$(ProjectDir)node_modules')" />     
    <Exec Command="echo Building the UI using GULP..." />
    <Exec Command="echo ---------------------------------------------" />
    <Exec Command="gulp $(BuildTask)" />
    <Exec Command="echo ---------------------------------------------" />
  </Target>
  <Target Name="Clean">
    <Exec Command="gulp clean:all" />
  </Target>
  <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
  <ItemGroup>
    <None Include="readme.md" />
  </ItemGroup>
</Project>

As you can see, in the background we use npm and gulp to do the actual work. The important pieces from our gulp file (including the Elm CSS generation and WebPack bundling):

gulp.task('elm-init', function (cb) {
    return gulp.src('src/*.elm')
        .pipe(elm())
        .pipe(gulp.dest('JS/generated'));
});

gulp.task('elm:dev', ['elm-init'], function (cb) {
    return gulp.src('src/main.elm')
        .pipe(elm.bundle('elm.js'), {
            debug: true
        })
        .pipe(gulp.dest('JS/generated'));
});
gulp.task('elm:release', ['elm-init'], function (cb) {
    return gulp.src('src/main.elm')
        .pipe(elm.bundle('elm.js'))
        .pipe(gulp.dest('JS/generated'));
});

bundle = function () {
    return gulp.src('JS/index.js')
        .pipe(webpackGulp({
            output: {
                filename: 'Ui.js',
            }
        }))
        .pipe(gulp.dest('build/'));
}
gulp.task('bundle:dev', [/*project spcific things, */ 'elm:dev'], bundle);
gulp.task('bundle:release', [/*project spcific things, */ 'elm:release'], bundle);

gulp.task('css', function (cb) {
    mkdirp('build/css', function (err) {
        if (err) console.error(err)
    });

    exec(path.resolve('./node_modules/.bin/elm-css')
        + ' --pathToMake ./node_modules/.bin/elm-make'
        + ' src/Stylesheets.elm',
        function (err, stdout, stderr) {
            console.log(stdout);
            console.log(stderr);
            cb(err);
        });
});

gulp.task('build:dev', function (cb) {
    runSequence('clean:dev', 'bundle:dev', 'css');
});

The ASP.NET project file contains the following BeforeBuild instructions:

  <Target Name="BeforeBuild">
    <MSBuild 
        Projects="..\YourUI\YourUI.csproj"
        Condition="'$(Configuration)'=='Release' OR !(Exists('$(SolutionDir)YourUI\build\Ui.js') AND Exists('$(SolutionDir)YourUI\build\css'))" 
        Targets="Build" />
    <Exec Command="echo Creating UI resources for $(Configuration)..." />
    <!-- Delete old links -->
    <Delete Files="$(ProjectDir)Scripts\Ui.js" />
    <Delete Files="$(ProjectDir)Scripts\Ui.min.js" />
    <RemoveDir Directories="$(ProjectDir)Content\Ui" />
    <!---->
    <!---->
    <!-- DEBUG build-->
    <!---->
    <Exec Condition=" '$(Configuration)'=='Debug' " Command="mklink $(ProjectDir)Scripts\Ui.js $(SolutionDir)YourUI\build\Ui.js" />
    <Exec Condition=" '$(Configuration)'=='Debug' " Command="mklink /d $(ProjectDir)Content\Ui $(SolutionDir)YourUI\build\css" />
    <!---->
    <!---->
    <!-- RELEASE build-->
    <!---->
    <ItemGroup Condition=" '$(Configuration)'!='Debug' ">
      <ElmApp Include="$(SolutionDir)YourUI\build\Ui.min.js" />
      <ElmStyles Include="$(SolutionDir)YourUI\build\css\*.css" />
    </ItemGroup>
    <Copy Condition=" '$(Configuration)'!='Debug' " SourceFiles="@(ElmApp)" DestinationFolder="$(ProjectDir)Scripts" />
    <Copy Condition=" '$(Configuration)'!='Debug' " SourceFiles="@(ElmStyles)" DestinationFolder="$(ProjectDir)Content\Ui" />
  </Target>
  <!-- Include the new files as content -->
  <ItemGroup Condition=" '$(Configuration)'=='Debug' ">
    <Content Include="Scripts\Ui.js" />
    <Content Include="Content\Ui\*.css" />
  </ItemGroup>
  <ItemGroup Condition=" '$(Configuration)'!='Debug' ">
    <Content Include="Scripts\Ui.min.js" />
    <Content Include="Content\Ui\*.css" />
  </ItemGroup>
Gabor
  • 1,656
  • 1
  • 16
  • 28
1

It doesn't technically need to be in Visual Studio 2015 to be part of continuous integration or development. For editing, you'll probably have less friction using Visual Studio Code (or other editors like Sublime, Vim, Atom, etc).

However, if you still want it tied into the Visual Studio 2015 ecosystem, you're going to want to use Task Runner integration. You already have grunt and gulp task runners built into the IDE. You could create a gulp task and use gulp-elm to automatically watch and compile your Elm code.

Personally, I'm a fan of Webpack for Elm development. With an additional Visual Studio 2015 plugin for Webpack task runners, you should be able to tie it together nicely. (caveat: I haven't personally tried that combination but it looks legitimate)

Chad Gilbert
  • 36,115
  • 4
  • 89
  • 97
  • is it possible to create a task that compiles and also launches the page in the browser? I have setup the tasks to compile, watch and connect, but I'm not able to make it start in the browser when I start the task (http://stackoverflow.com/questions/40914056/gulp-build-the-code-and-start-it-in-the-browser) – Buda Gavril Dec 02 '16 at 08:05
  • I've provided an answer on that question with two options, [`gulp-connect-multi`](https://www.npmjs.com/package/gulp-connect-multi) and [`gulp-open`](https://www.npmjs.com/package/gulp-open) – Chad Gilbert Dec 02 '16 at 12:10