-
Notifications
You must be signed in to change notification settings - Fork 0
Bundling
Provides necessary tools to bundle frontend resources (scripts and styles) and serve them either unbundled in development mode or bundled in production.
- DevGuild.AspNetCore.Services.Bundling
Add following line to Configure method of Startup class to add required service to dependency injection container:
services.AddBundling(this.Configuration.GetSection("Bundling"));Add following section to appsettings.json configuration file:
"Bundling": {
"Enabled": false
}This setup will configure bundling in a disabled state - instead of serving content bundles, the service will serve the original files to simplify debug and development.
This mode should be used in development environment only. All deployments (both production and test instances) should be configured to enable bundling.
Bundling configuration is defined in bundles.json file in the application root with following structure:
- styles - array of objects, representing styles bundles with following structure:
- output - string - path to generated bundle file.
- input - array of strings - paths to source files.
- options - object that represents styles bundling options:
- minify - true if styles should be minified, false otherwise.
- scripts - array of objects, representing scripts bundles with following structure:
- output - string - path to generated bundle file.
- input - array of strings - paths to source files.
- options - object that represents scripts bundling options:
- uglify - uglify options:
- enabled - true if uglify should be used to process the scripts, otherwise false.
- options - object that should be passed as options to uglify.
- uglify - uglify options:
- copy - array of objects, that defines files that need to be copied to make sure that relative links (e.g. to fonts) keep working after bundling.
- sass - array of strings, that defines files or wildcard paths that need to be processed by sass compiler.
Note: at the moment, wildcards are only supported in copy and sass sections. Support in styles and scripts is coming soon.
{
"styles": [
{
"output": "wwwroot/css/bundle.min.css",
"input": [
"wwwroot/css/layout/layout.css",
"wwwroot/css/crud/shared.css",
"wwwroot/css/crud/index.css"
],
"options": {
"minify": true
}
},
{
"output": "wwwroot/vendor/vendor.min.css",
"input": [
"wwwroot/lib/bootstrap/dist/css/bootstrap.css",
"wwwroot/lib/Font-Awesome/web-fonts-with-css/css/fontawesome-all.css"
],
"options": {
"minify": true
}
}
],
"scripts": [
{
"output": "wwwroot/js/app/routing.min.js",
"input": [
"wwwroot/lib/devguild.aspnet-routing/routing-core.js",
"wwwroot/js/app/routing/pages/home.js",
"wwwroot/js/app/routing/app.js"
],
"options": {
"uglify": {
"enabled": true,
"options": null
}
}
},
{
"output": "wwwroot/vendor/vendor.min.js",
"input": [
"wwwroot/lib/es6-shim/es6-shim.js",
"wwwroot/lib/fetch/fetch.js",
"wwwroot/lib/jquery/dist/jquery.js",
"wwwroot/lib/jquery-validation/dist/jquery.validate.js",
"wwwroot/lib/jquery-validation-unobtrusive/src/jquery.validate.unobtrusive.js",
"wwwroot/lib/popper.js/dist/umd/popper.js",
"wwwroot/lib/bootstrap/dist/js/bootstrap.js",
"wwwroot/lib/bootstrap-datepicker/dist/js/bootstrap-datepicker.js"
],
"options": {
"uglify": {
"enabled": true,
"options": null
}
}
}
],
"copy": [
{
"src": "wwwroot/lib/Font-Awesome/web-fonts-with-css/webfonts/*.*",
"dest": "wwwroot/webfonts/"
}
],
"sass": [
"wwwroot/css/**/*.scss"
]
}To implement actual bundling, the gulp tool should be used with the following gulpfile.js:
"use strict";
// ReSharper disable PossiblyUnassignedProperty
// ReSharper disable UndeclaredGlobalVariableUsing
// ReSharper disable Es6Feature
// ReSharper disable IdentifierTypo
// ReSharper disable StringLiteralTypo
(() => {
const gulp = require("gulp");
const sass = require("gulp-sass");
const concat = require("gulp-concat");
const cssmin = require("gulp-cssmin");
const uglify = require("gulp-uglify");
const merge = require("merge-stream");
const del = require("del");
const through = require("through2");
const log = require("fancy-log");
const colors = require("ansi-colors");
const path = require("path");
const config = require("./bundles.json");
function compileSass(done) {
if (!(config.sass && Array.isArray(config.sass) && config.sass.length > 0)) {
done();
return undefined;
}
const tasks = config.sass.map(f => gulp
.src(f)
.pipe(verbose(chunk => `Compiling SASS: '${colors.green(chunk.path)}'`))
.pipe(sass())
.pipe(gulp.dest(f => f.base)));
return merge(tasks);
}
function copyFiles(done) {
if (!(config.copy && Array.isArray(config.copy) && config.copy.length > 0)) {
done();
return undefined;
}
const tasks = config.copy.map(f => gulp
.src(f.src)
.pipe(verbose(chunk => `Copying file '${colors.green(path.relative(chunk.cwd, chunk.path))}' to '${colors.green(f.dest)}'`))
.pipe(gulp.dest(f.dest)));
return merge(tasks);
}
function bundleScripts(done) {
if (!(config.scripts && Array.isArray(config.scripts) && config.scripts.length > 0)) {
done();
return undefined;
}
const tasks = config.scripts.map(bundle => {
let builder = gulp.src(bundle.input, { base: "." }).pipe(concat(bundle.output));
builder = builder.pipe(verbose(chunk => `Bundling '${colors.green(bundle.output)}'`));
if (bundle.options && bundle.options.uglify) {
builder = builder.pipe(uglify(bundle.options.uglify.options ? bundle.options.uglify.options : undefined));
}
builder = builder.pipe(gulp.dest("."));
return builder;
});
return merge(tasks);
}
function bundleStyles(done) {
if (!(config.styles && Array.isArray(config.styles) && config.styles.length > 0)) {
done();
return undefined;
}
const tasks = config.styles.map(bundle => {
let builder = gulp.src(bundle.input, { base: "." }).pipe(concat(bundle.output));
builder = builder.pipe(verbose(chunk => `Bundling '${colors.green(bundle.output)}'`));
if (bundle.options && bundle.options.minify) {
builder = builder.pipe(cssmin());
}
builder = builder.pipe(gulp.dest("."));
return builder;
});
return merge(tasks);
}
bundleStyles.displayName = "bundle:css:process";
function watch() {
config.scripts.forEach(bundle => {
gulp.watch(bundle.input, gulp.series("bundle:js"));
});
config.styles.forEach(bundle => {
gulp.watch(bundle.input, gulp.series("bundle:css"));
});
config.sass.forEach(pattern => {
gulp.watch(pattern, gulp.series("sass"));
});
}
function watchSass() {
config.sass.forEach(pattern => {
gulp.watch(pattern, gulp.series("sass"));
});
}
gulp.task("sass", compileSass);
gulp.task("copy", copyFiles);
gulp.task("bundle:js", bundleScripts);
gulp.task("bundle:css", gulp.series("sass", bundleStyles));
gulp.task("bundle", gulp.series("bundle:js", "bundle:css"));
gulp.task("build", gulp.series("bundle", "copy"));
gulp.task("watch", watch);
gulp.task("watch:sass", watchSass);
function verbose(format) {
if (format === undefined) {
format = chunk => `Processing '${colors.green(chunk.path)}'`;
}
return through.obj((chunk, encoding, callback) => {
log.info(format(chunk));
callback(null, chunk);
});
}
})();Tasks:
- sass - compiles sass files into css (bundles.json/sass).
- copy - copies files (bundles.json/copy).
- bundle:js - bundles scripts (bundles.json/scripts).
- bundle:css - compiles sass and bundles styles (bundles.json/styles).
- bundle - bundles scripts and styles.
- build - bundles scripts and styles and copies files.
- watch - watches for any changes in source files and recompiles / rebundles necessary files.
- watch:sass - watches for any changes in sass files and recompiles them.
During development, task watch:sass should be running to make sure any changes in sass files are compiled into css. If bundling is disabled - watch task is not necessary, since bundles are not actually served to the browser.
To reference bundles in web pages, following tag helpers should be used: <styles-bundle> and <scripts-bundle>. They can be placed in same places as the <link rel="stylesheet"> and <script> tags:
<styles-bundle path="/vendor/vendor.min.css" />
<styles-bundle path="/css/bundle.min.css" />Note: in bundles.json, the files should be referenced relatively to the application root: wwwroot/css/bundle.min.css, but when referencing them from web pages, the path relative to wwwroot should be used instead: /css/bundle.min.css.