Less.js: Comment déclencher des importations synchronisées et asynchrones

Créé le 7 déc. 2014  ·  26Commentaires  ·  Source: less/less.js

Comment less décident-ils d'appeler loadFile ou loadFileSync du fileManager actuel ? Selon ce code , un paramètre isSync doit être défini. Mais une courte recherche d'un appel à getFileManager révèle que cette option n'est utilisée que par lib/less/functions/data-uri.js .

Est-il possible de définir explicitement cette option lors de l'appel de render() ?

feature request medium priority stale

Commentaire le plus utile

Y a-t-il déjà un renderSync ? Sinon, existe-t-il une solution de contournement pour un render synchrone ?

Edit : Nvm. Pour toute personne future qui tombe dessus, voici ce que j'ai fait :

less.renderSync = function (input, options) {
    if (!options || typeof options != "object") options = {};
    options.sync = true;
    var css;
    this.render(input, options, function (err, result) {
        if (err) throw err;
        css = result.css;
    });
    return css;
};

Tous les 26 commentaires

isSync peut être passé dans l'objet options à rendre. data-uri est toujours
sync car les fonctions ne peuvent pas être asynchrones.

Mais le importManager ne passe aucune option à getFileManager ...

C'est fait ici

https://github.com/less/less.js/blob/32dbbee247f76af00eb7577053eccad2ee5f6110/lib/less-browser/file-manager.js#L61

C'est parce que cette option est ignorée par moins de noyau et n'est spécifique qu'au navigateur. Ainsi, le navigateur est toujours appelé async et peut, selon les options, utiliser un mécanisme de synchronisation ou async pour obtenir le fichier.

Je peux voir à quel point c'est déroutant. Est-ce que ça pose problème ?

Une chose que je vois immédiatement, c'est que cela ne sera effectué que par les options au chargement de la page, donc s'il est défini par la suite ou transmis en tant qu'option, il sera ignoré.

Eh bien, je dois probablement expliquer mon cas d'utilisation :

J'ai écrit un less-loader pour webpack . Étant donné que webpack a son propre mécanisme de résolution, j'utilise un plugin pour me connecter à moins de résolution de fichiers via un gestionnaire de fichiers.

Webpack prend en charge les chargeurs synchronisés et asynchrones, mais je n'ai pas trouvé de moyen d'en dire moins pour rendre tous les fichiers synchronisés ou asynchrone. Actuellement, il appelle toujours loadFile . J'ai donc utilisé un sale hack pour appeler loadFileSync lorsqu'une compilation synchrone est demandée. Heureusement, moins fonctionne de manière synchrone lorsque le rappel est appelé de manière synchrone (ce qui ne devrait pas être fait dans des circonstances normales bien sûr).

Je vois...

Je pense que nous devrions déplacer une option asynchrone pour être sur le moins de contexte, puis l'utiliser pour déterminer quel appel faire comme vous le suggérez. Il faudra peut-être quelques modifications au gestionnaire de fichiers du navigateur, mais je pense que ce sera un bon refactor.

Frais!

Il y a juste un problème : il est très inhabituel de faire quelque chose de manière synchrone en acceptant une callback (comme le fait la fonction render ). Vous proposez une option sync comme celle-ci :

less.render(
    input,
    { ... sync: true ... },
    function (err, result) {
    }
);

?

Imho, c'est bizarre d'avoir le rappel appelé de manière synchrone. Je m'attendrais à une API comme celle-ci :

// async
less.render(input, option, callback);

// sync
var result = less.renderSync(input, option);

Oui tu as raison, c'est mieux.

+1
Il semble que cela soit également très utile d'envisager d'implémenter renderSync pour ne pas restreindre l'exécution de code dans le rappel uniquement. Dans la portée du rappel, de nombreuses méthodes telles que console.err ou throw new Error() ou une erreur JavaScript délibérée n'imprimeront rien sur la console, arrêtent seulement l'exécution du code, entraînant potentiellement des bogues qui ne peuvent pas être retracés. J'imagine que ce comportement ne devrait pas se produire.

Dans mon cas particulier, renderSync serait utilisé dans un utilitaire de ligne de commande et plutôt que de contrôler le flux de rappel à l'aide de promesses pour garantir que toutes les sorties et les erreurs sont imprimées dans l'ordre à chaque fois, je préférerais simplement utiliser renderSync et ne pas avoir s'en soucier.

(Je ne rabaisse pas le problème lui-même, mais juste pour s'assurer qu'il ne deviendra pas encore plus étrange qu'il ne l'est):

Imho, c'est bizarre d'avoir le rappel appelé de manière synchrone.

C'est une exagération... Dans cette ligne de code, vous ne supposez pas que la configuration est définie de manière asynchrone, n'est-ce pas ?
Les rappels ne sont que des rappels, en eux-mêmes ils n'ont rien à voir avec des trucs de synchronisation/async.

Ok, alors nous devons parler du terme callback : wink:.

Je sais, certains appellent des fonctions passées à forEach a callback (comme MDN ). Je ne l'appellerais pas ainsi, car pour moi, un rappel est quelque chose qui est appelé lorsqu'une tâche est terminée.

Et si le rappel suit la convention d'erreur du nœud avec le premier argument étant null ou une erreur, alors il y a de bonnes raisons de l'appeler _toujours_ de manière asynchrone.

Je sais, certains appellent des fonctions passées à forEach un rappel`

Quelqu'un utilise trop de node ;) Tout le monde appelle cette chose un "rappel". Donc, s'il s'agit d'une "fonction de rappel appelée lorsqu'une tâche est terminée", il s'agit ni plus ni moins de "rappel asynchrone".

Mais peu importe, désolé, je ne voulais pas passer pour un CO et lancer ce débat purement linguistique (je voulais juste m'assurer que nous parlons la même langue et que les documents mentionnent que less.render est synchrone).

PS Juste pour préciser :

@kwketh

Ce formulaire less.render était là depuis des années, vous ne pouvez pas simplement le prendre et le changer à partir de rien pour casser des millions d'extraits.

@sept-phases-max

Merci beaucoup pour vos réponses, elles sont toutes utiles. Je suis d'accord avec tous vos points concernant les rappels. J'ai regardé très brièvement le code .render et vous avez raison, la forme sous laquelle il est écrit, tout tourne autour des rappels et ne semble ni facile ni raisonnable d'avoir renderSync .

Mon problème est en quelque sorte différent mais lié (https://github.com/less/less.js/issues/2546). L'implémentation de la fonctionnalité renderSync résoudrait mon problème mais ce ne serait pas la solution ultime.

Cela vous dérange-t-il de jeter un coup d'œil? J'apprécierais vraiment.

Merci.

Quelqu'un utilise trop de nœud

Eh bien, c'est vrai :grin:

Mais la convention de rappel du nœud est bien établie. Je suppose que le rappel est toujours appelé de manière asynchrone dans ce cas.

De plus : Comment les erreurs sont-elles gérées lorsqu'il y a eu une erreur ? Est-il lancé (comme la plupart des API de synchronisation) ou passé en argument au rappel ?

C'est juste que l'API actuelle est ambiguë (du moins à mon humble avis)

Y a-t-il déjà un renderSync ? Sinon, existe-t-il une solution de contournement pour un render synchrone ?

Edit : Nvm. Pour toute personne future qui tombe dessus, voici ce que j'ai fait :

less.renderSync = function (input, options) {
    if (!options || typeof options != "object") options = {};
    options.sync = true;
    var css;
    this.render(input, options, function (err, result) {
        if (err) throw err;
        css = result.css;
    });
    return css;
};

Cette fonctionnalité est-elle réellement implémentée ? Existe-t-il des documents ? Je ne trouve que l'option async .

Idk si c'est réellement pris en charge, mais je sais que ce que j'ai fait fonctionne pour moi actuellement, alors... haussez les épaules

@Aarilight merci beaucoup, votre code

Ce comportement de rappel synchrone est vraiment contre-intuitif :confused:

@Aarilight ça ne marche pas pour moi=(
J'ai essayé

less.render(css, {sync : true}, (e, result) =>{
        if(e) {
         console.error(e)
    }

        output = result;
        return result
    });

et connecté https://github.com/less/less.js/blob/master/lib/less/render.js

            console.log('1')
            this.parse(input, options, function(err, root, imports, options) {
                console.log('2')
                if (err) { return callback(err); }

                var result;
                console.log('3')
                try {
                    console.log('4')
                    var parseTree = new ParseTree(root, imports);
                    console.log('5')
                    result = parseTree.toCSS(options);
                }
                catch (err) { 
                    console.log('6')
                    return callback(err); 
                }

                console.log('7')
                callback(null, result);
            });
            console.log('8')

Et je vois 1, 8 puis 2,3,4,5,6,7 pour certains fichiers

-1 pour diviser le rendu en render et renderSync . C'est une convention Node.js qui est maladroite. Et cela ne permet pas d'envoyer une option de synchronisation à grunt / gulp / accord ou à d'autres workflows intégrés à moins qui passent un objet JS à une fonction désignée. IMO, il est bon de transmettre un rappel facultatif lors de l'utilisation d'une option asynchrone.

Une autre option : ce que j'ai vu des bibliothèques commencer à faire est en fait de retourner une promesse dans les deux cas. Ensuite, tout ce qui change entre sync / async, c'est lorsque la promesse est remplie, mais le code gérant le résultat est exactement le même.

Et d'ailleurs :

{sync: true}

Il n'y a pas une telle option.

-1 pour diviser le rendu en rendu et renduSync. C'est une convention Node.js qui est maladroite.

N'est-ce pas un point de vue complètement subjectif ? IMHO combinant async et synchronisation dans une seule fonction est (à quelques exceptions près) un terrible anti-modèle. Il crée du code encombré d'instructions conditionnelles, est plus difficile à maintenir et est encore plus déroutant pour l'utilisateur qu'une fonction clairement définie et documentée qui fait bien une chose. juste mon 2c

N'est-ce pas un point de vue complètement subjectif ?

Oui.

Quoi qu'il en soit, mon autre point n'est pas subjectif. C'est-à-dire que Less est utilisé dans les processus de génération qui peuvent avoir besoin d'être mis à jour si une fonction est fractionnée. Par exemple : Accord (https://github.com/jenius/accord), que j'utilise actuellement pour un projet, extrait différents compilateurs dans une seule API et transmet généralement un objet à la fonction requise par ce moteur. Donc, ce n'est probablement pas une grosse affaire de changer la fonction utilisée en fonction des options Less spécifiées par un développeur, mais je ne sais pas combien de bibliothèques cela affecterait. C'est juste quelque chose dont il faut être conscient.

À partir de maintenant, l'ajout de syncImport: true à mes options a résolu ce problème pour moi.

(Ce n'est pas dans la documentation... j'ai juste eu la chance de tomber dessus dans le code source)

Ce problème a été automatiquement marqué comme obsolète car il n'a pas eu d'activité récente. Il sera fermé si aucune autre activité ne se produit. Merci pour vos contributions.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

joe223 picture joe223  ·  4Commentaires

awebdev picture awebdev  ·  4Commentaires

chricken picture chricken  ·  6Commentaires

bassjobsen picture bassjobsen  ·  6Commentaires

briandipalma picture briandipalma  ·  6Commentaires