使用 Rollup 解析从 URL 导入的 ES6 模块

Resolving an ES6 module imported from a URL with Rollup

从 ES6 模块中的 URL 导入是完全有效的,因此我一直在使用这种技术在位于不同 hosts/ports:[=13 的微服务之间重用模块=]

import { authInstance } from "http://auth-microservice/js/authInstance.js"

我即将发布一个发布周期,并开始使用 rollup 进行捆绑到 IIFE 的惯常路径。 Rollup 似乎不支持从 URLs 导入 es6 模块,我认为应该支持,因为这在规范中是允许的:(

module-name The module to import from. This is often a relative or absolute path name to the .js file containing the module. Certain bundlers may permit or require the use of the extension; check your environment. Only single quotes and double quotes Strings are allowed. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)

我已经在互联网上搜索了一个小时,但一无所获。有人见过类似于 rollup-plugin-node-resolve 的解析器来解析 URLs 中的模块吗?

我不得不从这里开始,所以最后只写了一个汇总插件的框架。我还是觉得解析绝对路径应该是rollup的一个核心特性。

已更新代码段

在相当长的一段时间里,我们一直在使用它来为我们的几个应用程序转换生产代码。

const fs = require('fs'),
    path = require('path'),
    axios = require("axios")

const createDir = path => !fs.existsSync(path) && fs.mkdirSync(path)
const mirrorDirectoryPaths = async ({ cacheLocation, url }) => {
    createDir(cacheLocation)
    const dirs = [], scriptPath = url.replace(/:\/\/|:/g, "-")

    let currentDir = path.dirname(scriptPath)
    while (currentDir !== '.') {
        dirs.unshift(currentDir)
        currentDir = path.dirname(currentDir)
    }
    dirs.forEach(d => createDir(`${cacheLocation}${d}`))
    return `${cacheLocation}${scriptPath}`
}

const cacheIndex = {}
const writeToDiskCache = async ({ cacheLocation, url }) => {
    //Write a file to the local disk cache for rollup to pick up.
    //If the file is already existing use it instead of writing a new one.
    const cached = cacheIndex[url]
    if (cached) return cached

    const cacheFile = await mirrorDirectoryPaths({ cacheLocation, url }),
        data = (await axiosInstance.get(url).catch((e) => { console.log(url, e) })).data
    fs.writeFileSync(cacheFile, data)
    cacheIndex[url] = cacheFile

    return cacheFile
}

const urlPlugin = (options = { cacheLocation }) => {
    return {
        async resolveId(importee, importer) {
            //We importing from a URL
            if (/^https?:\/\//.test(importee)) {
                return await writeToDiskCache({ cacheLocation: options.cacheLocation, url: importee })
            }
            //We are importing from a file within the cacheLocation (originally from a URL) and need to continue the cache import chain.
            if (importer && importer.startsWith(options.cacheLocation) && /^..?\//.test(importee)) {
                const importerUrl = Object.keys(cacheIndex).find(key => cacheIndex[key] === importer),
                    importerPath = path.dirname(importerUrl),
                    importeeUrl = path.normalize(`${importerPath}/${importee}`).replace(":\", "://").replace(/\/g, "/")
                return await writeToDiskCache({ cacheLocation: options.cacheLocation, url: importeeUrl })
            }
        }
    }
}

此插件与以下配置一起适用于我: https://github.com/mjackson/rollup-plugin-url-resolve

import typescript from "@rollup/plugin-typescript";
import urlResolve from "rollup-plugin-url-resolve";

export default {
  output: {
    format: "esm",
  },
  plugins: [
    typescript({ lib: ["es5", "es6", "dom"], target: "es5" }),
    urlResolve(),
  ],
};

显然你可以删除 TypeScript 插件。