Sometimes I want to define a constant, which is to be used in both LESS and Typescript. What is the best way for achieving that?
I'm not sure you have any common ground here - unless you are going to parse the variable by reading one language from the other.
You could use a server-side language to inject the constant into both a LESS file and a TypeScript file, but this could be overkill.
One possible solution would be to detect the value that was used in the LESS file by inspecting the DOM result, for example if you had a width in LESS defined as a constant, you could inspect the width of the element in TypeScript to get the result.
The below has not been tested. If I decide to do this in my own work then I'll check it.
Put your constants in a standalone JavaScript file, in an object constants.js:
export const shareWithLess = {
constantName: '400px'
};
Write a little node script to generate a constants file for LESS:
const constants = require('./constants.js');
for (const [name, value] of Object.entries(constants) {
if (typeof value === 'number')
console.log(`#${name}: #{value};`);
else if (typeof value === 'string')
console.log(`#${name}: '#{value}';`);
else
throw new Error(`Unexpected type for value of '${name}' in constants.js`);
}
and run it like this:
node generateConstants.js >./constants.less
which would then contain
#constantName: 400px;
Worrying about quotes and generating a .d.ts is left as an exercise for the reader.
Related
When using Recoil.js, one creates an atom by handing atom() an object that include a key (a string):
const textState = atom({
key: 'textState', // unique ID (with respect to other atoms/selectors)
default: '', // default value (aka initial value)
});
Later on one can get the value (and a setter) by handing the thing that atom() returns to something like useRecoilState:
function TextInput() {
const [text, setText] = useRecoilState(textState);
It's fine that I need to first create the atom using atom() but after that I'd love to get the value (and the setter) using the string key. I'm imagining something like this:
function TextInput() {
const [text, setText] = useRecoilState('textState');
The use case for this is that I could then create all my atoms (and selectors) in places that make sense (i.e., higher up the hierarchy) and then have components access that state without having to include the atoms from the file that originally created them.
Is it possible to get the value/setter function for Recoil atoms/selectors using the key (the string/text) instead of having to hand useRecoilState() (etc) the thing returned from atom()?
No it's not possible. The value that the call to atom() returns is a reference to the state, that the useRecoil... hooks need to access it. This also wouldn't work with atomFamilies which need a parameter to access a specific atom.
I am also not sure what the benefit would be. You can still create the atoms somewhere up in the hierarchy if you want to. I am also not sure what you mean by "without having to include the atoms from the file that originally created them". What would be the problem with that?
The whole idea of Recoil is to have a state tree orthogonal to your component tree, so there is no need for creation higher up in the hierarchy. Atoms are created where they are needed during runtime.
It feels like you want to have more of a redux like pattern with atoms being created in one place up in the component tree, which defies this core idea of recoil that is setting it apart from the more flux like state management patterns.
How can I check if a riot tag has already been loaded and compiled (in-browser with script tag), in order to avoid doing it again, programmatically.
In other words, what should I use instead of doesTagExist function in my simplified code, below?
if (!doesTagExist('my-tag')) {
riot.compile('/path/to/my-tag', function() {
riot.mount('dom-node', 'my-tag');
});
} else {
riot.mount('dom-node', 'my-tag');
}
had same problem. After bit of research I think you can't get it directly. Implementation is stored inside __TAG_IMPL which is not accessible from outside. You can however access selector for all implemented tags via riot.util.tags.selectTags(), which returns comma separated list of selectors i.e. datepicker,[data-is="datepicker"].
Oneliner for convenience
riot.util.tags.selectTags().search(/(^|,)my-tag($|,)/g) >= 0
or depending on your purity inclination
riot.util.tags.selectTags().search('"my-tag"')
Note, that first version is future-proof, if riot decides to start using single commas in selector.
I'm using this with BundleTransformer from nuget and System.Web.Optimisation in an ASP.Net app. According to various docs this minifier is supposed to "remove unreachable code". I know it's not as aggressive as google closure (which I can't use presently) but I can't get even the simplest cases to work, eg;
function foo() {
}
where foo isn't called from anywhere. I can appreciate the argument that says this might be an exported function but I can't see a way to differentiate that. All my JS code is concatenated so it would be able to say for sure whether that function was needed or not if I can find the right switches.
The only way I've found to omit unnecessary code is to use the debugLookupList property in the web.config for BundleTransformer but that seems like a sledgehammer to crack a nut. It's not very granular.
Does anyone have an example of how to write so-called 'unreachable code' that this minifier will recognise?
Here's a place to test online
I doubt the minifier has any way of knowing if a globally defined function can be removed safely (as it doesn't know the full scope). On the other hand it might not remove any unused functions and might only be interested in unreachable code (i.e. code after a return).
Using the JavaScript Module Pattern, your unused private functions would most likely get hoovered up correctly (although I've not tested this). In the example below, the minifier should only be confident about removing the function called privateFunction. Whether it considers unused functions as unreachable code is another matter.
var AmazingModule = (function() {
var module = {};
function privateFunction() {
// ..
}
module.otherFunction = function() {
// ..
};
return module;
}());
function anotherFunction() {
// ..
}
I want to understand in which case I should or have to use the evaluate function.
I have read the API doc about the evaluate function of CasperJS, but I'm unsure in which case I should use this function. And what does DOM context mean? Can somebody provide an example?
The CasperJS documentation has a pretty good description of what casper.evaluate() does.
To recap: You pass a function that will be executed in the DOM context (you can also call it the page context). You can pass some primitives as arguments to this function and return one primitive back. Keep in mind that this function that you pass to evaluate must be self contained. It cannot use variables or functions that are defined outside of this function.
CasperJS provides many good functions for everyday tasks, but you may run into a situation when you need a custom function to do something. evaluate is basically there to do
Retrieve some value from the page to take action based on it in your script
Manipulate the page in some way other than clicking or filling out a form
Combinations of points 1. and 2.
Examples
You may need a generic function to get the checked property from a checkbox. CasperJS currently only provides getElementAttribute function which will not work in this case.
function getChecked(cssSelector){
return document.querySelector(cssSelector).checked;
}
if (casper.evaluate(getChecked, selector)){
// do something
} else {
// do something else
}
In most of the cases it is just preference of what you want to use. If you have a list of users with data-uid on each li element then you have at least 2 possibilities to retrieve the uids.
Casper-only:
var uids = casper.getElementsAttribute('ul#user-list > li', 'data-uid');
Casper-Evaluate:
var uids = casper.evaluate(function(){
return Array.prototype.map.call(document.querySelectorAll('ul#user-list > li'), function(li){ return li["data-uid"]});
});
Regarding manipulation everything is possible but depends on what you want to do. Let's say you want to take screenshots of web pages, but there are some elements that you don't want to be there. Or you could add your own CSS to the document.
Remove elements:
function removeSelector(cssSelector){
var elements = document.querySelectorAll(cssSelector);
Array.prototype.forEach.call(elements, function(el){
el.parent.removeChild(el);
});
}
casper.evaluate(removeSelector, '.ad'); // if it would be that easy :)
Change site appearance through CSS:
function applyCSS(yourCss){
var style = document.createElement("style");
style.innerHTML = yourCss;
document.head.appendChild(style);
}
casper.evaluate(applyCSS, 'body { background-color: black; }'); // non-sense
Roots
CasperJS is built on top of PhantomJS and as such inherits some of its quirks. The PhantomJS documentation for page.evaluate() says this:
Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.
Closures, functions, DOM nodes, etc. will not work!
I have been using SASS for a while now, and one thing I really like is how I can use it for my FlashBuilder projects also, namely that is supports custom CSS attributes, like 'embedAsCFF' and 'unicodeRange'.
I'm trying out LESS for the first time, and it will not let me compile to CSS while using these two custom attributes:
embedAsCFF: true;
unicodeRange: U+0021, U+0023-U+0026, U+0028-U+002a, U+002c, U+002e-U+0039, U+0040-U+005d, U+0061-U+007d;
I receive a 'Less Compilation Error: Syntax Error...'
Any LESS users know how I need to add in support for these custom attributes? Thanks in advance.
Update: This issue will be resolved in the release of LESS 1.4.2
Not a Custom Name but a Format Issue
It appears on my experimenting that the issue is really the fact that you are using capital letters in the property names (not that they are custom attributes themselves). Capital letters are apparently not supported by LESS. In other words, these work:
embedascff: true;
embed-as-cff: true;
unicoderange: U+0021; //etc.
unicode-range: U+0021; //etc.
But this does not:
Color: red;
I have not for certain isolated where in the actual LESS code itself this might be fixed (if it can be fixed for the way LESS handles the property rules). I suspect the cause is in the parser.js file lines 1578-1584 (as of this writing), which are:
property: function () {
var name;
if (name = $(/^(\*?-?[_a-z0-9-]+)\s*:/)) {
return name[1];
}
}
This seems to be filtering out allowing for capital letters. I don't know what the consequences would be if that regular expression was changed to allow for them.