I am trying to find a proper configuration for the publishOptions
inside project.json
(ASP.NET Core 1.0 / Full Framework) so that non-minified files are not published.
Official documetation doesn't help much: project.json reference.
Searching for globbing patterns, and finding some artilcles with gulp
examples, I came up with this wwwroot/js/**/*!(*.min.js)
, but it doesn't seem to work.
Is my syntax wrong? Or, it's just that project.json
and dotnet publish
don't support this syntax?
"publishOptions": {
"include": [
"wwwroot",
"Views",
"Areas/**/Views",
"appsettings.json",
"web.config"
],
"exclude": [
"wwwroot/lib",
"wwwroot/js/**/*!(*.min.js)",
"wwwroot/css/*.less",
"wwwroot/_references.js"
],
"includeFiles": [],
"excludeFiles": []
},
The typical workflow for JavaScript files/libraries management is to use gulp or grunt tasks to copy over the necessary files into the wwwroot
folder which may happen on certain events (prebuild, postbuild, project open, clean).
In the latest tooling, the default MVC doesn't include gulpfile.js anymore as the most common usage was to minify and bundle js files, even when no external libraries were used so gulp may be a bit overwhelming for new users.
But it can easily be brought back, when you right-click the bundleconfig.json
file in the solution explorer and choose "Bundler & Minifier" > "Convert to Gulp".
This creates a gulpfile.js
and package.json
(nodejs dependencies) in the root of your project and adds npm folder to the "Dependencies" section of Solution Explorer. When you watch in the Windows Explorer, you'll see a node_modules
folder in the project root folder. That's where npm will download all packages and it's dependencies.
The generated gulpfile.js
looks like this and has a few predefined tasks. i won't use this file as example, as it is strongly based on the bundleconfig.json
and it's structure and use my gulpfile.json
which used to be shipped with older templates.
"use strict";
var gulp = require("gulp"),
rimraf = require("rimraf"),
concat = require("gulp-concat"),
cssmin = require("gulp-cssmin"),
uglify = require("gulp-uglify");
var webroot = "./wwwroot/";
var paths = {
app: webroot + "app/",
libs: webroot + "lib/",
js: webroot + "js/**/*.js",
minJs: webroot + "js/**/*.min.js",
css: webroot + "css/**/*.css",
minCss: webroot + "css/**/*.min.css",
concatJsDest: webroot + "js/app.min.js",
concatCssDest: webroot + "css/app.min.css"
};
gulp.task("clean:js", function (cb) {
rimraf(paths.concatJsDest, cb);
});
gulp.task("clean:libs", function (cb) {
rimraf(paths.libs, cb);
});
gulp.task("clean:css", function (cb) {
rimraf(paths.concatCssDest, cb);
});
gulp.task("clean", ["clean:js", "clean:css", "clean:libs"]);
gulp.task("min:js", function () {
return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
.pipe(concat(paths.concatJsDest))
.pipe(uglify())
.pipe(gulp.dest("."));
});
gulp.task("min:css", function () {
return gulp.src([paths.css, "!" + paths.minCss])
.pipe(concat(paths.concatCssDest))
.pipe(cssmin())
.pipe(gulp.dest("."));
});
gulp.task("min", ["min:js", "min:css"]);
gulp.task("libs", function (cb) {
gulp.src([
'bootstrap/**/*.js',
'bootstrap/**/*.css',
'jquery/**/*.js`, // we can also limit this to `jquery/dist/**/*.js to only include distribution files
'jquery/**/*.css'
], {
cwd: "node_modules/**"
})
.pipe(gulp.dest(paths.libs));
});
gulp.task("app", function (cb) {
gulp.src([
'app/**.js'
])
.pipe(gulp.dest(paths.app));
});
gulp.task("default", ['clean', 'libs']);
It looks more complicated than it actually is. There are several minizier tasks (min:js
, min:css
) and one general minifier task min
which just runs all others in sequence.
A clean task which deletes the output file(s) from wwwroot
. When converting from the template, it deletes only the default wwwroot/js/site.min.js
file.
Since there are no javascript libraries used in the default template, except of what's inside the wwwroot/lib
folder already the packages are not handled that way.
So first thing you may want is to grab bootstrap and jquery from npm rather than the static versions provided by the template. So we add the dependencies to the package.json
.
{
"name": "app",
"version": "0.0.0",
"private": true,
"dependencies": {
"bootstrap": "3.3.6",
"jquery": "2.2.0"
},
"devDependencies": {
"gulp": "3.8.11",
"gulp-concat": "2.5.2",
"gulp-cssmin": "0.1.7",
"gulp-uglify": "1.2.0",
"rimraf": "2.2.8"
}
}
The libs
task from the gulpfile.js
above for example will copy over all required files of a package to wwwroot
. I said required, because in the packages there are often unbundled files for debugging and stuff, which we usually don't want inside wwwroot
(they can grow quite big).
gulp.task("libs", function (cb) {
gulp.src([
'bootstrap/**/*.js',
'bootstrap/**/*.css'
], {
cwd: "node_modules/**"
})
.pipe(gulp.dest(paths.libs));
});
It will look for all *.js
and *.css
files within the bootstrap folder in node_modules
folder and copy them over to path.libs
which is configured as wwwroot/lib/
.
The app
task does the same for our own code. clean
clears the folders and (i.e. before switching from debug to release build or before publishing).
Finally you can bind the tasks to certain VS Events. You need to open the "Task Runner Explorer" View (View > Other Window > Task Runner Explorer). There you can choose a task and right-click it, then "Binding" and choose one of the binding (Before Build, After Build, Clean, Projct Open). They are pretty self explaining, "Clean" means when you do "Build > Clean Solution".
Now to the publishing part. You can run certain command, when you publish your application (either via dotnet or Visual Studio).
In the project.json
there is a scripts section for this.
"scripts": {
"prepublish": [ "npm install", "bower install", "gulp clean", "gulp min", "gulp libs" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
Each of the entries "prepublish" is one command to be executed. In this example, before the publishing begins, npm install
will be executed first in order to restore all npm
dependencies. Then bower install
to install the dependencies managed by bower (remove it if you don't use bower and do all via npm).
The next three commands are the interesting ones, they will execute gulp tasks. We can also simplify this by adding a "publish" task.
gulp.task("publish", ['clean', 'libs', 'min']);
"scripts": {
"prepublish": [ "npm install", "bower install", "gulp publish" ],
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
This will copy all the necessary files for publishment into the wwwroot folder, publish the files and then call the "postpublish" scripts.
That's a rough introduction in gulp. It's has a learning curve, but once you get it working it imrpoves the overall workflow.
What's not covered here is to add a watch
task which may look into a certain folder (I usually use app
folder in the project root) and when any file changes there run the app
task, so the our code gets minifed and copied over to wwwroot
and is available when we debug it.