isomorphic-loader icon indicating copy to clipboard operation
isomorphic-loader copied to clipboard

ECMAScript Module (ESM) support

Open robaca opened this issue 4 years ago • 0 comments

Hi,

please add support for isomorphic-loader for module type projects (and hybrid variants).

We are currently facing two issues here:

(1) extendRequire does not work for ES modules. I played around writing our own ESM loader (only works on Node >=16.12):

import fs from 'fs'
import path from 'path'
import assert from 'assert'

const isomorphicLoaderConfig = JSON.parse(await fs.promises.readFile(path.join(process.cwd(), '.isomorphic-loader-config.json'), 'utf-8'))
assert.ok(isomorphicLoaderConfig?.assetsFile, 'please run "yarn build:staticResources" before running "yarn build:staticPages"')
const isomorphicAssets = JSON.parse(await fs.promises.readFile(isomorphicLoaderConfig.assetsFile, 'utf-8'))

const EXTENSIONS = ['.svg', '.jpg', '.png']

export async function resolve(specifier, context, defaultResolve) {
    const { parentURL = null } = context
    if (EXTENSIONS.some((ext) => specifier.endsWith(ext))) {
        const url = parentURL ? new URL(specifier, parentURL).href : new URL(specifier).href
        return { url }
    }
    return defaultResolve(specifier, context)
}

export async function load(url, context, defaultLoad) {
    if (EXTENSIONS.some((ext) => url.endsWith(ext))) {
        const assetPath = Object.keys(isomorphicAssets.marked).find((asset) => url.endsWith(asset))
        if (assetPath) {
            return {
                format: 'json',
                source: `"/our-prefix/${isomorphicAssets.marked[assetPath]}"`,
            }
        }
        throw new Error(`Did not find asset ${url} in isomorphic-assets.json`)
    }
    return defaultLoad(url, context, defaultLoad)
}

A hybrid solution would mean to also support CJS dependencies which still use require.

(2) Maybe webpack 4 or TypeScript related, but the isomorphic-assets.json is missing the entries in marked that are direct dependencies of es module files. I checked the webpack-plugin.js and the top level modules list traversed by this snippet is not containing the relevant modules. Instead they can be found in nested modules:

      const marked = stats.modules.reduce((acc, m) => {
        sigIdx = m.identifier.indexOf(loaderSig);
        if (sigIdx >= 0 && m.assets && m.assets.length > 0) {
          const n = posixify(removeCwd(m.identifier.substr(sigIdx + loaderSig.length), true));
          acc[n] = m.assets[m.assets.length - 1];
        }

I do not know enough of the internals of webpack to propose a fix here - maybe it's already a bug in the ts-loader or file-loader...

robaca avatar Dec 22 '21 08:12 robaca