There are many ways of bundling & minification of client side resources (JavaScript and CSS files). Most common ways are:
* Using the [Bundler & Minifier](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier) Visual Studio extension or the [nuget package](https://www.nuget.org/packages/BuildBundlerMinifier/).
* Using the [Bundler & Minifier](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier) Visual Studio extension or the [NuGet package](https://www.nuget.org/packages/BuildBundlerMinifier/).
* Using [Gulp](https://gulpjs.com/)/[Grunt](https://gruntjs.com/) task managers and their plugins.
ABP offers a simpler, dynamic, powerful, modular and built-in way.
ABP offers a simple, dynamic, powerful, modular and built-in way.
### Volo.Abp.AspNetCore.Mvc.UI.Bundling Package
@ -46,12 +47,12 @@ The simplest way of creating a bundle is to use `abp-script-bundle` or `abp-styl
</abp-style-bundle>
````
This bundle defines a style bundle with a **unique name**: *MyGlobalBundle*. It's very easy to *understand* how to use it. Let's see how it *works*:
This bundle defines a style bundle with a **unique name**: `MyGlobalBundle`. It's very easy to understand how to use it. Let's see how it *works*:
* ABP creates the bundle as **lazy** from the provided files when it's **first requested**. For the subsequent calls, it's returned from the **cache**. That means if you conditionally add files to the bundle, it's executed only once and any change of the condition will not effect the bundle for the next requests.
* ABP creates the bundle as **lazy** from the provided files when it's **first requested**. For the subsequent calls, it's returned from the **cache**. That means if you conditionally add the files to the bundle, it's executed only once and any changes of the condition will not effect the bundle for the next requests.
* ABP adds bundle files **individually** to the page for the `development` environment. It automatically bundles & minifies for other environments (`staging`, `production`...).
* The bundle files may be **physical** files or [**virtual/embedded** files](../Virtual-File-System.md).
* ABP automatically adds **version query string** (like ?_v=67872834243042 - generated from last change date of the related files) to the bundle file URL which prevents browser caching when a bundle changes. The versioning works even if the bundle files are individually added to the page (on the development environment).
* ABP automatically adds **version query string**to the bundle file URL to prevent browsers from caching when the bundle is being updated. (like ?_v=67872834243042 - generated from last change date of the related files). The versioning works even if the bundle files are individually added to the page (on the development environment).
#### Importing The Bundling Tag Helpers
@ -91,7 +92,7 @@ Advantages of **named** bundles:
#### Single File
If you need to just add a single file to the page, you can use the `abp-script` or `abp-style` tag without a surrounding`abp-script-bundle` or `abp-style-bundle` tag. Example:
If you need to just add a single file to the page, you can use the `abp-script` or `abp-style` tag without a wrapping in the`abp-script-bundle` or `abp-style-bundle` tag. Example:
````xml
<abp-scriptsrc="/scripts/my-script.js"/>
@ -142,7 +143,8 @@ This time, no file defined in the tag helper definition because the bundle files
#### Configuring An Existing Bundle
ABP supports [modularity](../Module-Development-Basics.md) for bundling too. A module can modify an existing bundle that is created by a depended module. Example:
ABP supports [modularity](../Module-Development-Basics.md) for bundling as well. A module can modify an existing bundle that is created by a dependant module.
Example:
````C#
[DependsOn(typeof(MyWebModule))]
@ -164,7 +166,7 @@ public class MyWebExtensionModule : AbpModule
}
````
> It's not possible to configure unnamed bundle tag helpers by code, because their name are not known on the development time. It's suggested to always use a name for a bundle tag helper.
> It's not possible to configure unnamed bundle tag helpers by code, because their name are not known at the development time. It's suggested to always use a name for a bundle tag helper.
### Bundle Contributors
@ -185,7 +187,7 @@ public class MyExtensionGlobalStyleContributor : BundleContributor
Contributors can also be used in bundle tag helpers. Example:
Contributors can also be used in the bundle tag helpers.
Example:
````xml
<abp-style-bundle>
@ -208,11 +211,12 @@ Contributors can also be used in bundle tag helpers. Example:
</abp-style-bundle>
````
`abp-style` and `abp-script` tags can get `type` attributes (instead of `src` attributes) as shown in this sample. When you add a bundle contributor, it's dependencies are also automatically added to the bundle.
`abp-style` and `abp-script` tags can get `type` attributes (instead of `src` attributes) as shown in this sample. When you add a bundle contributor, its dependencies are also automatically added to the bundle.
#### Contributor Dependencies
A bundle contributor can have one or more dependencies to other contributors. Example:
A bundle contributor can have one or more dependencies to other contributors.
Example:
````C#
[DependsOn(typeof(MyDependedBundleContributor))] //Define the dependency
@ -232,9 +236,9 @@ While it is rarely needed, `BundleConfigurationContext` has a `ServiceProvider`
#### Standard Package Contributors
Adding a specific NPM package resources (js, css files) into a bundle is pretty standard for that package. For instance you always add the `bootstrap.css` file for the bootstrap NPM package.
Adding a specific NPM package resource (js, css files) into a bundle is pretty straight forward for that package. For example you always add the `bootstrap.css` file for the bootstrap NPM package.
There are built-in contributors for all [standard NPM packages](Client-Side-Package-Management.md). For instance, if your contributor depends on the bootstrap, you can just declare it instead of adding the bootstrap.css yourself:
There are built-in contributors for all [standard NPM packages](Client-Side-Package-Management.md). For example, if your contributor depends on the bootstrap, you can just declare it, instead of adding the bootstrap.css yourself.
````C#
[DependsOn(typeof(BootstrapStyleContributor))] //Define the bootstrap style dependency
@ -246,22 +250,23 @@ public class MyExtensionStyleBundleContributor : BundleContributor
Using the built-in contributors for standard packages;
* Prevents you **wrongly typing** the resource paths.
* Prevents changing your contributor if the resource **path changes** (the depended contributor will handle it).
* Prevents multiple modules add the same file **multiple times**.
* Manages **dependencies recursively** (adds dependencies of dependencies... if necessary).
* Prevents you typing **invalid the resource paths**.
* Prevents changing your contributor if the resource **path changes** (the dependant contributor will handle it).
* Prevents multiple modules adding the **duplicate the files**.
* Manages **dependencies recursively** (adds dependencies of dependencies, if necessary).
##### Volo.Abp.AspNetCore.Mvc.UI.Packages Package
> This package is already installed by default with the startup templates. So, most of the time, you don't need to install it manually.
> This package is already installed by default in the startup templates. So, most of the time, you don't need to install it manually.
Standard package contributors are defined in the `Volo.Abp.AspNetCore.Mvc.UI.Packages` nuget package. To install it into your project:
Standard package contributors are defined in the `Volo.Abp.AspNetCore.Mvc.UI.Packages` NuGet package.
Then add the `AbpAspNetCoreMvcUiPackagesModule` module dependency to your own module
Then add the `AbpAspNetCoreMvcUiPackagesModule` module dependency to your own module;
````C#
using Volo.Abp.Modularity;
@ -279,7 +284,8 @@ namespace MyCompany.MyProject
#### Bundle Inheritance
In some specific cases, it may be needed to create a **new** bundle **inherited** from other bundle(s). Inheriting from a bundle (recursively) inherits all files/contributors of that bundle. Then the derived bundle can add or modify files/contributors **without modifying** the original bundle. Example:
In some specific cases, it may be needed to create a **new** bundle **inherited** from other bundle(s). Inheriting from a bundle (recursively) inherits all files/contributors of that bundle. Then the derived bundle can add or modify files/contributors **without modifying** the original bundle.
Example:
````c#
services.Configure<BundlingOptions>(options =>
@ -309,9 +315,9 @@ It's suggested to define multiple bundles for an application, each one is used f
* **Module bundles**: For shared resources among the pages of an individual module.
* **Page bundles**: Specific bundles created for each page. Use the bundling tag helpers to create the bundle as a best practice.
Establish a balance between performance, network bandwidth usage and managing too many bundles.
Establish a balance between performance, network bandwidth usage and count of many bundles.
### See Also
* [Client Side Package Management](Client-Side-Package-Management.md)
## ASP.NET Core MVC Client Side Package Management
ABP framework can work any type of client side package management system. Even you can decide to use nothing and manually manage your dependencies.
ABP framework can work with any type of client side package management systems. You can even decide to use no package management system and manage your dependencies manually.
However, ABP framework best works with **NPM/Yarn**. It provides tools to make it easier to work with and built-in modules are configured to work with NPM/Yarn by default.
However, ABP framework works best with **NPM/Yarn**. By default, built-in modules are configured to work with NPM/Yarn.
Finally, we suggest the [**Yarn**](https://yarnpkg.com/) over the NPM since it's faster, stable and also compatible with the NPM.
@ -10,7 +11,7 @@ Finally, we suggest the [**Yarn**](https://yarnpkg.com/) over the NPM since it's
ABP is a modular platform. Every developer can create modules and the modules should work together in a **compatible** and **stable** state.
One challenge is the **versions of the depended NPM packages**. What if two different module use the same JavaScript library but its different (and potentially incompatible) versions.
One challenge is the **versions of the dependant NPM packages**. What if two different modules use the same JavaScript library but its different (and potentially incompatible) versions.
To solve the versioning problem, we created a **standard set of packages** those depends on some common third-party libraries. Some example packages are [@abp/jquery](https://www.npmjs.com/package/@abp/jquery), [@abp/bootstrap](https://www.npmjs.com/package/@abp/bootstrap) and [@abp/font-awesome](https://www.npmjs.com/package/@abp/font-awesome). You can see the **list of packages** from the [Github repository](https://github.com/volosoft/abp/tree/master/npm/packs).
@ -19,7 +20,7 @@ The benefit of a **standard package** is:
* It depends on a **standard version** of a package. Depending on this package is **safe** because all modules depend on the same version.
* It contains the gulp task to copy library resources (js, css, img... files) from the **node_modules** folder to **wwwroot/libs** folder. See the *Mapping The Library Resources* section for more.
Depending on a standard package is easy. Just add it to your **package.json** file as you normally add a package. Example:
Depending on a standard package is easy. Just add it to your **package.json** file like you normally do. Example:
````json
{
@ -40,7 +41,7 @@ After depending on a NPM package, all you should do is to run the **yarn** comma
yarn
````
You can instead use the `npm install` but the [Yarn](https://yarnpkg.com/) is suggested as mentioned before.
Alternatively, you can use `npm install` but [Yarn](https://yarnpkg.com/) is suggested as mentioned before.
#### Package Contribution
@ -58,15 +59,15 @@ See current standard packages for examples.
Using NPM packages and NPM/Yarn tool is the de facto standard for client side libraries. NPM/Yarn tool creates a **node_modules** folder in the root folder of your web project.
Next challenge is copying needed resources (js, css, img... files) from the node_modules into a folder inside the **wwwroot** folder to make it accessible to the clients/browsers.
Next challenge is copying needed resources (js, css, img... files) from the `node_modules` into a folder inside the **wwwroot** folder to make it accessible to the clients/browsers.
ABP defines a [Gulp](https://gulpjs.com/) based task to **copy resources** from **node_modules** to **wwwroot/libs** folder. Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of times, you only configure dependencies.
ABP defines a [Gulp](https://gulpjs.com/) based task to **copy resources** from **node_modules** to **wwwroot/libs** folder. Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of the time, you only configure dependencies.
The **startup templates** are already configured to work all these out of the box. This section will explain the configuration options.
#### Resource Mapping Definition File
An module should define a JavaScript file named `abp.resourcemapping.js` which is formatted as in the example below:
A module should define a JavaScript file named `abp.resourcemapping.js` which is formatted as in the example below:
````js
module.exports = {
@ -83,7 +84,7 @@ module.exports = {
}
````
* **aliases** section defines standard aliases (placeholders) those can be used in the mapping paths. **@node_modules** and **@libs** are required (by the standard packages), you can define your own aliases to reduce duplication.
* **aliases** section defines standard aliases (placeholders) that can be used in the mapping paths. **@node_modules** and **@libs** are required (by the standard packages), you can define your own aliases to reduce duplication.
* **clean** section is a list of folders to clean before copying the files.
* **mappings** section is a list of mappings of files/folders to copy. This example does not copy any resource itself, but depends on a standard package.
@ -104,11 +105,11 @@ Once you properly configure the `abp.resourcemapping.js` file, you can run the g
gulp
````
When you run the gulp, all packages will copy their own resources into the **wwwroot/libs** folder. Running yarn & gulp again is only necessary if you make a change in your dependencies in the **package.json** file.
When you run the `gulp`, all packages will copy their own resources into the **wwwroot/libs** folder. Running `yarn & gulp` is only necessary if you make a change in your dependencies in the **package.json** file.
> When you run the Gulp command, dependencies of the application are resolved using the package.json file. The Gulp task automatically discovers and maps all resources from all dependencies (recursively).
Background jobs are used to queue some tasks to be executed in the background. You may need background jobs for several reasons. Here are some examples:
- To perform **long-running tasks** without having the users wait. For example, a user presses a 'report' button to start a long-running reporting job. You add this job to the **queue** and send the report's result to your user via email when it's completed.
- To create **re-trying** and **persistent tasks** to **guarantee** that a code will be **successfully executed**. For example, you can send emails in a background job to overcome **temporary failures** and **guarantee** that it eventually will be sent. That way users do not wait while sending emails.
Background jobs are **persistent** that means they will be **re-tried** and **executed** later even if your application crashes.
ABP provides an **abstraction** module and **several implementations** for background jobs. It has a built-in/default implementation as well as Hangfire and RabbitMQ integrations.
### Abstraction Module
TODO
### Creating a Background Job
A background job is a class that implements the `IBackgroundJob<TArgs>` interface or derives from the `BackgroundJob<TArgs>` class. `TArgs` is a simple plain C# class to store the job data.
An example background job to send emails in background: