2017-02-15 18 views
0

短版:有沒有辦法掛鉤到Webpack的AST,使其識別新的模塊格式?

我們如何從裝載機內部操作的文件最終輸出束的AST,還有AST?在這兩種情況下,我都想操縱現有的AST,而不是我正在做的解析源代碼並製作新的AST。我所做的很慢,我知道Webpack必須已經制作了一個AST,所以我想避免重複工作。

龍版本:

例如,假設我有一堆類似的格式寫入文件(但不完全)AMD模塊:

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

所不同的是,它是調用module而不是define,依賴性參數是一個導入名稱到模塊路徑而不是一個模塊路徑數組的映射圖,模塊主體函數接收到一個import對象,其中包含所有請求的導入,而不是每個請求的導入的一個參數RT。

以上是類似於AMD的格式如下,以相同的輸出:

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

什麼是掛接到的WebPack做出的WebPack能夠理解的文件(可以知道的推薦方法文件有什麼依賴關係),以便最終構建一個包含以這種module()格式編寫的文件的包?

我已經嘗試了一種方法:我製作了一個自定義加載程序,它接收文件的源代碼作爲字符串,解析它並創建和AST,轉換AST,然後輸出AMD define()格式的代碼,Webpack可以理解。

不過,我覺得這樣很慢,因爲如果有很多文件,並且它們很大,那麼從每個文件中解析和製作AST看起來都是多餘的,因爲我敢打賭,Webpack已經開始這樣做了。有什麼方法可以從Webpack獲取AST並在Webpack想要掃描它的依賴性之前將其轉換,以便我可以將AST轉換爲AMD格式(或任何可識別的格式),以便Webpack最終可以使用該文件?還有另一種方法嗎?

回答

0

我想你會發現在依賴分析過程中使用了加載器。

基本上解析器需要源代碼才能完成它的工作。因此,在當前分析階段遇到的任何import/require語句(依賴項)需要:a。解決並且:b。在它可以被解析之前被加載。如果掛鉤了增強解析包的「解決步驟」,則可以console.log out解析器轉換的狀態轉換,通常在觸發「create-module」插件時達到高潮。

勾成 「決心步」:

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

鉤到 「創建模塊」:

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

希望這有助於。

0

我正在尋找這樣的事情,想要操縱ast,但沒有示例或有用的文檔。

谷歌搜索只是浪費了2個小時我的時間,但與半完成的和難以理解的文件我也想出這個(沒有工作,雖然):

var acorn = require("acorn-dynamic-import").default; 

function MyPlugin(options) { 
    // Configure your plugin with options... 
} 

MyPlugin.prototype.apply = function(compiler) { 
    compiler.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; 

這將讓我的節點if語句,對於其他類型的節點,你可以看看在Parser.js

我嘗試返回另一個節點,但創建一個節點是很多工作,似乎並沒有一個簡單的方法來做到這一點。

何必試圖做這的WebPack呢?該的WebPack貢獻者都取得了不錯的產品,但沒有人知道它是如何工作的,因爲有許多的它的功能沒有文檔。

作爲一個babel插件,你可能會做得更好,這個插件寫得很好,可以理解documentation

我在大約20分鐘這正與巴貝爾:

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.stringLiteral('use helloworld'))); 
     } 
     } 
    }; 
}; 

在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")] 
      } 
     }, 
     } 
    ] 
    } 
} 
相關問題