You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Apr 8, 2020. It is now read-only.
Repository navigation
This repository was archived by the owner on Apr 8, 2020. It is now read-only.
This is easily handle by adding Sass or Less loader in webpack.config. Or you propose to made it in yo-templates? This possibly should be an option of generator.
Thanks for the suggestion. I'm not sure whether we'll handle it by adding further options to the generator, or by adding docs describing how to do it.
But it should be really straightforwards - just amend your webpack.config.js to specify a loader for your SASS/LESS/etc files. In that sense it's more of a webpack question than anything about this project, but I appreciate we should make that obvious in docs so people know there's no other hidden steps they need to follow :)
I'm actually having trouble with getting sass to work with prerendering. Does anyone have a working webpack.config.js for sass?
EDIT:
I'm no webpack expert, but I made it work. I don't really understand the implications of the following settings, maybe someone can shed some light. Based on webpack/css-loader#59
An option in the generator would go awesome. I'm having trouble getting it to work for less.
I added the loader to the webpack.config.js file directly after the existing .css line: { test: /\.less/, loader: extractCSS.extract('css!less') }
It works when i run 'webpack' directly at the CLI, but when I run 'dotnet run' there's an exception in the middleware when I make the first page request.
Exception:
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
An unhandled exception has occurred: Call to Node module failed with error: Error: Webpack compilation reported errors. Compiler output follows: Hash: 42861fb47b6854d4d6b6
Version: webpack 1.13.1
Time: 2609ms
Asset Size Chunks Chunk Names
webpack-output.js 19.6 kB 0 [emitted] main
ERROR in ./ClientApp/components/Counter.less
Module build failed: Error: Cannot find module './../../node_modules/css-loader/lib/css-base.js'
at Function.Module._resolveFilename (module.js:438:15)
at Function.Module._load (module.js:386:25)
at Module.require (module.js:466:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (/Users/simon/code/Zenith.Core/src/Zenith.Core.Erp.Yo/node_modules/css-loader/index.js!/Users/simon/code/Zenith.Core/src/Zenith.Core.Erp.Yo/node_modules/less-loader/index.js!/Users/simon/code/Zenith.Core/src/Zenith.Core.Erp.Yo/ClientApp/components/Counter.less:62:19)
I'm sorry, I was terribly wrong. The issue here is that we need different webpack bundles for both configurations (we need different module loaders for sass browser vs sass server as the webpack maintainers show here), but this is not supported by aspnet-webpack.
This is effectively breaking one of webpacks features, and it makes me wonder if this is the correct approach. Maybe instead of overriding the configuration we could define two configurations, and let aspnet-webpack search for the one it needs.
I'm close to making this work by manually tweaking LoadViaWebpack.ts, I'll share when it does work.
Well, I made it work, but not 100% with angular2. Either you:
use extractCSS but lose style encapsulation
don't use extractCSS at all, at the cost of not having styles in case client-side javascript is disabled (and also for the prerendered page before the framework kicks-in)
Steps:
Read this to understand what are the requirements for the webpack side of things
Ignore the css-loader?module parameter if you're using angular2: it'll break things because angular2 has built-in style scoping
Edit webpack.config.js
Choose one of the two loaders (neither works 100%)
{test: /\.scss$/,include: /ClientApp/,//loader: "css-loader!sass-loader" // WORKS but not with javascript disabledloader: extractCSS.extract("style-loader","css-loader!sass-loader")// WORKS but doesn't scope styles}
Edit node_modules/aspnet-webpack/LoadViaWebpack.js (must do it again if updating the module!)
It almost works using loaders: ['raw-loader', 'sass-loader'] as suggested in this post, but then you are missing the css-loader and don't get url resolving (e.g. for images).
If you try to use loaders: ['to-string-loader', 'css-loader', 'sass-loader'] or similar you get the Cannot find module './../../node_modules/css-loader/lib/css-base.js' error that was mentioned by @shobman, which I'm pretty sure is an error in the webpack prerendering configuration. I'll take a look later.
@SteveSandersonMS@laskoviymishka I know you're not providing a built-in css-preprocessor support, but maybe you could take a look at the issue we're having when doing it ourselves?
The "cannot find module" error looks like a bug in aspnet-webpack because it does work with server-side prerendering disabled. E.g. this works:
Do you want me to open a new issue? Maybe provide a repro? I think you'll hit the issue pretty easily if you try to set up a project with sass, but let me know :).
@tinchou Are you on the current version of Microsoft.AspNetCore.NodeServices? The current version is 1.0.0-beta-000011. Versions prior to beta 10 had an issue around module resolution that might possibly have caused your Cannot find module errors.
I ask this because I just tried setting up a CSS preprocessor (I used LESS), and in all cases it just worked fine. It works both with loader: extractCSS.extract('css!less') to strip out the generated CSS into a regular standalone .css file, and with loaders: ['to-string-loader', 'css-loader', 'less-loader'] (and in component, styles: [require('../../styles/site.less')]) for Angular 2 style encapsulation. I have not experienced any Cannot find module errors in any case.
And if you try to use an array as configuration (allowed by webpack as seen here) you get this exception
I see - thanks for letting me know!
For WebpackDevMiddleware.ts, it does seem reasonable that we could and should support array-style Webpack configurations. It just needs to preprocess them all in the same way, and then return to .NET an array of PublicPath values instead of just one.
For LoadViaWebpack.ts, I don't quite see how it makes sense to support array-style Webpack configurations, unless the developer also has a way of specifying which of their webpack configs is the one they want to use to build this particular file (given that more than one of the configs might be able to build it, possibly in different ways). Maybe if you need this, it would make sense to have each of your configs in separate files, and then combine them into a top-level one like this:
// Top level webpack.config.js
module.exports = [
require('./webpack.config.first.js'),
require('./webpack.config.second.js')
];
... and then when using prerendering, you could specify which config you want to use to build the boot module, e.g.:
Closing now as I'm fairly convinced this works (it certainly does work as documented). But if anyone finds issues with LESS and Angular 2 RC5 in particular, please file a new issue with repro info!
@SteveSandersonMS
I followed the documentation to configure less loading, but I can only make it work when I import less files in boot-client.tsx. If I import less files in, say, ClientApp/components/Layout.tsx, I got this error
Exception: Call to Node module failed with error: Error: Webpack compilation reported errors. Compiler output follows: Hash: 73b83ecc6b0630c3f216
Version: webpack 1.13.2
Time: 4079ms
Asset Size Chunks Chunk Names
webpack-output.js 93.9 kB 0 [emitted] main
ERROR in ./ClientApp/css/layout.less
Module build failed: Error: Cannot find module './../../node_modules/css-loader/lib/css-base.js'
at Function.Module._resolveFilename (module.js:455:15)
If I run webpack manually, I could see the style bundle output correctly.
I can only make it work when I import less files in boot-client.tsx
That is as expected. It works to import them in boot-client.tsx, because code in that file doesn't run on the server. If you import them to some other file that does execute on the server, then you're trying to run css-loader the server, which it doesn't support (it would be meaningless for css-loader to support server-side execution - there's no DOM to put the styles into).
You should either reference your client-only resources from boot-client (so they only load on the client), or you'll need to implement some mechanism for making them not trigger any errors if they are loaded on the server. Theoretically you could implement your own version of css-loader that detects if it's running inside Node and if so does nothing.
That makes sense. Thanks for the explanation.
I've decided to solve this by creating a prerender bundle that uses css-loader/locals which doesn't embed CSS but only exports the identifier mappings. I then use this bundle in asp-prerender-webpack-config in the Home\Index.cshtml.
@tuan Great that you got it working! Would you be able to share your fix slightly more in depth? I'm struggling with the exact same problem, but being new to Webpack, I don't quite have enough context to implement your fix. Thanks :)
This does not work if I import sass files in a file that is rendered on the server because of the reason Steven pointed out.
So I created another config just for creating a bundle that will be executed on the server. Let's name it webpack.config.prerender.js. In this config I have
Note: I don't use extract text plugin in this config. Also, I use css/locals instead of css loader.
You can create a helper to share the common settings between your webpack.config.js and webpack.config.prerender.js
In Home\index.html, I use the new webpack.config.prerender.js instead. Here's the diff
Hey guys, I finally updated my packages and I'm ready to sort this out. @SteveSandersonMS says it would be meaningless for css-loader to support server-side execution - there's no DOM to put the styles into, but I think this is not correct.
In my scenario, I'm trying to pass SCSS to Angular 2, and the only reason I need to use css-loader is because otherwise the url() links are wrong. E.g.:
If I were writing the style directly in the styles property (no require involved), then Angular would have no problem with this.
So, if it is really true that css-loader doesn't work on server-side, then I'll ask them what's wrong with that (remember this loader only grabs a CSS file and transforms it into another, no DOM manipulation involved without other loaders). I think it should work but we have a bug somewhere that gives us cannot find module './../../node_modules/css-loader/lib/css-base.js'.
If this solution needs to use require to load the .html and .css/.scss files, doesn't that mean I can't use other third-party components that don't use require? That would be a big problem.
@tinchou@RobCannon You should be able to do sass with require & loaders taking advantage of everything if I'm not mistaken. Are you not able to right now?
The reason we use require is to simply inject the raw text from the file and insert it into template or styles (webpack does that) then the loaders come and do the rest. Also that way we don't have to be specific about the URL location of our files, which is always nice :)
require("./some-styles.scss");
If you have the loaders set up correctly, I believe roughly like so:
loaders: [
// Support for CSS as raw text
{test: /\.css$/, loader: 'raw'},
//sass loader implementation
{test: /\.scss$/, loaders: ["style", "css", "sass"]},
@MarkPieszak, thanks for your quick reply! This is what I'm trying to use and that's not working with ASP.NET. The error is the one above: the server can't find the css loader and fails to prerender.
@tinchou Yes, you're right! I was conflating css-loader with style-loader, but now I see how you're using css-loader without style-loader. I'm now looking into what stops css-loader from working standalone during server-side execution.
@tinchouhttps://github.com/tinchou Yes, you're right! I was conflating
css-loader with style-loader, but now I see how you're using css-loader
without style-loader. I'm now looking into what stops css-loader from
working standalone during server-side execution.
OK, I tracked it down. It was an incompatibility between css-loader and ExternalsPlugin, because css-loader dynamically generates a relative-path require to one of its own files (i.e., ./../../node_modules/css-loader/lib/css-base.js), but ExternalsPlugin doesn't handle relative paths properly (it ignores the data.context value, which indicates what relative paths should be resolved against, and just emits the relative path string directly even if the module it's emitting will go in a totally different path).
Instead of trying to get ExternalsPlugin fixed, an easier solution was just to remove it, and replace it with webpack-node-externals instead, which also happens to be a much more actively-maintained plugin, so is probably a better choice anyway.
I've published an update to aspnet-webpack, so if you update to the latest version (i.e., run npm install aspnet-webpack), then you should find the problem disappears.
Also I'm changing the default Angular2Spa template so that it uses css-loader by default now, because otherwise (like you've pointed out), things like url(...) references in CSS wouldn't work, and lots of people would struggle with that. See 925f47f
In conclusion, thanks @tinchou for persisting with pointing this out - things are much better now this is fixed!
OK, I tracked it down. It was an incompatibility between css-loader and
ExternalsPlugin, because css-loader dynamically generates a relative-path
require to one of its own files (i.e.,
./../../node_modules/css-loader/lib/css-base.js), but ExternalsPlugin
doesn't handle relative paths properly (it ignores the data.context
value, which indicates what relative paths should be resolved against, and
just emits the relative path string directly even if the module it's
emitting will go in a totally different path).
Instead of trying to get ExternalsPlugin fixed, an easier solution was
just to remove it, and replace it with webpack-node-externals https://www.npmjs.com/package/webpack-node-externals instead, which
also happens to be a much more actively-maintained plugin, so is probably a
better choice anyway.
I've published an update to aspnet-webpack, so if you update to the
latest version (i.e., run npm install aspnet-webpack), then you should
find the problem disappears.
Also I'm changing the default Angular2Spa template so that it uses
css-loader by default now, because otherwise (like you've pointed out),
things like url(...) references in CSS wouldn't work, and lots of people
would struggle with that. See 925f47f 925f47f
In conclusion, thanks @tinchouhttps://github.com/tinchou for
persisting with pointing this out - things are much better now this is
fixed!
Activity
laskoviymishka commentedon Jun 15, 2016
This is easily handle by adding Sass or Less loader in webpack.config. Or you propose to made it in yo-templates? This possibly should be an option of generator.
nojaf commentedon Jun 15, 2016
Yes indeed an extra option in the yeoman thing
SteveSandersonMS commentedon Jun 21, 2016
Thanks for the suggestion. I'm not sure whether we'll handle it by adding further options to the generator, or by adding docs describing how to do it.
But it should be really straightforwards - just amend your
webpack.config.jsto specify a loader for your SASS/LESS/etc files. In that sense it's more of a webpack question than anything about this project, but I appreciate we should make that obvious in docs so people know there's no other hidden steps they need to follow :)RobCannon commentedon Jul 20, 2016
I highly recommend that you make it an option in the generator, otherwise you will get a lot of issues for people trying to set it up themselves.
colltoaction commentedon Jul 28, 2016
I'm actually having trouble with getting sass to work with prerendering. Does anyone have a working
webpack.config.jsfor sass?EDIT:
I'm no webpack expert, but I made it work. I don't really understand the implications of the following settings, maybe someone can shed some light. Based on webpack/css-loader#59
shobman commentedon Aug 7, 2016
An option in the generator would go awesome. I'm having trouble getting it to work for less.
I added the loader to the
webpack.config.jsfile directly after the existing .css line:{ test: /\.less/, loader: extractCSS.extract('css!less') }It works when i run 'webpack' directly at the CLI, but when I run 'dotnet run' there's an exception in the middleware when I make the first page request.
Has anyone got this working?
colltoaction commentedon Aug 7, 2016
@shobman did you check my last comment? I couldn't make it work with
extracttext, but it does without it.colltoaction commentedon Aug 9, 2016
I'm sorry, I was terribly wrong. The issue here is that we need different webpack bundles for both configurations (we need different module loaders for sass browser vs sass server as the webpack maintainers show here), but this is not supported by aspnet-webpack.
See how the configuration is tweaked to work in the backend here: https://github.com/aspnet/JavaScriptServices/blob/master/src/Microsoft.AspNetCore.SpaServices/npm/aspnet-webpack/src/LoadViaWebpack.ts#L37. And if you try to use an array as configuration (allowed by webpack as seen here) you get this exception https://github.com/webpack/webpack/blob/8ff6cb5fedfc487665bb5dd8ecedf5d4ea306b51/lib/MultiCompiler.js#L39.
This is effectively breaking one of webpacks features, and it makes me wonder if this is the correct approach. Maybe instead of overriding the configuration we could define two configurations, and let aspnet-webpack search for the one it needs.
I'm close to making this work by manually tweaking
LoadViaWebpack.ts, I'll share when it does work.colltoaction commentedon Aug 10, 2016
Well, I made it work, but not 100% with angular2. Either you:
extractCSSbut lose style encapsulationextractCSSat all, at the cost of not having styles in case client-side javascript is disabled (and also for the prerendered page before the framework kicks-in)Steps:
Read this to understand what are the requirements for the webpack side of things
css-loader?moduleparameter if you're using angular2: it'll break things because angular2 has built-in style scopingEdit
webpack.config.jsEdit
node_modules/aspnet-webpack/LoadViaWebpack.js(must do it again if updating the module!)Hope someone figures out how to make this fully work!
colltoaction commentedon Aug 11, 2016
It almost works using
loaders: ['raw-loader', 'sass-loader']as suggested in this post, but then you are missing thecss-loaderand don't get url resolving (e.g. for images).If you try to use
loaders: ['to-string-loader', 'css-loader', 'sass-loader']or similar you get theCannot find module './../../node_modules/css-loader/lib/css-base.js'error that was mentioned by @shobman, which I'm pretty sure is an error in the webpack prerendering configuration. I'll take a look later.colltoaction commentedon Aug 19, 2016
@SteveSandersonMS @laskoviymishka I know you're not providing a built-in css-preprocessor support, but maybe you could take a look at the issue we're having when doing it ourselves?
The "cannot find module" error looks like a bug in
aspnet-webpackbecause it does work with server-side prerendering disabled. E.g. this works:Do you want me to open a new issue? Maybe provide a repro? I think you'll hit the issue pretty easily if you try to set up a project with sass, but let me know :).
SteveSandersonMS commentedon Aug 20, 2016
@tinchou Are you on the current version of
Microsoft.AspNetCore.NodeServices? The current version is1.0.0-beta-000011. Versions prior to beta 10 had an issue around module resolution that might possibly have caused yourCannot find moduleerrors.I ask this because I just tried setting up a CSS preprocessor (I used LESS), and in all cases it just worked fine. It works both with
loader: extractCSS.extract('css!less')to strip out the generated CSS into a regular standalone.cssfile, and withloaders: ['to-string-loader', 'css-loader', 'less-loader'](and in component,styles: [require('../../styles/site.less')]) for Angular 2 style encapsulation. I have not experienced anyCannot find moduleerrors in any case.I see - thanks for letting me know!
For
WebpackDevMiddleware.ts, it does seem reasonable that we could and should support array-style Webpack configurations. It just needs to preprocess them all in the same way, and then return to .NET an array ofPublicPathvalues instead of just one.For
LoadViaWebpack.ts, I don't quite see how it makes sense to support array-style Webpack configurations, unless the developer also has a way of specifying which of their webpack configs is the one they want to use to build this particular file (given that more than one of the configs might be able to build it, possibly in different ways). Maybe if you need this, it would make sense to have each of your configs in separate files, and then combine them into a top-level one like this:... and then when using prerendering, you could specify which config you want to use to build the boot module, e.g.:
What do you think?
colltoaction commentedon Aug 20, 2016
@SteveSandersonMS I had just updated to RC5, and it's not yet supported in universal (see angular/universal#511).
I'll try it when they release an updated package and I'll post here.
SteveSandersonMS commentedon Sep 1, 2016
I've added some detailed docs on ways to configure LESS/SASS/etc loading: https://github.com/aspnet/JavaScriptServices/tree/dev/src/Microsoft.AspNetCore.SpaServices#example-a-simple-webpack-setup-that-builds-less
Closing now as I'm fairly convinced this works (it certainly does work as documented). But if anyone finds issues with LESS and Angular 2 RC5 in particular, please file a new issue with repro info!
2 remaining items
tuan commentedon Sep 6, 2016
@SteveSandersonMS
I followed the documentation to configure less loading, but I can only make it work when I import less files in boot-client.tsx. If I import less files in, say, ClientApp/components/Layout.tsx, I got this error
If I run webpack manually, I could see the style bundle output correctly.
tuan commentedon Sep 6, 2016
Related issue: #241
I removed my webpack config for preprocessing less files and just tried to import relative css file, and I got the same error.
Below is the diff between my changes and the sample code:
SteveSandersonMS commentedon Sep 8, 2016
That is as expected. It works to import them in
boot-client.tsx, because code in that file doesn't run on the server. If you import them to some other file that does execute on the server, then you're trying to runcss-loaderthe server, which it doesn't support (it would be meaningless forcss-loaderto support server-side execution - there's no DOM to put the styles into).You should either reference your client-only resources from
boot-client(so they only load on the client), or you'll need to implement some mechanism for making them not trigger any errors if they are loaded on the server. Theoretically you could implement your own version ofcss-loaderthat detects if it's running inside Node and if so does nothing.tuan commentedon Sep 8, 2016
That makes sense. Thanks for the explanation.
I've decided to solve this by creating a prerender bundle that uses
css-loader/localswhich doesn't embed CSS but only exports the identifier mappings. I then use this bundle in asp-prerender-webpack-config in the Home\Index.cshtml.paulinfrancis commentedon Sep 9, 2016
@tuan Great that you got it working! Would you be able to share your fix slightly more in depth? I'm struggling with the exact same problem, but being new to Webpack, I don't quite have enough context to implement your fix. Thanks :)
tuan commentedon Sep 9, 2016
@paulinfrancis
I use sass so in my webpack.config.js I have
This does not work if I import sass files in a file that is rendered on the server because of the reason Steven pointed out.
So I created another config just for creating a bundle that will be executed on the server. Let's name it webpack.config.prerender.js. In this config I have
Note: I don't use extract text plugin in this config. Also, I use
css/localsinstead ofcssloader.You can create a helper to share the common settings between your
webpack.config.jsandwebpack.config.prerender.jsIn Home\index.html, I use the new webpack.config.prerender.js instead. Here's the diff
Hope this helps!
colltoaction commentedon Sep 19, 2016
Hey guys, I finally updated my packages and I'm ready to sort this out. @SteveSandersonMS says
it would be meaningless for css-loader to support server-side execution - there's no DOM to put the styles into, but I think this is not correct.In my scenario, I'm trying to pass SCSS to Angular 2, and the only reason I need to use
css-loaderis because otherwise theurl()links are wrong. E.g.:If I were writing the style directly in the
stylesproperty (norequireinvolved), then Angular would have no problem with this.So, if it is really true that
css-loaderdoesn't work on server-side, then I'll ask them what's wrong with that (remember this loader only grabs a CSS file and transforms it into another, no DOM manipulation involved without other loaders). I think it should work but we have a bug somewhere that gives uscannot find module './../../node_modules/css-loader/lib/css-base.js'.My next step is to download a starter template that doesn't use ASP.NET (like this one https://github.com/angular/universal-starter) and check if it does work.
@MarkPieszak I've seen you collaborating on integrating this and Universal, so maybe you can share your thoughts? Thanks! :)
RobCannon commentedon Sep 20, 2016
If this solution needs to use require to load the .html and .css/.scss files, doesn't that mean I can't use other third-party components that don't use require? That would be a big problem.
MarkPieszak commentedon Sep 20, 2016
@tinchou @RobCannon You should be able to do sass with require & loaders taking advantage of everything if I'm not mistaken. Are you not able to right now?
The reason we use require is to simply inject the raw text from the file and insert it into
templateorstyles(webpack does that) then the loaders come and do the rest. Also that way we don't have to be specific about the URL location of our files, which is always nice :)If you have the loaders set up correctly, I believe roughly like so:
I'd have to double check the exact setup.
colltoaction commentedon Sep 20, 2016
@MarkPieszak, thanks for your quick reply! This is what I'm trying to use and that's not working with ASP.NET. The error is the one above: the server can't find the css loader and fails to prerender.
SteveSandersonMS commentedon Sep 20, 2016
@tinchou Yes, you're right! I was conflating
css-loaderwithstyle-loader, but now I see how you're usingcss-loaderwithoutstyle-loader. I'm now looking into what stopscss-loaderfrom working standalone during server-side execution.colltoaction commentedon Sep 20, 2016
Awesome! Feels good not to be crazy after all 😜
On Tue, Sep 20, 2016, 07:19 Steve Sanderson notifications@github.com
wrote:
In aspnet-webpack, replace ExternalsPlugin with webpack-node-external…
SteveSandersonMS commentedon Sep 20, 2016
OK, I tracked it down. It was an incompatibility between
css-loaderandExternalsPlugin, becausecss-loaderdynamically generates a relative-pathrequireto one of its own files (i.e.,./../../node_modules/css-loader/lib/css-base.js), butExternalsPlugindoesn't handle relative paths properly (it ignores thedata.contextvalue, which indicates what relative paths should be resolved against, and just emits the relative path string directly even if the module it's emitting will go in a totally different path).Instead of trying to get
ExternalsPluginfixed, an easier solution was just to remove it, and replace it withwebpack-node-externalsinstead, which also happens to be a much more actively-maintained plugin, so is probably a better choice anyway.I've published an update to
aspnet-webpack, so if you update to the latest version (i.e., runnpm install aspnet-webpack), then you should find the problem disappears.Also I'm changing the default Angular2Spa template so that it uses
css-loaderby default now, because otherwise (like you've pointed out), things likeurl(...)references in CSS wouldn't work, and lots of people would struggle with that. See 925f47fIn conclusion, thanks @tinchou for persisting with pointing this out - things are much better now this is fixed!
colltoaction commentedon Sep 20, 2016
Dude it works great. Thanks to you!
On Tue, Sep 20, 2016 at 12:57 PM Steve Sanderson notifications@github.com
wrote: