PostCSS import as reference instead of inline - less

Less has this handy option whereby the referenced importing file will be only used to resolve variables but it will not be inlined. Is there any way to do the same with postcss-import or any other similar PostCSS plugin?
The below block of code is how this behaviour works in Less. I'd like to achieve similar behaviour with PostCSS.
#import (reference) "foo.less";
/* Content of "foo.less" won't be inlined but variables on this different file will be resolved */
.rules {
width: #big; /* Declared in "foo.less". It will be resolved to 1200px (for example) */
}

Related

Bootstrap 4 how to overwrite scss variables that are used to define other default variables

First of all I would like to mention this question: Customize bootstrap 4 variables using it's own variables?, where it seems the same question has been asked but without fruitful answer so I thought I would ask again with a very specific example.
I basically want to overwrite some of bootstrap 4's default variables. In the example below I want to overwrite $font-size-base. I followed the recommended approach of the bootstrap documentation but it only seems to be partially working. Bootstrap's default variables (in _variables.scss) reuse other defined variables. For instance : $input-btn-font-size: $font-size-base !default;. When changing $font-size-base with the approach below however, it doesn't affect $input-btn-font-size.
#import "node_modules/bootstrap/scss/functions";
#import "node_modules/bootstrap/scss/variables";
$font-size-base: 0.9rem;
$secondary: $gray-400;
#import "node_modules/bootstrap/scss/bootstrap";
On the other hand if I use the next approach where I import the variables later, then I do get the desired result where all variables that depend on $font-size-base get changed as well. This however is not the recommended approach and becomes clear when you want to define a variable that depends on a default variable. See $secondary: $gray-400;, this then throws a compile error given that $gray-400 is unknown.
#import "node_modules/bootstrap/scss/functions";
$font-size-base: 0.9rem;
$secondary: $gray-400;
#import "node_modules/bootstrap/scss/variables";
#import "node_modules/bootstrap/scss/bootstrap";
What is the recommended solution here?
Separate the override variables....
The only overrides that need to follow the /variables import are those that reference variables (ie: $secondary: $gray-400;).
If you just want to override a variable that doesn't reference another (ie: $font-size-base: 2.9rem;) that would go before the /variables import...
/* simple overrides */
$font-size-base: 2.9rem;
#import "bootstrap/functions";
#import "bootstrap/variables";
/* var dependent overrides */
$theme-colors: (
secondary: $gray-400
);
#import "bootstrap";
https://www.codeply.com/go/wpc3XKQ8TG
Note: To override a theme color such as secondary you must update the theme-colors map.

flowtype definition of Iterable from immutable.js breaks other libs' Iterables

I just added immutable.js as a dependency to my project. I added
node_modules/immutable/dist/immutable.js.flow
to my .flowconfig.
The problem is that immutable exports an Iterable type, which is also a global type used in many other libraries that are in node_modules/, such as fbjs and react-native. For example one of the errors below.
node_modules/fbjs/lib/countDistinct.js.flow:22
22: function countDistinct<T1, T2>(iter: Iterable<T1>, selector: (item: T1) => T2): number {
^^^^^^^^^^^^ type application of identifier `Iterable`. Too few type arguments. Expected at least 2
32: declare class Iterable<K, V> extends _ImmutableIterable<K, V, typeof KeyedIterable, typeof IndexedIterable, typeof SetIterable> {}
^^^^ See type parameters of definition here. See lib: flow/immutable.js:32
In order to fix this I copied immutable.js.flow to my project and removed the .flowconfig line that includes it. In my copied file I rename Iterable to WhateverIterable and the errors are gone.
What is the best way to fix this thing without having to manually edit the immutable definitions?
The main problem is that node_modules/immutable/dist/immutable.js.flow is not written to be a library definition, so using it as one can cause errors.
What is immutable.js.flow
The docs refer to these files as declaration files. immutable.js.flow sits next to a file named immutable.js. Whenever Flow is asked to require immutable.js, it will resolve to immutable.js.flow instead. You can test this with the flow find-module command, which shows which file Flow resolves to when foo.js imports immutable:
$ flow find-module immutable foo.js
/Users/glevi/test/immutable/node_modules/immutable/dist/immutable.js.flow
Declaration files are written a little differently than libdefs. Library definitions declare a bunch of global things. They declare which variables, functions, types, classes, modules, etc are available globally, and declare the types of these things. Declaration files declare only the type of the module that they are shadowing.
A libdef for immutablejs would look like
declare module 'immutable' {
declare class Iterable<K,V> { ... }
...
}
while immutable.js.flow might look like
declare export class Iterable<K,V> { ... }
What should you do
In theory, you should not need to add node_modules/immutable/dist/immutable.js.flow to your .flowconfig. Flow should automatically use it whenever your code imports immutable.
If there is a problem with the immutable.js.flow that immutable ships with, then the best thing to do is to open a pull request or issue against immutable.js.flow or to submit a libdef to flow-typed.
A quick search shows someone working on a immutable libdef, so that might help too!

LESSCSS loop with #import (inline) causes "SyntaxError: Recursive variable definition"

I have an array:
#styles: amelia, cerulean, cosmo, cyborg, darkly, flatly, fonts, journal, lumen, readable, simplex, slate, spacelab, superhero, united, yeti;
And I have my loop:
.loopStyles (#index) when (#index > 0) {
#name: extract(#styles, #index);
.nb-#{name} {
#import (inline) 'bower_components/bootswatch/#{name}/bootstrap.css';
}
.loopStyles(#index - 1);
}
.loopStyles(length(#styles));
However this throws an error: SyntaxError: Recursive variable definition for #index.
If I remove the #import or if I change the import option reference to something other than less or inline, it works just fine.
What I'm trying to achieve is a way to prefix these extra styles with a class, so I'd prefer if the stylesheet was imported inline rather than referenced.
Less docs state "...only variables which have been declared in the root or current scope will be considered and that only the current file and calling files will be considered when looking for a variable. This means that this usage is typically limited to when you inject a variable into the compile process or define a variable at the beginning of your root file."
I've gotten a lot of irrelevant errors while trying to get this to work.

What does "forceCompile" mean on YII when you use Less?

I have this:
'components'=>array(
'less'=>array(
'class'=>'ext.less.components.LessCompiler',
'forceCompile'=> true, //YII_DEBUG, // indicates whether to force compiling
//'compress'=>false, // indicates whether to compress compiled CSS
//'debug'=>false, // indicates whether to enable compiler debugging mode
'paths'=>array(
'less/style.less'=>'css/style.css',
),
),
If I enable forceCompile my site is extremely slow. I would imagine because it regenerates the css on each page load. My question is around disabling it. If I disable it:
Will any changes I make to style.less not reflect in the browser?
If so, what is the point of Less? Surely it can't actually be used in production then? Or do you disable forceCompile so it only generates it once?
Any clarity on forceCompile would be highly appreciated!
(And yes, I looked all of for a clear explanation... best I could find was this).
First let me tell you what is the point of less:
less is a meta language, so in general terms using less helps you write easily maintainable css, although the "language" used is less syntax. As a common example, you can define variables in less that are compiled to css values according to the other statements in your less file. Or you can use mixins, nesting, inheritance concepts like you would in most other languages that support OOP.
So you write understandable, readable pseudo/meta css code that is converted to actual css upon compilation.
Now the extension:
Even if you disable forceCompile, the changes made in style.less should reflect, because the extension checks if the file was modified (the following lines from LessCompiler.php should convince you about that):
if ($this->forceCompile || $this->hasChanges())
$this->compileAll();
// ...
/**
* Returns whether any of files configured to be compiled has changed.
* #return boolean the result.
*/
protected function hasChanges() {
// ...
$compiled = $this->getLastModified($destination);
// ...
$modified = $this->getLastModified($dir);
// ...
}
/**
* Returns the last modified for a specific path.
* #param string $path the path.
* #return integer the last modified (as a timestamp).
*/
protected function getLastModified($path){
//...
}
So forceCompile will always compile the file(s) you specify in paths, and you should not enable it in production. The hasChanges call should take care of less files that have been modified, and compile them, which as you see above is automatically done by the extension.

Pass a variable to sass from programming language (coldfusion or PHP)

I would like to pass a variable to my sass from coldfusion or php.
Above I declare a var that I need to pass to sass to set a container-size in my _base.sass.
Is there a way to do it?
Use the !default flag in your variable to do this. here's what i mean
// SCSS file
#import "php-variables"; // have php write this file first before compiling
#import "variables"; // custom colors, font-sizes, etc.
// contents of php-variables
$myvar: #f00; // the value you're setting with php
// contents of variables
$myvar: #0f0 !default; // the value to use if php DOESN't override it.
This way you can still have a fallback for if your php code doesn't need to override a var. anything you write in the php file will be declared first. then as long as your variables file uses the !default flag on ALL variables then it won't override the php set ones.
more info here:
http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#variable_defaults_
I have tested this with the php compiler at http://www.phpsass.com/ and it works.
I think you should be writing directly to the sass file through php/coldfusion. I doubt there is another way to do it.
An easy way to do this would just be to put your variable on your first line in the sass file or something and just overwrite the value using PHP.
The cleanest solution i found was to do the following. In your html file (mine is a Blade template) you can inject your variable ($bodyBgColour):
<style>
:root {
--main-bg-color: {{ $bodyBgColour }}
</style>
Then in your scss file you can use it:
$background-colour: var(--main-bg-color);
And you can subsequently use that sass variable in your classes:
body {
background-color: $background-colour;
}