How do you get webpack to *actually* ignore an external and rely on the browser to import?
Asked Answered
L

2

5

I'm trying to get webpack to ignore an import, so that its imported by the browser using a native ES6 import statement, not webpack. I'm trying to get ffmpeg.js to import directly as it crashes webpack when it tries to bundle it, as the files are too large.

Following the answer here (How to exclude a module from webpack, and instead import it using es6), I have my code in the local tree as /ffmpeg/ffmpeg-mpeg.js and verified my dev server can access as http://localhost:8080/ffmpeg/ffmpeg-webm.js

I then import via:

  import ffmpeg from '/ffmpeg/ffmpeg-webm.js';

And add that to the externals section of my webpack config:

  externals: {
    '/ffmpeg/ffmpeg-webm.js': 'ffmpeg',
  },

The result is an link that looks like this

webpack:///external "ffmpeg"

containing:

module.exports = ffmpeg;

Which then fails with "Uncaught Error: Cannot find module ?" (In fact that error is hardcoded in the generated file)

So that seems to assume there is a global ffmpeg option and then maps that module to that, but instead I want it leave the line completely untouched by webpack and leave it to the browser.

Whats the correct way to do that? The exclude rule thats downvoted on that page doesn't work either.

Ladonnalady answered 5/4, 2020 at 22:19 Comment(3)
if it's global, ie on the global or window object you should be able to access it directly without importing it. eg if (!window.ffmpeg) { /* do some fallback logic */ }Comanche
I think that's the issue, ffmpeg isn't a global, it doesn't exist until the module is loaded via the import statement. In fact if I'm reading the generated code right, it looks like it will ALWAYS get that error as it hasn't found the global module at build time.Ladonnalady
I forgot to ask the obvious.. Did you include the external script in your app's html? You need to. (Eg: <script src="/ffmpeg/ffmpeg-webm.js"></script>)Subsumption
S
3

Edit:

You can use this:

import(/* webpackIgnore: true */'/ffmpeg/ffmpeg-webm.js').then(({default: ffmpeg}) => {
  //Do what you want to do with ffmpeg
});

Which will prevent webpack from compiling the import (so it will be a regular ES6 import)


Original answer:

You forgot to include the external script in your page.

Also since you pointed out that your file is very big, I'd recommend to include it defered

So you need to add

<script src="/ffmpeg/ffmpeg-webm.js" defer></script>

To the head of your app and you would then import it slightly differently using the import function with a callback

import('/ffmpeg/ffmpeg-webm.js').then(ffmpeg => {
  //Do what you want to do with ffmpeg
});

Small note: the externals key does not need to be the path of your file, it's just the name you will use when importing, so rename it if you are getting confused with the path

module.export = {
  //...
  externals: {
    "ffmpeg-webm": "ffmpeg"
  }
}
//Then import
import('ffmpeg-webm').then(ffmpeg => {
  //Do what you want to do with ffmpeg
});

Alternatively for node js, instead of using externals you could use

const ffmpeg = __non_webpack_require__('/ffmpeg/ffmpeg-webm.js')

Just keep in mind that this will transform it as a normal require that only works with node js

Subsumption answered 8/4, 2020 at 15:44 Comment(6)
But if I wanted to import via script tag I wouldn't need the import statement, If remove webpack from the equation ES6 can import that module fine. I just need to tell webpack to ignore that import statement and pass it through unaltered to the generated code and everything will work fine (and without trying to bundle it)Ladonnalady
Yes but what you don't get is that excluding it from the bundle means you need to include it in your html page for webpack to load it as an external dependency and then be able to import it.. There is no way around that one.. Did you at least try?Subsumption
Its available at /ffmpeg/ffmpeg-webm.js. So without webpack code that import statement will work fine, without any additional script tags, the browser will find the import statement and load /ffmpeg/ffmpeg-webm.js (I've verified that in a small non-webpack example). If I wanted to add it as a script component, rather than a module, I wouldn't need the import statementLadonnalady
Yes you do... If you want to import it as an external webpack module that's the whole point, you're confusing webpack import with es6, from the moment you declare a script as external you have to include it in some way for webpack to use it in your webpack app, that way is to have it load on the page and webpack reference it as a module that it can import, you can't have both it excluded from a bundle and imoortedSubsumption
I was looking back at this and updated it with a real solution to your problem as __non_webpack_require__ is node js onlySubsumption
Note: If you have removeComments: true in your tsconfig.json, this will remove the webpackIgnore comment BEFORE Webpack sees it. This (now obvious) problem cost me a good 45 minutes of my life.Crosspollinate
C
1

The official way to do this is using a Magic Comment:

import(/* webpackIgnore: true */ 'ignored-module.js');

This tells webpack to copy the import() statement to the output bundle as-is.

There are more magic comments you can use, like enabling lazy loading (which may solve your problem and still allow you to use webpack's importing).

Note if you use TypeScript: Your tsconfig.json may inhibit webpackIgnore. Here are two cases to look out for:

//Needs to be false or the TS compiler will remove your comments BEFORE webpack sees them
"removeComments": false,

/*
Need to be ES2020 or later(ish).
The default is ES3, which is old enough that webpack takes things into its own hands
and overhauls imports() even if you tell it not to.
*/
"target": "ES2020",
"module": "ES2020",
Crosspollinate answered 7/12, 2023 at 15:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.