马宇豪
2024-07-16 f591c27b57e2418c9495bc02ae8cfff84d35bc18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
    MIT License http://www.opensource.org/licenses/mit-license.php
    Author Tobias Koppers @sokra
*/
 
"use strict";
 
const formatLocation = require("../formatLocation");
const UnsupportedWebAssemblyFeatureError = require("./UnsupportedWebAssemblyFeatureError");
 
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../Module")} Module */
 
class WasmFinalizeExportsPlugin {
    /**
     * Apply the plugin
     * @param {Compiler} compiler the compiler instance
     * @returns {void}
     */
    apply(compiler) {
        compiler.hooks.compilation.tap("WasmFinalizeExportsPlugin", compilation => {
            compilation.hooks.finishModules.tap(
                "WasmFinalizeExportsPlugin",
                modules => {
                    for (const module of modules) {
                        // 1. if a WebAssembly module
                        if (module.type.startsWith("webassembly") === true) {
                            const jsIncompatibleExports =
                                module.buildMeta.jsIncompatibleExports;
 
                            if (jsIncompatibleExports === undefined) {
                                continue;
                            }
 
                            for (const connection of compilation.moduleGraph.getIncomingConnections(
                                module
                            )) {
                                // 2. is active and referenced by a non-WebAssembly module
                                if (
                                    connection.isTargetActive(undefined) &&
                                    /** @type {Module} */
                                    (connection.originModule).type.startsWith("webassembly") ===
                                        false
                                ) {
                                    const referencedExports =
                                        compilation.getDependencyReferencedExports(
                                            /** @type {Dependency} */ (connection.dependency),
                                            undefined
                                        );
 
                                    for (const info of referencedExports) {
                                        const names = Array.isArray(info) ? info : info.name;
                                        if (names.length === 0) continue;
                                        const name = names[0];
                                        if (typeof name === "object") continue;
                                        // 3. and uses a func with an incompatible JS signature
                                        if (
                                            Object.prototype.hasOwnProperty.call(
                                                jsIncompatibleExports,
                                                name
                                            )
                                        ) {
                                            // 4. error
                                            const error = new UnsupportedWebAssemblyFeatureError(
                                                `Export "${name}" with ${jsIncompatibleExports[name]} can only be used for direct wasm to wasm dependencies\n` +
                                                    `It's used from ${
                                                        /** @type {Module} */
                                                        (connection.originModule).readableIdentifier(
                                                            compilation.requestShortener
                                                        )
                                                    } at ${formatLocation(
                                                        /** @type {Dependency} */ (connection.dependency)
                                                            .loc
                                                    )}.`
                                            );
                                            error.module = module;
                                            compilation.errors.push(error);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            );
        });
    }
}
 
module.exports = WasmFinalizeExportsPlugin;