Skip to content
This repository was archived by the owner on Apr 8, 2020. It is now read-only.

Commit 7f5810a

Browse files
Add docs about configuring Webpack to build LESS/SASS
1 parent eed4d8c commit 7f5810a

File tree

1 file changed

+133
-1
lines changed
  • src/Microsoft.AspNetCore.SpaServices

1 file changed

+133
-1
lines changed

src/Microsoft.AspNetCore.SpaServices/README.md

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ Benefits:
325325

326326
It lets you work as if the browser natively understands whatever file types you are working with (e.g., TypeScript, SASS), because it's as if there's no build process to wait for.
327327

328-
### Example: A simple Webpack setup
328+
### Example: A simple Webpack setup that builds TypeScript
329329

330330
**Note:** If you already have Webpack in your project, then you can skip this section.
331331

@@ -376,6 +376,138 @@ The Webpack loader, `ts-loader`, follows all chains of reference from `MyApp.ts`
376376

377377
So that's enough to build TypeScript. Here's where webpack dev middleware comes in to auto-build your code whenever needed (so you don't need any file watchers or to run `webpack` manually), and optionally hot module replacement (HMR) to push your changes automatically from code editor to browser without even reloading the page.
378378

379+
### Example: A simple Webpack setup that builds LESS
380+
381+
Following on from the preceding example that builds TypeScript, you could extend your Webpack configuration further to support building LESS. There are two major approaches to doing this:
382+
383+
1. **Have each build embed the style information into your JavaScript code**. At runtime, Webpack can dynamically attach the styles to your document via JavaScript. This has certain benefits during development.
384+
385+
2. **Or, have each build write a standalone `.css` file to disk**. At runtime, load it using a regular `<link rel='stylesheet'>` tag. This is likely to be the approach you'll want for production use as it's the most robust and best-performing option.
386+
387+
If instead of LESS you prefer SASS or another CSS preprocessor, the exact same techniques should work, but of course you'll need to replace the `less-loader` with an equivalent Webpack loader for SASS or your chosen preprocessor.
388+
389+
#### Approach 1: Loading the styles using JavaScript
390+
391+
This technique is a little simpler to set up than technique 1, plus it works flawlessly with Hot Module Replacement (HMR). The downside is that it's really only good for development time, because in production you probably don't want users to wait until JavaScript is loaded before styles are applied to the page (this would mean they'd see a 'flash of unstyled content' while the page is being loaded).
392+
393+
First create a `.less` file in your project. For example, create a file at `ClientApp/styles/mystyles.less` containing:
394+
395+
```less
396+
@base: #f938ab;
397+
398+
h1 {
399+
color: @base;
400+
}
401+
```
402+
403+
Reference this file from an `import` or `require` statement in one of your JavaScript or TypeScript files. For example, if you've got a `boot-client.ts` file, add the following near the top:
404+
405+
```javascript
406+
import './styles/mystyles.less';
407+
```
408+
409+
If you try to run the Webpack compiler now (e.g., via `webpack` on the command line), you'll get an error saying it doesn't know how to build `.less` files. So, it's time to install a Webpack loader for LESS (plus related NPM modules). In a command prompt at your project's root directory, run:
410+
411+
```
412+
npm install --save less-loader less
413+
```
414+
415+
Finally, tell Webpack to use this whenever it encounters a `.less` file. In `webpack.config.js`, add to the `loaders` array:
416+
417+
```
418+
{ test: /\.less/, loader: 'style!css!less' }
419+
```
420+
421+
This means that when you `import` or `require` a `.less` file, it should pass it first to the LESS compiler to produce CSS, then the output goes to the CSS and Style loaders that know how to attach it dynamically to the page at runtime.
422+
423+
That's all you need to do! Restart your site and you should see the LESS styles being applied. This technique is compatible with both source maps and Hot Module Replacement (HMR), so you can edit your `.less` files at will and see the changes appearing live in the browser.
424+
425+
**Scoping styles in Angular 2 components**
426+
427+
If you're using Angular 2, you can define styles on a per-component basis rather than just globally for your whole app. Angular then takes care of ensuring that only the intended styles are applied to each component, even if the selector names would otherwise clash. To extend the above technique to per-component styling, first install the `to-string-loader` NPM module:
428+
429+
```
430+
npm install --save to-string-loader
431+
```
432+
433+
Then in your `webpack.config.js`, simplify the `loader` entry for LESS files so that it just outputs `css` (without preparing it for use in a `style` tag):
434+
435+
```javascript
436+
{ test: /\.less/, loader: 'css!less' }
437+
```
438+
439+
Now **you must remove any direct global references to the `.less` file**, since you'll no longer be loading it globally. So if you previously loaded `mystyles.less` using an `import` or `require` statement in `boot-client.ts` or similar, remove that line.
440+
441+
Finally, load the LESS file scoped to a particular Angular 2 component by declaring a `styles` value for that component. For example,
442+
443+
```javascript
444+
@ng.Component({
445+
selector: ... leave value unchanged ...,
446+
template: ... leave value unchanged ...,
447+
styles: [require('to-string!../../styles/mystyles.less')]
448+
})
449+
export class YourComponent {
450+
... code remains here ...
451+
}
452+
```
453+
454+
Now when you reload your page, you should file that the styles in `mystyles.less` are applied, but only to the component where you attached it. It's reasonable to use this technique in production because, even though the styles now depend on JavaScript to be applied, they are only used on elements that are injected via JavaScript anyway.
455+
456+
#### Approach 2: Building LESS to CSS files on disk
457+
458+
This technique takes a little more work to set up than technique 1, and lacks compatibility with HMR. But it's much better for production use if your styles are applied to the whole page (not just elements constructed via JavaScript), because it loads the CSS independently of JavaScript.
459+
460+
First add a `.less` file into your project. For example, create a file at `ClientApp/styles/mystyles.less` containing:
461+
462+
```less
463+
@base: #f938ab;
464+
465+
h1 {
466+
color: @base;
467+
}
468+
```
469+
470+
Reference this file from an `import` or `require` statement in one of your JavaScript or TypeScript files. For example, if you've got a `boot-client.ts` file, add the following near the top:
471+
472+
```javascript
473+
import './styles/mystyles.less';
474+
```
475+
476+
If you try to run the Webpack compiler now (e.g., via `webpack` on the command line), you'll get an error saying it doesn't know how to build `.less` files. So, it's time to install a Webpack loader for LESS (plus related NPM modules). In a command prompt at your project's root directory, run:
477+
478+
```
479+
npm install --save less less-loader extract-text-webpack-plugin
480+
```
481+
482+
Next, you can extend your Webpack configuration to handle `.less` files. In `webpack.config.js`, at the top, add:
483+
484+
```javascript
485+
var extractStyles = new (require('extract-text-webpack-plugin'))('mystyles.css');
486+
```
487+
488+
This creates a plugin instance that will output text to a file called `mystyles.css`. You can now compile `.less` files and emit the resulting CSS text into that file. To do so, add the following to the `loaders` array in your Webpack configuration:
489+
490+
```javascript
491+
{ test: /\.less$/, loader: extractStyles.extract('css!less') }
492+
```
493+
494+
This tells Webpack that, whenever it finds a `.less` file, it should use the LESS loader to produce CSS, and then feed that CSS into the `extractStyles` object which you've already configured to write a file on disk called `mystyles.css`. Finally, for this to actually work, you need to include `extractStyles` in the list of active plugins. Just add that object to the `plugins` array in your Webpack config, e.g.:
495+
496+
```javascript
497+
plugins: [
498+
extractStyles,
499+
... leave any other plugins here ...
500+
]
501+
```
502+
503+
If you run `webpack` on the command line now, you should now find that it emits a new file at `dist/mystyles.css`. You can make browsers load this file simply by adding a regular `<link>` tag. For example, in `Views/Shared/_Layout.cshtml`, add:
504+
505+
```html
506+
<link rel="stylesheet" href="~/dist/mystyles.css" asp-append-version="true" />
507+
```
508+
509+
**Note** This technique (writing the built `.css` file to disk) is ideal for production use. But note that, at development time, *it does not support Hot Module Replacement (HMR)*. You will need to reload the page each time you edit your `.less` file. This is a known limitation of `extract-text-webpack-plugin`. If you have constructive opinions on how this can be improved, see the [discussion here](https://github.com/webpack/extract-text-webpack-plugin/issues/30).
510+
379511
### Enabling webpack dev middleware
380512

381513
First install the `Microsoft.AspNetCore.SpaServices` NuGet package and the `aspnet-webpack` NPM package, then go to your `Startup.cs` file, and **before your call to `UseStaticFiles`**, add the following:

0 commit comments

Comments
 (0)