webpack less loader override variables for node_modules - less

I have the following project structure:
Proj.A: Repo with all less files (styles, mixins, variables, etc.)
End project
Requires Proj.A
Has config.less which sets less #variables defined on Proj.A
Expect all the components below that also requires Proj.A to get the override values set in config.less
Components (installed in End Project through npm install)
also requires Proj.A for less files (styles, mixing, variables, etc.)
requires its style through js, like require('index.less')
if variables defined in Proj.A are not override it uses the default values.
To simplify better, there is an example:
Proj.A
/*index.less*/
// declare all my variables
#bg-color: pink
Component
/* component.js */
require('component.less')
/* component.less */
#import '~projA/index.less'
End Project
/* index.js */
require('config.less')
var myComponent = require('component')
/* config.less */
#import '~projA/index.less'
#bg-color: blue
webpack config (it's a super simple webpack config, the only special thing is the less loader)
{
loaders: [
{
test: /\.less$/,
loader: ExtractTextPlugin.extract('css?sourceMap!less?sourceMap&strictMath')
}
]
}
I expect that if I require Component isolated it should get a #bg-color: pink. But if it's required from End Project it should get a #bg-color: blue.
For now it aways get pink. Is there a way to tell webpack | less-loader to not bundle separately or have some kind of association with specific node_modules. I'd like to know how can I solve this problem, perhaps creating a new loader ?
Thanks!

Very simple solution if you control all parts (maybe a little hacky):
Component
/* component.js */
require('component.less')
/* component.less */
#import '~projA/index.less'
#import (optional) "#{THEME}"; /* if optional works, not tested */
End Project
/* index.js */
var myComponent = require('component')
/* config.less */
#bg-color: blue
webpack config
{
loaders: [
{
test: /\.less$/,
loader: ExtractTextPlugin.extract('css?sourceMap!less?{"modifyVars":{"THEME":"\'' + path.resolve('config.less') + '\'"}}')
}
]
}

Without your webpack configuration, it is hard to tell what you're doing exactly, so I can only tell you what I know.
What I've done in the past is used a chained loader for my styles (style!css!less). The style-loader has a nifty piece of functionality in it for "reference-counted styles" or as I like to call them useables.
The idea is that your components can "use" and "unuse" less files and the webpack style-loader will add/remove these less files from the DOM as needed so you have a little more control over what styles are loaded and not loaded.
See this github page for some more information.

Related

How to bundle tailwind css inside a Vue Component Package

In one of my projects, I build a nice vue3 component that could be useful to several other projects. So I decided to publish it as an NPM package and share it with everyone.
I wrote the isolate component, build it and publish BUT I use Tailwind css to make the style.
When I publish and install the component everything is working BUT without the beauty of the css part.
I tried several configurations and alternative tools to generate the package that automatically add the tailwind as an inner dependency to my package.
Does someone have experience with this? how can build/bundle my component by adding the tailwind CSS instructions into it?
You're almost there
Since you've got your component working, the majority of the part has been done.
For configuring the styling of the component you need to identify the Tailwind CSS classes being used by your Vue component package and retain them in the final CSS that is generated by the Tailwind engine in your project.
Follow below steps in the project where you want to use your tailwind vue component package.
For Tailwind CSS V3
// tailwind.config.js
module.exports = [
//...
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
"./node_modules/package-name/**/*.{vue,js,ts,jsx,tsx}" // Add this line
// Replace "package-name" with the name of the dependency package
],
//...
]
For Tailwind CSS V2
// tailwind.config.js
module.exports = [
//...
purge: {
//...
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
"./node_modules/package-name/**/*.{vue,js,ts,jsx,tsx}" // Add this line
// Replace "package-name" with the name of the dependency package
],
//...
//...
}
]
The content property in the tailwind.config.js file defines file path pattern that the tailwind engine should look into, for generating the final CSS file.
For Pro users
You may also try to automate the above setup by writing an install script for your npm package to add this configuration to the tailwind.config.js file
References
Tailwind Docs - 3rd party integration
It's a bit difficult for someone to answer your question as you've not really shared the source code, but thankfully (and a bit incorrectly), you've published the src directory to npm.
The core issue here is that when you're building a component library, you are running npm run build:npm which translates to vue-cli-service build --target lib --name getjvNumPad src/index.js.
The index.js reads as follows:
import component from './components/numeric-pad.vue'
// Declare install function executed by Vue.use()
export function install (Vue) {
if (install.installed) return
install.installed = true
Vue.component('getjv-num-pad', component)
}
// Create module definition for Vue.use()
const plugin = {
install
}
// Auto-install when vue is found (eg. in browser via <script> tag)
let GlobalVue = null
if (typeof window !== 'undefined') {
GlobalVue = window.Vue
} else if (typeof global !== 'undefined') {
GlobalVue = global.Vue
}
if (GlobalVue) {
GlobalVue.use(plugin)
}
// To allow use as module (npm/webpack/etc.) export component
export default component
There is no mention of importing any CSS, hence no CSS included in the built version.
The simplest solution would be to include the index.css import in your index.js or the src/components/numeric-pad.vue file under the <style> section.
Lastly, I'm a bit rusty on how components are built, but you might find that Vue outputs the CSS as a separate file. In that case, you would also need to update your package.json to include an exports field.

Importing SCSS variables in Vue components

I recently switched from Vue-CLI to laravel-mix, the usage of SCSS variables worked perfectly with Vue-CLI and now doesnt seem to work anymore at all after I switched to laravel-mix.
Vue-CLI just handled everything for me and I feel like I have to configure something to get the variables to work in laravel-mix.
This is what I've tried (and what worked with Vue-CLI):
// vue component
import variables from "#/styles/variables.scss";
// ...
data() {
return {
variables
}
}
methods: {
test() {
console.log(this.variables)
}
}
// scss
$variable: #FFFFFF;
:export {
variable: $variable;
}
Edit: To clarify, this log outputs an empty object, not undefined.
For this thing to work you need to follow that particular steps
Make Your Variables File. As you made your scss file inside your style its not good you need to make inside /assets/sass/
Add Variables File To App.scss. For that thing you need to import newly create file inside your app.scss by #import 'folder/file';
Add Alias To webpack.mix.js. What we essentially need to do is define an alias or variable that contains the path to our sass directory so we can include that SASS in our Vue components. Just add alias like this in your webpack
resolve: {
alias: {
'#': path.resolve('resources/assets/sass')
}
}
Last thing add Navigation Vue Component. You can import scss variables by adding #import '~#/folder/fie.scss'; in the vue component

Is that possible to generate correct indenting code with nuxt js

When i'm generating the project with nuxtjs, the code is compressed.
I would like to know if it's possible to generate a correct indenting code ?
Thanks
The minimization is done by Webpack. You can change the Webpack config in your nuxt.config.js file under the extend option of the build property. To disable minimization, you need to set config.optimization.minimize to false.
For example, in your nuxt.config.js file:
build: {
/*
** You can extend webpack config here
*/
extend(config, ctx) {
config.optimization.minimize = false;
}
},
You probably wouldn't want to do this in production though. Minimization is a standard practice to help reduce the size of your JavaScript files.

Vue SFC add global Sass variables to all components

Im my webpack config I add a path
"mixins": path.resolve(
__dirname,
"resources/assets/sass/mixins/mixins.scss"
),
Which means in all my single file components I use
<style lang='scss' scoped>
#import '~variables';
This works fine but what I am finding is this file is used in 95% of components so the import really is unnecessary. I want these vars available everywhere.
How can I globally add my SASS to my single file components without the need for the import in every file?
Well, Load your common CSS from Webpack and make it available globally for all the component. Webpack configurations are as below.
sass-loader also supports a data option which allows you to share common variables among all processed files without having to explicit import them
module.exports = {
css: {
loaderOptions: {
sass: {
data: `
#import "#/scss/_variables.scss";
#import "#/scss/_mixins.scss";
`
}
}
}
};
In here, specifing the sass loader under the loaderOptions option. Just like that, all the code in those files will be available in the global scope. So from any component we can use it out of the box:
And now you can able to access the variable in your Vue SFC without importing it.
<style lang="scss">
.classroom {
/* No need to import, it just works \o/ */
background: $bg-classroom;
}
</style>
Reference Official Docs here
Hope this helps!

Importing SCSS file in Vue SFC components without duplication with Webpack

When I try to access a scss file in all my Vue SFCs the styles are duplicated causing large css bundles and Dev Tools to crash when style debugging
I am using Webpack 4 and webpack-dev-server to build and run development services with hot reload. I did not create the project with Vue CLI.
I have quite a lot of SFCs (~50) and a sass file (index.scss) that contains global styles and variables. I need to be able to use the styles and variables in index.scss across my SFCs. My current approach is using the data option in my Webpack sass-loader.
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
},
{
test: /\.scss$/,
use: [
isDev ? { loader: 'vue-style-loader', options: { sourceMap: hasSM }} : {loader: MiniCssExtractPlugin.loader },
{
loader: 'css-loader',
options: {
sourceMap: hasSM
}
},
{
loader: 'sass-loader',
options: {
sourceMap: hasSM,
data: `#import "#/styles/index.scss";`
}
}
]
}
]
}
This is successful, however I am noticing my index.scss styles included in every component. Local development with devserver is almost impossible because the duplication across 50 components is so vast and devtools can't cope. When I do a build to extract the css then I can see the duplication and the app.css file is huge. I can use a minifying process for deployments but this is not suitable at all for local development.
I have tried other approaches such as removing the data option from sass-loader using import ./styles/index.scss in my main.js file instead, however this fails to build because it can't find the variables I use in my SFCs.
Please see my code snippet for roughly how I have my loaders set up. I feel as if there is a better way to do this, whether it's using different loaders/plugins and I am open to using different approaches
I managed to solve. Essentially when every Vue component was being processed then the sass-loader was importing my global sass file that included Variables, Mixins and most importantly my Styles. The import statement in my main.js doesn't work because the Variables and Mixins are not available by the time the component is being processed.
So I only need to import Variables and Mixins in my components and the Styles can be external and included in my main.js. Since Variable and Mixins are just being included when required (with #include statements), then there is no duplication since it's getting compile to CSS.
So I split my Styles and Variables and Mixins into separate variables
Styles => styles.scss
Variable and Mixins => variableMixins.scss
then import ./styles/styles.scss in my main.js
and my webpack sass-loader would be like
{
loader: 'sass-loader',
options: {
sourceMap: hasSM,
data: `#import "#/styles/variableMixins.scss";`
}
}
Been trying to solve this for too long.
This solution works but isn't perfect for me because I want to keep variables and global styles for specific things together.
_typography.scss, for example should contain general styles and variables relating to global line-height and vertical rhythm.
Then more granularly, a component such as _H1.scss would contain it's own sandboxed styles.
I don't want those general styles duplicated for every component.
The value of using CSS is sharing styles and being able to adjust and rebrand in a project globally. Components do the opposite of this by sandboxing everything.
I think CSS is currently at odds with componentized development and perhaps the answer may be to create a new approach where we use 'component ecosystems' to create relationships between otherwise dumb nodes.
A bit like how we use revealing module patterns in JS.
We ended up splitting up css into separate files (one per component), imporing them all into index.scss and importing index in App.vue`
import '#/scss/index.scss'
This eliminated lots of bloat / duplication and significantly simplified workflow: using sourcemaps + workspaces we can now edit scss directly in devtools and it won't break layout or multiply <style> tags or do any other quakery described all over Webpack's and vue-cli's github issues.
Surprisingly, even code-splitting for css still works, and dynamically loaded modules have their separate css files.
If you need scoping (which you'd need), just use id="component-name" on main node and wrap your scss in
#component-name {
...
}
It amazes me how unsupported modern css techniques by Devtools, Webpack etc. Every aspect is full of bugs and only simpliest scenarios sort of work out of the box (if work at all).