From df51776718dca5bf950a7739e2678ae4ab45130c Mon Sep 17 00:00:00 2001 From: Jasmin Savard Date: Thu, 26 May 2022 14:18:10 -0400 Subject: [PATCH] Add gulp pipeline documentation (#11769) --- src/docs/guides/README.md | 1 + src/docs/guides/gulp-pipeline/README.md | 434 ++++++++++++++++++ .../images/gulpfile-failed-to-load.png | Bin 0 -> 8721 bytes .../gulp-pipeline/images/gulpfile-loaded.png | Bin 0 -> 10418 bytes .../gulp-pipeline/images/solution-items.png | Bin 0 -> 13402 bytes .../images/task-runner-explorer-refresh.png | Bin 0 -> 1316 bytes 6 files changed, 435 insertions(+) create mode 100644 src/docs/guides/gulp-pipeline/README.md create mode 100644 src/docs/guides/gulp-pipeline/images/gulpfile-failed-to-load.png create mode 100644 src/docs/guides/gulp-pipeline/images/gulpfile-loaded.png create mode 100644 src/docs/guides/gulp-pipeline/images/solution-items.png create mode 100644 src/docs/guides/gulp-pipeline/images/task-runner-explorer-refresh.png diff --git a/src/docs/guides/README.md b/src/docs/guides/README.md index 4db767d78e0..28be402b4f2 100644 --- a/src/docs/guides/README.md +++ b/src/docs/guides/README.md @@ -17,6 +17,7 @@ These guides are specific to Orchard Core CMS - [Creating an Orchard Core CMS website](create-cms-application/README.md) - [Adding a Menu Item to the Admin Navigation](add-admin-menu/README.md) - [Installing Localization Files](install-localization-files/README.md) +- [How to use the assets transpiler/bundler/minifier pipeline](gulp-pipeline/README.md) - [Integrate facebook plugins](integrate-facebook-plugins/README.md) - [Implement Full Text search](implement-fulltext-search/README.md) - [Integrate AzureAD as external provider](azuread-integration/README.md) diff --git a/src/docs/guides/gulp-pipeline/README.md b/src/docs/guides/gulp-pipeline/README.md new file mode 100644 index 00000000000..ec328dc570b --- /dev/null +++ b/src/docs/guides/gulp-pipeline/README.md @@ -0,0 +1,434 @@ +# Gulp Pipeline + +Orchard Core includes a processing pipeline for client-side assets (typically scripts and stylesheets) which is used to perform front-end development workflow tasks such as transpilation, minification and bundling of client-side assets in both core projects and extensions (i.e. modules and themes). Many of the built-in modules and themes in Orchard Core use this pipeline to process client-side assets, and you can enable your own extensions to use it as well. + +# Overview + +The client-side asset pipeline is powered by [Gulp](http://gulpjs.com), a popular open-source task runner based on [Node.js](https://nodejs.org) that can be used to automate a wide variety of tasks in a development workflow. The pipeline defines a set of Gulp *tasks* that can be executed by Gulp using either the command line or using the **Task Runner Explorer** tool window in Visual Studio 2022 or later. For those using Visual Studio Code you can use its terminal. + +Physically, the client-side asset pipeline consists of two files in the Orchard Core solution folder: + +- `src/package.json` contains information about the Node packages required by the pipeline. This file tells the Node package manager (NPM) which packages it needs to download and install for the pipeline to function. +- `src/gulpfile.js` contains JavaScript code that defines a set of Gulp tasks and their implementation logic. + +In Visual Studio you will find these files in **Solution Explorer** in a solution folder named `Solution Items`: + +![](images/solution-items.png) + +There are several reasons why the pipeline has been implemented at the solution level rather than in each extension that needs to process client-side assets. + +* Current and future can share the existing pipeline logic instead of having to reinvent it. +* Only one copy of the necessary Node.js packages needs to be downloaded and stored alongside the codebase. +* Keeping Node package folders (`node_modules`) anywhere inside the `OrchardCore.Cms.Web` project causes their contents to be included when publishing Orchard for deployment which would increase the size of the deployment package by orders of magnitude even though these files are only useful at development time. + +The client-side asset pipeline is not configured by default to be invoked automatically when opening or building Orchard Core. To minimize build time and make it as easy as possible to get started with Orchard Core, all built-in modules and themes in Orchard Core are kept in source control with their processed output files included. This means you don't have to activate and run the client-side asset pipeline to build or run Orchard Core out of the box. You only need to run the client-side asset pipeline if you make changes to these assets, or wish to use it to process assets in your own extensions. + +# Getting started + +## Installing prerequisites + +The client-side asset pipeline requires Node.js to be installed. If you are using Visual Studio 2022 or later, Node.js is typically already installed as part of Visual Studio. If you are not using Visual Studio, or if you selected not to include Node.js when installing Visual Studio, you will need to install Node.js manually from https://nodejs.org. + +Next you will need to use NPM to install all the packages the client-side asset pipeline needs, including Gulp itself. Using the command line, navigate to the Orchard Core solution folder and execute the command `npm install`, which will install all dependencies referenced in the `package.json` file. In Visual Studio 2022 or later, you can instead simply open the `package.json` file and save it without making any changes - this will trigger an automatic `npm install` behind the scenes. + +## Executing tasks + +There are three different Gulp tasks that you can invoke to execute the pipeline in different ways. + +- **build** performs an incremental build of all asset groups in the solution; asset groups whose outputs are already newer than all their inputs are not processed. +- **rebuild** performs an unconditional full build of all asset groups in the solution, even if their outputs are already newer than their inputs. +- **watch** monitors all asset groups in the solution for changes to their inputs, and rebuilds an asset group if one or more of its inputs are modified. + +Note: These tasks also take the asset manifest files themselves into consideration when evaluating changes; a modification to the asset manifest file (`Assets.json`) is treated the same as a modification to one of the input asset files declared in the manifest. + +The way you typically execute the Gulp tasks depends on whether you are using Visual Studio or not. + +### Using the command line + +1. Make sure you have Node.js installed and added to your `PATH` varable. +2. Make sure you have installed all the required Node.js packages using the `npm install` command as described above. +3. Navigate to the Orchard Core solution folder where the file `gulpfile.js` is located. +4. Execute one of the commands `gulp build`, `gulp rebuild` and `gulp watch` to execute the corresponding Gulp task. + +### Using Visual Studio + +Visual Studio 2022 and later comes with a built-in tool window named **Task Runner Explorer** that can be used to execute NPM tasks as well as tasks from different task runners such as Gulp and Grunt among others. + +To open Task Runner Explorer, select **View -> Other Windows -> Task Runner Explorer** from the menu. Alternatively, you can right-click on the file `gulpfile.js` in Solution Explorer and select **Task Runner Explorer** from there. + +Initially you may see an error message in Task Runner Explorer: + +![](images/gulpfile-failed-to-load.png) + +This can happen if you have not installed the necessary dependency packages (see the section on installing prerequisites above) or if you have recently installed dependency packages and Task Runner Explorer has not yet retried the parsing of the Gulp file after that. Once you have installed all the dependency packages, just click the refresh icon and wait for it to reload: + +![](images/task-runner-explorer-refresh.png) + +When Task Runner Explorer has correctly parsed the Gulp file you will see the list of tasks contained inside it: + +![](images/gulpfile-loaded.png) + +You can now double-click one of the tasks to execute it. + +### Binding tasks to Visual Studio events + +Task Runner Explorer also has the ability to "bind" tasks to be executed automatically in response to Visual Studio solution events. Orchard Core is not preconfigured with any such bindings because all assets in the original code base are already processed and their outputs are included in source control, but it can be useful to configure these bindings temporarily while developing your own client-side assets or while working on modifications to the ones in Orchard Core. + +The most common scenario is to bind the **build** task to the **After Build** solution event. This way, each time you build Orchard Core (for example, by hitting `F5` or `Ctrl+F5` or selecting **Build -> Build Solution** from the menu) the asset pipeline's **build** task will be executed at the end of the build process. Any asset groups whose input files have changed since the last build will be refreshed. + +To configure this binding, follow these steps: + + 1. Right click on the `build` task + 2. Select **Bindings** + 3. Select **After Build** + +Another common scenario is binding the **watch** task to the **Project Open** solution event, which will start the **watch** task when the solution is loaded and keep it running until you terminate it. + +Note: It's important to be aware that task bindings are stored in a specially formatted comment in the beginning of the Gulp file, so when you configure task bindings you are effectively making a change to one of the core files belonging to the Orchard Core code base which may be overwritten if you later choose to update your code base to a newer version of Orchard Core. + +# Using the pipeline for your own module or theme + +You typically don't have to execute any of the tasks in the client-side asset pipeline unless you are either making changes to Orchard Core itself or creating your own custom extensions and wish to utilize the pipeline to process your own client-side assets. This section explains how to enable the pipeline for your own extension. + +## Adding an asset manifest file + +The first step is to add an *asset manifest file* to your extension. This asset manifest file is a simple JSON document that declares one or more *asset groups* to be processed by the pipeline. Each asset group specifies a set of *input files* in your extension (such as `.less`, `.scss`, `.css`, `.ts` or `.js` files) along with an *output file* and (optionally) one or more options to influence the processing. + +To add an asset manifest, add a new JSON file named `Assets.json` to the root folder of your extension (both the name and location of the file are mandatory. The client-side asset pipeline will detect and parse this file, and add the asset groups declared inside it for processing when of the pipeline tasks are executed. + +The basic structure of the asset manifest looks like this: + +```js +[ + { + // First asset group + "inputs": [ + "some/input/file.less", + "some/input/file2.less" + ], + "output": "some/output/file.css" + // Options can be added here + }, + { + // Repeat for more asset groups + } +] +``` + +All input and output paths are relative to the extension root folder. However they do not have to reside within the extension folder; using `../` to resolve paths outside of the extension folder is fully supported. It is a common convention in Orchard Core to use a folder named `Assets` to contain input asset files and to keep those separate from the output asset files, but this is not required. + +Using the asset pipeline is completely optional. If you don't add an `Asset.json` manifest file in the root folder of your extension, the client-side asset pipeline will simply ignore your extension. + +## Basic example (single input file) + +The following example takes the LESS stylesheet `Assets/Styles.less` in your extension and transpiles it into the output file `Styles/Styles.css`: + +```js +[ + { + "inputs": [ + "Assets/Styles.less" + ], + "output": "Styles/Styles.css" + } +] +``` + +When executing the **build** or **rebuild** task, the asset pipeline will perform the following tasks on `Styles.less`: + +- Transpile LESS to plain CSS +- Add/remove vendor prefixes as necessary +- Add source maps (non-minified output only) +- Add a static informational header (non-minified output only) +- Normalize line ending characters +- Minify + +After the **build** task has executed your extension's `Styles` folder will contain two files: + +* `Styles.css` (non-minified with inline source maps) +* `Styles.min.css` (minified) + +Once these output asset files have been generated you can reference them from Razor views just as you normally wolud using the Orchard Core resource manager, either by declaring them in a resource manifest class and requiring them using one of the `Require()` methods or by including them by path using one of the `Include()` methods. + +Note: The generated output asset files will not be automatically added to your extension project (`.csproj`) file. If you wish to keep the output asset files in source control, you will need to manually include them in your project using Solution Explorer after they have been generated for the first time. See the section on advanced scenarios below for some pointers on when you may or may not want to do this. + +## Multiple input files + +You can also specify multiple inputs in the same asset group: + +```js +[ + { + "inputs": [ + "Assets/Grid.less", + "Assets/Forms.less", + "Assets/Type.less", + ], + "output": "Styles/Styles.css" + } +] +``` + +This works exactly like the basic example above with the single input, with the addition that all three inputs will be bundled into the output files `Styles.css` and `Styles.min.css`. + +## Globs (wildcards) + +The client-side asset pipeline also supports using [glob wildcard patterns](https://www.npmjs.com/package/glob#glob-primer) to include multiple input assets without having to specify each one individually. + +The following example processes all files with a `.js` extension in the `Assets` folder and all its subfolders, and bundles them into a single `Scripts/Scripts.js` output file: + +```js +[ + { + "inputs": [ + "Assets/**/*.js" // Include all .js files anywhere in or underneath the Assets folder + ], + "output": "Scripts/Scripts.js" + } +] +``` + +## Separate output files for each input file + +In many cases you will want to process many input files in the exact same way but keep them in separate output files. You could do this by declaring a separate asset group for each pair of input/output files. However this can be extremely tedious and error prone to write, and even more so to maintain over time as you add or remove assets to your extention, especially if you have a large number of asset files. + +The pipeline makes this easier by allowing you to use the `@` characted instead of a file name the output file path of your asset group. The `@` character disables the bundling step and basically translates to "the same filename as whatever input asset file is currently being processed". When combined with glob wildcards this can make it a lot easier to manage your assets: + +```js +[ + { + "inputs": [ + "Assets/Moment/Localizations/*.ts" + ], + "output": "Scripts/Localizations/@.js" + } +] +``` + +In this example, all TypeScript files in the `Assets/Moment/Localizations` are processed and each generated into a separate `.js` file with the same name in the `Scripts/Localizations` folder. For example, assuming the `Assets/Moment/Localizations` folder contains `en-GB.ts`, `fr-FR.ts` and `sv-SE.ts`, then the output `Scripts/Localizations` folder would contain the resulting files `en-GB.js`, `en-GB.min.js`, `fr-FR.js`, `fr-FR.min.js`, `sv-SE.js` and `sv-SE.min.js`. If localization files are added or removed over time, the asset group is implicitly redefined accordingly. + +## Multiple asset groups + +You can define multiple asset groups in the same asset manifest, as in the following example: + +```js +[ + { // First asset group + "inputs": [ + "Assets/Bootstrap/Bootstrap.less", + "Assets/Bootstrap/Theme.less" + ], + "output": "Styles/Bootstrap.css" + }, + { // Second asset group + "inputs": [ + "Assets/Styles.less" + ], + "output": "Styles/Styles.css" + }, + { // Third asset group + "inputs": [ + "Assets/JavaScript/Lib/**/*.js", + "Assets/JavaScript/Admin/Admin.js" + ], + "output": "Scripts/Lib.js" + } +] +``` + +## Adding additional files to be watched + +As described above, the **watch** task can be used to continuously monitor input asset files for changes and rebuild affected asset groups automatically for a smooth and efficient local dev/test workflow. + +In some cases you may want the **watch** task to monitor additional files besides those specified as input assets. In particular, this is commonly needed when using LESS/SASS imports or the TypeScript `` or `import` keywords to indirectly include files into the pipeline which were not part of the initial input specification. + +Let's say you have a main SCSS stylesheet that looks something like this: + +```less +@import "Utils/Mixins.scss"; +@import "Utils/Variables.scss"; +@import "Utils/Type.scss" +``` + +In these cases you can use the `watch` property in an asset group to specify an additional set of files to monitor for changes: + +```js +[ + { + "inputs": [ + "Assets/Main.scss" // This one imports additional .scss files + ], + "output": "Styles/Styles.css", + "watch": [ + "Assets/Utils/*.scss" // Also watch these two files for changes + ] + } +] +``` + +Note that glob wildcards are supported. + +## Supported asset file formats + +The client-side asset pipelines can process either *stylesheet assets* or *script assets*. + +An asset group can only be used to process one of these categories, and must have a matching output asset file extension. Asset groups dealing with stylesheet assets must specify a `.css` output file, while asset groups dealing with script assets must specify a `.js` output file. An asset group can contain mixed types of input assets as long as they can be processed into the same output file type (i.e. as long as they all belong to either the stylesheet or the script family). + +For example you can specify both `.less` and `.css` input assets in a group targeted for a `.css` output file and you can specify both `.ts` and `.js` input assets in a group targeted for a `.js` output file, but you cannot mix and match; if you try the asset pipeline will throw an error. + +### Stylesheet assets + +The following file types are supported as stylesheet input assets: + +* LESS (`.less`) +* SASS (`.sass`) +* SCSS (`.scss`) +* Plain CSS (`.css`) + +The following tasks are performed on stylesheet assets: + +* LESS/SASS transpilation +* Vendor prefix normalization +* Inline source map generation (unless disabled) +* File header generation +* Line ending normalization +* Bundling (unless disabled) +* Minification + +### Script assets + +The following file types are supported as script input assets: + +* TypeScript (`*.ts`, `*.jsx`) +* Plain JavaScript (`*.js`) + +The following tasks are performed on script assets: + +* TypeScript transpilation +* Inline source map generation (unless disabled) +* File header generation +* Line ending normalization +* Bundling (unless disabled) +* Minification + +Note: All input script assets are processed through the TypeScript transpiler, also plain JavaScript `.js` files. This means the asset pipeline will throw errors for obvious syntactical errors in plain JavaScript files. This should generally be considered an advantage as JavaScript errors can be caught at build time rather than at runtime. + +## Supported options + +The following is an exhaustive list of all possible properties that can be specified in an asset group in the asset manifest file. + +### `inputs` (required) + +An array of input files to include in the asset group. Paths are relative to the asset manifest file. Glob wildcards are supported. Single entries must be wrapped in an array. + +### `output` (required) + +The output file to be generated by the asset group. The path is relative to the asset manifest file. All inputs will be bundled into the specified output file unless `@` is specified as the base filename, eg `Scripts/@.css`, to skip bundling. A minified version with a `.min` suffix will be automatically generated also. + +### `watch` + +An array of additional files to be monitored for changes. Paths are relative to the asset manifest file. Glob wildcards are supported. Single entries must be wrapped in an array. + +### `generateSourceMaps` + +`true` to emit inline source maps into non-minified output files, `false` to disable source maps. Default is `true`. + +### `flatten` + +By default, when using a glob to specify input assets and using the `@` character in the output file path to bypass bundling, output files are generated in the same relative location as their corresponding input assets relative to the first glob in the input pattern. For example, assuming you have the following input assets: + +* `Assets/Pages/PageStyles.less` +* `Assets/Widgets/LoginWidget/Login.less` + +Given the following asset group definition: + +```js +[ + { + "inputs": [ "Assets/**/*.less" ], + "output": "Styles/@.css" + } +] +``` + +The default behavior of the asset pipeline would generate the following output files: + +* `Styles/Pages/PageStyles.css` +* `Styles/Pages/PageStyles.min.css` +* `Styles/Widgets/LoginWidget/Login.css` +* `Styles/Widgets/LoginWidget/Login.min.css` + +This may not always be the desired behavior. The `flatten` property can be set to `true` to have the asset pipeline flatten the output folder structure and disregard the relative locations of the input asset files. In this case, setting `flatten` to `true` would instead produce the following two output files: + +* `Styles/PageStyles.css` +* `Styles/PageStyles.min.css` +* `Styles/Login.css` +* `Styles/Login.min.css` + +### `separateMinified` + +By default, minified output files are generated alongside their non-minified siblings with a `.min` filename extension: + +* `Styles/SomeStyles.css` +* `Styles/SomeStyles.min.css` + +In some cases, such as when using a runtime module loader, it can be useful to place minified output files in a subfolder instead of suffixing their filenames. This allows you to simply configure a different base path for the module loader depending on execution mode (i.e. debug vs. release) rather than having to declare every resource differently. Setting the `separateMinified` option property to `true` will result in the following alternative output structure: + +* `Styles/SomeStyles.css` +* `Styles/min/SomeStyles.css` + +### `typeScriptOptions` + +Any options you wish to pass through to the TypeScript transpiler (only applicable for script asset groups). The following default values are specified by the asset pipeline unless overridden in this property: + +```js +{ + allowJs: true, + noImplicitAny: true, + noEmitOnError: true +} +``` + +# Advanced scenarios + +## Excluding output files from source control + +When developing an extension intended for redistribution and used by third parties, it is recommended that generated output files be added to `.csproj` files of the containing extension and included in source control. All the built-in projects in the Orchard Core code base employ this methods. This is so that consumers can use your extension without having to install Node.js and execute the Gulp tasks in the client-side asset pipeline to generate the needed output asset files first. + +However, when developing an extension for internal use you may also consider the alternative approach of leaving generated output files out of both `.csproj` files and source control and rely on them being rebuilt by the client-side asset pipeline whenever needed. This is similar to how you often assume that the NuGet package manager will be used to restore NuGet package references before a project is built. + +This approach has a couple of advantages: + +* Smaller version control footprint +* No risk of inconsistent/stale output assets due to forgetting to rebuild them or commit their changes to version control + +When using this approach, the `Styles` and `Scripts` folders in your extension will always remain empty in Solution Explorer although they will contain the output files on disk, and you will typically configure a Gulp task binding to ensure that client-side assets are always built when the solution is built in Visual Studio. If using an automated build system you will also typically add a step to your build script to ensure the **build** or **rebuild** task is executed as part of the build. + +## Including custom extension folders + +Orchard Core has the ability to load extensions from other folders besides the `OrchardCore.Modules` and `OrchardCore.Themes` folders. If your extension is stored and loaded from such a custom location, the client-side asset pipeline will not automatically detect your asset manifest. This is because, by default, it only looks for `Assets.json` files in folders under these locations: + +* `OrchardCore.Modules/` +* `OrchardCore.Themes/` + +To add your custom location to be scanned for asset manifests, follow these steps: + +1. Open the file `src/gulpfile.js` in Visual Studio or any other text editor. + +2. Find the `getAssetGroups()` function. + +3. This function declares an `assetManifestPaths` array variable. You can add your own glob here and merge the resulting arrays. For example: + +```js +var assetManifestPaths = glob.sync("./src/OrchardCore.{Modules,Themes}/*/Assets.json", {}); +var customThemePaths = glob.sync("AnotherLocation/MyCompanyThemes/*/Assets.json"); // Custom location! +assetManifestPaths = assetManifestPaths.concat(customThemePaths); +``` + +4. Save and close the file. + +The Orchard Core development team is investigating ways to automate this process. + +# Evolution of the client-side asset pipeline + +For those interested in the history behind the client-side asset pipeline, you can find the initial discussion with reasons for its development and proposed solutions in [issue #5450](https://github.com/OrchardCMS/Orchard/issues/5450). \ No newline at end of file diff --git a/src/docs/guides/gulp-pipeline/images/gulpfile-failed-to-load.png b/src/docs/guides/gulp-pipeline/images/gulpfile-failed-to-load.png new file mode 100644 index 0000000000000000000000000000000000000000..2c826a56906da66eb2bebc5ffb7407df14c4b064 GIT binary patch literal 8721 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 W=OeTJlJC!3gtC%K5=CMrAO0JiQ;&WC literal 0 HcmV?d00001 diff --git a/src/docs/guides/gulp-pipeline/images/solution-items.png b/src/docs/guides/gulp-pipeline/images/solution-items.png new file mode 100644 index 0000000000000000000000000000000000000000..57d186fe743cb9dddf2cbef3a5257885f81af454 GIT binary patch literal 13402 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 Oki4`C}FfdWj%4dKI|^K-~-sHue<-iOJciB??KY z>6v-9O7C~?S5nAKu~iB;^)>Jbs{}UJ3djZt>nkaMm6T-LDnT3-;TxdfoL`ixV6JDVn`~fUpkQvPmzt7j zlw_Qin5?5Ge1uOWMX1c zerbuV640>_U*s0Rjm;~Dh7>T&^eYkz^bPe4K)!-0^!3HBG&dKny0|1L72#g21{a4^ z7NqJ2r55Lx79|7YE=?I^Re_arQEFmIeo;t%ehw@k12XbU@{2R_3lxlu^$Zm>!ZY(y z^2>`g!5VyhtvvIJOA_;vQ$1a5m4HU*WoD*Wxj2~{7@L}yxj35|7#g}dI~kiDlP-`0PyDHQz!YBuOxku^Wjq-e7^ir; zIEGZ*N}4i#dinyPgro&>5~kfI2bzveFVmh-rrWTgeqVLb#=C5KM^BtNb>`sb=dY`i z?tU$~-V(f&YrFWezdwJq#d@$sc162|FHe}gU>Y}Poye810UTNTEX_H6|C~Nty#1N_ z$)DyQR^Jp#731#jND6qp_UFoY`S?R2f8XBxdYe0Vs;yd&0f1_=ll(k`u%z$*S8C5gY;N87^6ik?8^Na4J!#?-L^gXdJhLkkv<$GT|NP?b*1JG!e|-JOdhUd* g?tAt#It>iW3~gau7efAO6@tnwPgg&ebxsLQ06viD<^TWy literal 0 HcmV?d00001