Existe-t-il un moyen de se connecter à l’AST de Webpack pour lui faire reconnaître un nouveau format de module?

Version courte:

Comment pouvons-nous manipuler l’AST pour le dernier paquet de sortie, ainsi que l’AST pour un fichier à l’intérieur d’un chargeur? Dans les deux cas, j’aimerais manipuler un AST existant plutôt que de le faire, c’est-à-dire parsingr les sources et créer un nouvel AST. Ce que je fais est lent, et je sais que Webpack doit déjà avoir fait une AST, je veux donc éviter les efforts en double.

Version longue:

Par exemple, supposons que j’ai un tas de fichiers écrits dans un format similaire aux modules AMD (mais pas tout à fait):

module({ Foo: '/path/to/Foo', Bar: '/path/to/Bar', Baz: '/path/to/Baz', }, function(imports) { console.log(imports) // {Foo:..., Bar:... Baz:...} }) 

La différence est qu’il s’appelle module au lieu de define , l’argument dependencies est une mappe de noms d’importation vers des chemins de modules au lieu d’un tableau de chemins de modules, et la fonction de corps de module reçoit un object import avec toutes les importations demandées au lieu d’un argument par importation demandée.

Ce qui précède est similaire au suivant au format AMD, avec le même résultat:

 define([ '/path/to/Foo', '/path/to/Bar', '/path/to/Baz', ], function(Foo, Bar, Baz) { console.log({Foo, Bar, Baz}) // {Foo:..., Bar:... Baz:...} }) 

Quel est le moyen recommandé de se connecter à Webpack pour que Webpack puisse comprendre les fichiers (savoir quelles sont les dépendances dont dispose le fichier) afin de créer finalement un ensemble de fichiers écrits dans ce format module() ?

J’ai déjà essayé une approche: j’ai créé un chargeur personnalisé qui reçoit le fichier source sous forme de chaîne, le parsing et le crée et l’AST, transforme l’AST, puis génère le code au format AMD define() , ce que Webpack comprend.

Cependant, j’ai l’impression que cela est lent, car s’il ya beaucoup de fichiers et s’ils sont volumineux, il est redondant d’parsingr et de créer un AST à partir de chaque fichier, car je parie que Webpack le fait déjà. Existe-t-il un moyen d’extraire l’AST de Webpack et de le transformer avant que Webpack ne souhaite parsingr ses dépendances, afin de pouvoir transformer l’AST en format AMD (ou tout autre format reconnu), afin que Webpack puisse enfin utiliser le fichier ? Y a-t-il une autre approche?

Je pense que vous constaterez que le chargeur est utilisé lors de l’parsing syntaxique des dépendances.

Fondamentalement, l’parsingur a besoin du code source pour pouvoir faire son travail. Par conséquent, toute instruction import / require (une dépendance) rencontrée au cours de la phase d’parsing en cours doit: a. être résolu et: b. être chargé avant de pouvoir être analysé. Si vous vous connectez à l ‘”étape de résolution” du paquet de résolution améliorée, vous pouvez console.log en dehors des transitions d’état par lesquelles le résolveur effectue la transition, aboutissant généralement au déclenchement des plugins “create-module”.

Accrocher à “résoudre-étape”:

 comstackr.plugin('after-resolvers', (comstackr) => { comstackr.resolvers.normal.plugin('resolve-step', function (type, request){ console.log("resolve-step type:["+type+"], path:["+request.path+"], request:["+request.request+"]"); }); }); 

Accrocher dans “create-module”:

 comstackr.plugin('compilation', (compilation, params) => { params.normalModuleFactory.plugin("create-module", (data) => { console.log('create-module: raw-request: '+data.rawRequest); } } 

J’espère que cela t’aides.

Je cherchais quelque chose comme ça, je voulais manipuler l’as, mais il n’y a pas d’exemple ni de documentation utile.

Googler pour cela m’a juste fait perdre 2 heures de mon temps, mais avec la documentation à moitié complète et incompréhensible, j’ai trouvé ceci (cela ne fonctionne pas):

 var acorn = require("acorn-dynamic-import").default; function MyPlugin(options) { // Configure your plugin with options... } MyPlugin.prototype.apply = function(comstackr) { comstackr.plugin("compilation", function(compilation, data) { data.normalModuleFactory.plugin( "parser" , function(parser, options) { parser.plugin( [ "statement if" ] ,(node)=> Object.assign( node ,{ test:{ type:"Literal", start: node.test.start, end: node.test.start+4, loc: { start: { line: 7, column: 3 }, end: { line: 7, column: node.test.loc.start.column+4 } }, range: [ node.test.range, node.test.range+4 ], value: true, raw: "true" } } ) ); }); }); }; module.exports = MyPlugin; 

Cela m’aurait donné le nœud d’une instruction if. Pour d’autres types de nœuds, vous pouvez consulter le fichier Parser.js .

J’essaie de renvoyer un autre nœud, mais créer un nœud demande beaucoup de travail et il ne semble pas qu’il soit facile de le faire.

Pourquoi se donner la peine d’essayer de faire cela dans le WebPack malgré tout? Les consortingbuteurs webpack ont ​​fait un bon produit, mais personne ne sait comment il fonctionne car il n’existe pas de documentation pour de nombreuses fonctionnalités.

Vous feriez probablement mieux de faire cela en tant que plugin babel, qui contient une documentation bien écrite et compréhensible.

Je travaille dans environ 20 minutes avec Babel:

 module.exports = function ({ types: t }) { return { visitor: { IfStatement(path, file) { path.node.test = { "type": "BooleanLiteral", "start": path.node.test.start, "end": path.node.test.start+4, "loc": { "start": { "line": 7, "column": path.node.test.loc.start.column }, "end": { "line": 7, "column": path.node.test.loc.start.column+4 } }, "value": true } // debugger; // path.unshiftContainer('body', t.expressionStatement(t.ssortingngLiteral('use helloworld'))); } } }; }; 

Dans webpack.config.js:

 const path = require("path"); const webpack = require("webpack"); module.exports = { entry: "./src", output: { path: path.resolve(__dirname, "dist"), filename: "[name].chunk.js" }, module:{ rules: [ { test: /\.html$/, use: [{ loader: './plugin/templateLoader' }] }, { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['env'], plugins: [require("./plugin/myBabelPlugin")] } }, } ] } }