Fix Webpack Module Parse Failed Image Import Error
Resolve Webpack 'Module parse failed: import/export only with sourceType module' error on image imports. Fix asset loader regex in webpack.config.js, handle dynamic DOM content display, and avoid loader pitfalls for smooth bundling.
Webpack: Content (image and text) not displaying in div after DOM manipulation in JavaScript; ‘Module parse failed: import and export may appear only with sourceType: module’ error on image import
I’m trying to dynamically append an h1, img, and p elements to a .content div using JavaScript in a Webpack project. The header buttons display correctly, but the appended content does not appear. There’s an uncaught runtime error:
Uncaught runtime errors:
×
ERROR
Module parse failed: 'import' and 'export' may appear only with 'sourceType: module' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> import image from "./image.jpg";
| const div = document.querySelector('.content');
| const h1 = document.createElement('h1');
The code worked when content was static in HTML, but fails after moving to JS. Here’s the setup:
index.js
import image from "./image.jpg";
const div = document.querySelector('.content');
const h1 = document.createElement('h1');
h1.innerText = 'Restaurant Page';
div.appendChild(h1);
const img = document.createElement('img');
img.src = image;
div.appendChild(img);
const p = document.createElement('p');
p.innerText = 'Welcome to my restaurant.';
div.appendChild(p);
template.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<header>
<nav>
<button>Home</button>
<button>Menu</button>
<button>About</button>
</nav>
</header>
<div class="content">
</div>
</body>
</html>
webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
clean: true,
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/template.html",
})
],
module: {
rules: [
{
test: /.html$/i,
loader: "html-loader",
},
{
test: /.(png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource",
}
]
}
};
package.json (devDependencies)
{
"devDependencies": {
"css-loader": "^7.1.2",
"html-loader": "^5.1.0",
"html-webpack-plugin": "^5.6.5",
"style-loader": "^4.0.0",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.2"
}
}
How do I fix the image import error and make the content display correctly in Webpack?
The “module parse failed” webpack error blocks your JavaScript from running entirely, so no dynamic content—like that h1, img, or p—shows up in the .content div despite buttons working fine. It’s triggered because your asset loader regex misses a crucial backslash (/.(png|svg|jpg|jpeg|gif)$/i), leaving webpack to mishandle the image import as raw JS instead of emitting a URL. Fix the config, restart webpack-dev-server, and your img.src = image will grab the proper public path to display everything.
Contents
- Understanding the Webpack Module Parse Failed Error
- Fixing the Asset Loader Regex in Webpack Config
- How Webpack Asset/Resource Handles Image Imports
- Complete Updated webpack.config.js
- Handling Babel-loader SourceType Conflicts
- Testing Dynamic DOM Content Display
- Common Webpack Loader Pitfalls and Best Practices
- Sources
- Conclusion
Understanding the Webpack Module Parse Failed Error
Ever hit a wall where your code looks perfect but nothing renders? That’s this webpack error in action. The full message—“Module parse failed: ‘import’ and ‘export’ may appear only with ‘sourceType: module’”—pops up right at your import image from "./image.jpg"; line. Why? Webpack’s parser chokes because it expects ES module syntax (like import/export) only in module mode, but something’s forcing script mode.
Here’s the kicker: your JS never executes. Header buttons show because they’re static HTML. Dynamic appends? Dead on arrival. Runtime errors halt the script before div.appendChild fires. And no wonder static HTML worked—it bypassed bundling headaches.
This ties straight to loaders. Without proper handling for ./image.jpg, webpack treats it like JS code. Binary image data doesn’t parse as modules, cue the crash. Check the stack trace: position (1:0) flags the import as the villain.
Fixing the Asset Loader Regex in Webpack Config
Spot the bug yet? Your webpack.config.js rule:
{
test: /.(png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource",
}
That lone dot after /? It’s literal “any character” in regex, not “dot for extension.” So it matches junk like x.png but skips image.jpg (too many chars before .jpg). Webpack ignores the rule, falls back to default JS parsing. Boom—error.
Quick fix: Escape it.
{
test: /.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
}
Save, npm run dev (or whatever starts webpack-dev-server), refresh. Image imports now emit to /dist/image.[hash].jpg with a URL string returned. Your img.src = image sets it perfectly.
Pro tip: Test regexes at regex101.com. Paste image.jpg, toggle case-insensitive—green means match.
How Webpack Asset/Resource Handles Image Imports
Webpack 5’s type: 'asset/resource' replaces old file-loader/url-loader combos—no extra packages needed. Import an image:
import restaurantImg from './image.jpg'; // Returns '/images/image.abc123.jpg'
Behind the scenes: copies file to output, injects [contenthash] for caching, serves via dev server. In prod, same—CDN-ready paths.
For your DOM code? Spot on. const img = document.createElement('img'); img.src = restaurantImg; works because it’s a string URL, not a blob or module object. Browsers fetch it seamlessly.
But what if paths break? Webpack-dev-server proxies /dist/ virtually. Static HTML sidestepped this; JS needs the bundle.
From the official webpack docs on asset management, this setup handles dev/prod uniformly: “Import returns URL string… emits separate file.”
Complete Updated webpack.config.js
Don’t stop at regex. Here’s your full config, polished:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
devServer: {
static: './dist',
port: 3000, // Optional, tweak as needed
},
plugins: [
new HtmlWebpackPlugin({
template: './src/template.html',
}),
],
module: {
rules: [
{
test: /.html$/i,
loader: 'html-loader',
},
{
test: /.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
// Add CSS if needed
{
test: /.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
Added devServer for reliability. Install webpack-dev-server if missing (npm i -D webpack-dev-server). Run npx webpack serve.
Your package.json scripts? Add:
"scripts": {
"dev": "webpack serve",
"build": "webpack"
}
Now npm run dev—content appears.
Handling Babel-loader SourceType Conflicts
Some setups sneak in babel-loader (maybe a hidden dep or prior config). It defaults to sourceType: 'script', nuking imports.
Error snippet: “File was processed with these loaders: ./node_modules/babel-loader/lib/index.js”? That’s the clue.
Fix: Install if absent (npm i -D babel-loader @babel/core), then add rule:
{
test: /.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
sourceType: 'unambiguous', // Auto-detects modules
},
},
}
As noted in this Stack Overflow thread, 'unambiguous' sniffs imports and flips to module mode. No Babel preset needed for plain JS.
Skip if no Babel—modern webpack eats ES modules natively.
Testing Dynamic DOM Content Display
Fixed config? Verify step-by-step.
- Clear
dist/, restart server. - Console: No red errors? Good.
- Inspect
.content: h1 text? Check.<p>Welcome...? Yes.<img src="/image.abc123.jpg">? Loaded? - Network tab: Image 200 OK? Perfect.
Stuck? console.log(image)—expect URL string like /images/image.hash.jpg. console.log(div.children) post-append.
Edge case: Relative paths. ./image.jpg resolves from src/index.js. Move image? Update import.
Prod build: npm run build, serve dist/index.html statically. Mirrors dev.
Another Stack Overflow case nails it: “JS never executed… image assignment never happened.” Parse fix = display fix.
Common Webpack Loader Pitfalls and Best Practices
Webpack trips folks daily. Beyond regex:
- No clean output: Dupe assets pile up. Keep
clean: true. - Dev server woes: Forget
static: './dist'? Assets 404. - CSS missing: Your deps have loaders, but no rule? Blank styles.
- Hashing:
asset/resourceauto-hashes. Cache-bust win. - Multiple images: Loop
import img1 from '...'; imgs.push(img1);—fine.
Best practice? Webpack asset guide: Multi-stage for prod, but asset/resource rules most.
For complex apps, Module Federation or Vite beckon, but stick webpack for control.
Vary your imports: import('image.jpg').then(url => img.src = url) for dynamic loads.
Sources
- Asset Management | webpack
- Module parse failed: ‘import’ and ‘export’ may appear only with ‘sourceType: module’
- Content not displaying in div using webpack
- Getting the “Module parse failed: ‘import’ and ‘export’ may appear only with ‘sourceType: module’”
- Unable to build because of error with export from v. 5 beta 30 webpack
- Webpack can’t resolve asset/resource?
Conclusion
Nail the regex escape, tweak Babel if lurking, and your webpack setup pumps out dynamic content flawlessly—images loading, text appending, no more silent failures. Webpack shines for this once loaders align; expect buttery dev-to-prod flow. Run into variants? Console logs and regex testers are your friends. Build confidently.