Why <style scoped> is not being parsed - vue-component

Just getting started with Vue and I can't get the <style scoped> to be processed by Vue. It fails to add the the proper attributes keys to my template elements and fails to augment the CSS classes with attribute specificity. It just behaves like "scoped" was not defined. I am not running any kind of build pipeline framework. Do I have to run some pre-processor or transpiler for this to work? I don't get how the Vue framework is even supposed to know which style block should be scoped to what Vue component since I bundle all my styles in one file.

Scoped css is a feature that is provided by using vue-loader, you can find the documentation here: https://vue-loader.vuejs.org/#what-is-vue-loader
As it is explained there, the scoped css is compiled using webpack. A good way to get started with Vue single file components and all the benefits they bring, is to setup a new vue project using vue-cli, you can find the docs here: https://cli.vuejs.org/guide/installation.html

Related

Vue 3 / Webpack 5 Boilerplate Code Not Applying CSS Scoping

I'm migrating from my Vue 2 / Webpack 4 setup to Vue 3 / Webpack 5.
Here's my boilerplate code on GitHub, so far. It's a VS.NET project, making use of NPM Task Runner to watch and auto-transpile my vue files.
It works for the most part, save for the fact that the CSS isn't properly scoped. It does scope the injected CSS (with attributes such as 'data-v-37bfa8da'), but it doesn't apply this scoping to the HTML elements.
Ergo, the CSS isn't applied at all.
It does get applied when I leave out the 'scoped' attribute in my .vue file's CSS. But then my CSS is global: not scoped at all. But on production, you really do need automated CSS scoping.
I've tried the most often suggested fixes on SO (link 1, link 2), but nothing works:
set esModule to false in css-loader
replace vue-style-loader by style-loader
add '*.vue' to the sideEffects prop in package.json
The first suggestion is currently applied in the GitHub repo's source. The others are not.
Another person, outside of SO, showed me a working setup where he used esbuild-loader. I tried this. Also doesn't work for me.
All packages are up to date. So is my NodeJS.
I don't have so much experience with Webpack. It could be any setting in any package. I could be searching for an answer for a long time.
Is there anybody on here more experienced in Webpack, who is able to find a solution to my problem more quickly?
The fix is to add Vue as an external to webpack.config.js.
externals: {
vue: 'Vue'
}

How to add <style> tag in Vue.js component

I'm on Vue.js v2. I have a CSS stylesheet stored as a string in a variable.
import sitePackCss from '!!raw-loader!sass-loader!../../app/javascript/styles/site.sass';
I need to create a tag from my component.
<style v-html="sitePackCss" />
OR
<style>{sitePackCss}</style>
When I do either of these, I get the following error in the console:
Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as <style>, as they will not be parsed.
How do I get this tag onto the page?
NOTE: I know this is a hacky, non-preferred way to include styles. This solution will only get used in the context of storybook, where I need to include specific CSS files for specific stories (without storybook/webpack adding them to every story). If I use normal webpack loaders, each tag is added to every story. Importing the styles as a string is the only way I've found to sidestep that behavior.
Try to add the style to the src tag of the style in your SFC :
<style lang="sass" src="../../app/javascript/styles/site.sass">
</style>
This seems to work!
import sitePackCss from '!!raw-loader!sass-loader!../../app/javascript/styles/site.sass';
In template:
<component is="style" type="text/css">${sitePackCss}</component>
Note: the sass files have references to fonts that were not working correctly using this technique. I had to update the staticDirs config to make those paths work. https://storybook.js.org/docs/react/configure/images-and-assets

Reducing CSS code duplication when scoping styles in Vue component

It is possible to scope styles in Vue component using this approach:
<style scoped src="bootstrap.css"></style>
But issue here arises when there are several components on a page using bootstrap and scoping it several times leads to a CSS code duplication issue - bootstrap.css is included multiple times.
Is there a way to reduce such CSS code duplication or is there another way to have scoped CSS?
Building using webpack and gulp task runner through Visual Studio
It is a legacy ASP.NET Web Forms app and importing styles globally breaks page styling.
Holy grail here is that adding scoped reference to bootstrap.css in vue component, but some magic tool/plugin during webpack build step could automatically check what classes are being used and scope (or extract) only those classes only, so code duplication still exists but not that huge as scoping same CSS files several times and I don't have to pick each of those classes manually and add it to scoped css section. Example of this scenario is .NET assembly weaving.
UPDATE: Ended up with using
<style scoped src="bootstrap.css"></style>

How to solve "violate CSP directive: "default-src 'self'" in Angular 8?

We have an Angular 8 single page web app deployed on the customer server. They set one of the CSP directive to: default-src 'self'. We build the Angular app using ng build --prod like any other Angular applications. After deploying, we get this error:
main-es2015.47b2dcf92b39651610c0.js:1 Refused to apply inline style because it violates the following Content Security Policy directive: "default-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback.
Look into the html code on the browser, I see something like this:
As you can see, Angular actually use tag <style> to serve the css (please correct me if I'm wrong). This violates the CSP directive mentioned in the question.
After searching around, I think Angular/React is quite bad at handling this issue, those frameworks are not built with CSP in mind. You can check out Angular github page, there is an open issue for this. Now I'm searching for a solution to overcome this, of course changing CSP policy is not an option because the customers don't want to.
How can I tell Angular not to use tag <style> in production to serve css? I think to make it works we need to set Angular in a way that it will load the css files, and then use styles in those files instead of injecting <style> into html which causes CSP issue.
Edit 1: Our project is using scss.
Edit 2: After searching around, I have found out that Angular will inject your component's styles into the DOM by using <style> element. As shown here:
Now I have an idea, because for each compinent's style will be injeced into the DOM through <style> element, we can prevent this from happening by bundling all component's style .scss file into a single style.scss file. From the image above you can see that we always have an empty <style> element, so if this works, we will endup with only one <style> element and a <link> element that link to our global style scss file. We can have multiple way to remove that empty <style> element before the page got rendered by the browser.
Now I'm stuck at configuring custom webpack to make this happen. We cant use ng eject to get the webpack.config.js file since Angular CLI 6. I've been using Angular CLI 8 so the only way for me to add custom configuration into Webpack is to use custom-webpack npm. I cant find a good config file that has the same output as my desire, please help if you know how to config webpack to bundle all component's styles scss files in Angular into a global scss file.
I think this can be an acceptable answer for my question:
First of all, my recommendation is stay away from using styleUrls. Angular will inject styles of your component into the DOM using <style> element. Secondly, if it's possible, you should know / ask for the CSP policy on the deployment server/environment. What I have been doing to resolve the issue (my project is reletively small with just a couple dozen of components):
Copy (one by one) relative link of components, put them into angular.json, in styles attribute. This is because Angular will bundle all styles in this attribute as a single css/scss file. I copy one by one because the css/scss file was designed to work with Angular View Encapsulation in the first place. Gathering all of them into one place might introduct unexpected issue, this will break the UI. Whenever copy a component style and put into styles, I check if the UI breaks because of that. This will help me narrow down the root cause if such issue happens.
For each component, after copy its component style file's relative path into styles, I remove styleUrls in #Component. This prevents Angular from injecting <style> into the DOM.
Caveats:
Gathering all styles into one single file and load them at once might cause performance issue. Luckily my company project is relatively small.
Now you need to document the new way of making styling work in your project.

Page specific css not loading

I use nativescript with VueJs
My problem is that my page specified CSS files aren't used.
My start page is start.js and in the same folder I have a start.css
but the styles aren't applied.
Do I need to something else, or configure?
Because at the docs I said that it normally should work like this.
Always refer the appropriate docs for the flavour, since you are using Vue you must follow the docs here. What you were referring to was for core js one.
With NativeScript Vue you have to write scoped styles within your component, just the same way how you would do it for a Vue based web app.
An external file can be used as Page-Specific CSS as follows in NativeScript-Vue:
<style scoped src="./Home.css"></style>
Where, Home.css is located in your components folder.
Similarly, for SCSS:
<style lang="scss" scoped src="./Home.scss"></style>
Note: You'll need to rebuild your app by if its running on an emulator/device when you make this addition to your .Vue file.

Resources