Load GLB model with Webpack - Three.js - javascript

I'm trying to use Webpack for the first time and I have trouble to add my glb model. My model is ok, used many times and I put in public folder. I dont' understand console error, any help will be appreciate, thanks.
I'm using three.js r116 and Firefox. Safari tell me same error, can't found the model.
Here a part of my JS code :
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
const loader = new GLTFLoader();
loader.load('/assets/models/street_car.glb', (gltf) => {
scene.add(gltf.scene);
});
My webpack.config :
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: './src/scripts/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'dist/main.js',
},
performance: {
hints: false
},
plugins: [
new CopyWebpackPlugin([{ from: '**/*', to: '' }], {
context: 'src',
writeToDisk: true,
}),
],
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
port: 9000,
historyApiFallback: true
}
};
And finally console error :

I just find the problem, add this lines to webpack.config
module:
{
rules:
[
{
test: /\.(glb|gltf)$/,
use:
[
{
loader: 'file-loader',
options:
{
outputPath: 'assets/models/'
}
}
]
},
]
}
And don't need to add assets in public folder, they are in my src folder with scripts.

For Webpack v5, the previous loaders are now obsolete (like file-loader, raw-loader, etc), and replaced by the use of Asset Modules
The correct asset module for 3d model formats like gltf, obj, fbx, stl etc. is asset/resource

I was looking for something like this but for a Symfony Webpack Encore application configuration. #MlleBz your answer actually helped me a lot, thanks.
So, with no further ado, if you're looking to implement a .glb or .gltf loader in a Symfony / React / ThreeJS application, add this to your webpack.config.js :
// add loader for .glb files (use this with three.js)
.addLoader({
test: /\.(glb|gltf)$/,
loader: 'file-loader'
})

Related

webpack v5 SourceMapDevToolPlugin "exclude" option not working

After upgarding to webpack 5, vendor.js file couldn't be excluded from being source-mapped via SourceMapDevToolPlugin.
// webpack.config.ts - removed other config for brevity
import { Configuration } from 'webpack-dev-server';
export default (env) => {
const config: Configuration = {};
config.mode = 'production';
config.entry = './entry.app.js';
config.output = {
path: path.join(__dirname, '/public'),
pathinfo: true,
filename: '[name].[fullhash].js',
chunkFilename: '[name].[fullhash].js',
};
config.devtool = 'source-map';
config.bail = true;
config.plugins = [
new webpack.SourceMapDevToolPlugin({
filename: '[file].map',
exclude: ['vendor.js'],
}),
];
config.optimization = {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: false,
sourceMap: false,
}),
new CssMinimizerPlugin(),
],
moduleIds: 'deterministic',
splitChunks: {
chunks: 'all',
maxInitialRequests: 100,
minSize: 0,
cacheGroups: {
vendor: {
name: 'vendor',
test: /([/\\]node_modules[/\\]|[/\\]dev[/\\]vendor[/\\])/,
chunks: 'all',
},
},
},
};
return config;
}
// entry.app.js - removed some lines for brevity
import './horrible-asset-loader';
import './setup-for-angular';
import { runApp } from './assets/js/app';
runApp();
// horrible-asset-loader.js
// contains a lot of require statements of npm packages saved into our repository under a vendor folder. crazy i know but I don't know why this was done.
require('ng-bs-daterangepicker/dist/ng-bs-daterangepicker.min.js'); // throwing an error when building because webpack is trying to create a source map for it
// Temporary solution to bundle multiple javascript files into one. This will be replaced by ES6 import.
SourceMapDevToolPlugin exclude config i've tried so far:
// from https://webpack.js.org/plugins/source-map-dev-tool-plugin/#exclude-vendor-maps
exclude: ['vendor.js']
//from https://github.com/webpack/webpack/issues/2431
exclude: /vendor.*.*/
exclude: 'vendor'
// just me desperately trying every possible config
exclude: ['vendor']
exclude: /vendor\.[0-9a-zA-Z]\.js/
exclude: 'vendor.js'
exclude: ['vendor.[chunkhash].js']
exclude: ['vendor.[fullhash].js']
The github issue link mentioned about an issue with UglifyJsPlugin but we aren't using that so I ruled it out.
Although if i set config.devtool to false, the SourceDevToolPlugin config works.
Is there something wrong with my config?
UPDATE: I think i got it now. Looks like i just really have to set devtool to false based on this example: https://webpack.js.org/plugins/source-map-dev-tool-plugin/#basic-use-case
I just thought devtool should only be set to false for development mode because of this note:
If you want to use a custom configuration for this plugin in development mode, make sure to disable the default one. I.e. set devtool: false.
Am I right?
UPDATE 1: Yup! looks like I'm right. I should've read the other comments on the github issue: https://github.com/webpack/webpack/issues/2431#issuecomment-245547872
Sorry for wasting anyone's time.
This was a really silly mistake. I misunderstood the docs for the plugin:
https://webpack.js.org/plugins/source-map-dev-tool-plugin/#basic-use-case
Setting devtool to false fixed the issue.

Webpack 5 - Uncaught ReferenceError: process is not defined

*** Edit - Ignore if you want answer only ***
Seeing as this question is still receiving views and upvotes I feel responsible to share some knowledge after going through the webpack rabbithole and coming out the other end.
If you:
are building a greenfield/early-stage modern javascript project
are considering migrating from create-react-app
don't have much experience with bundling
do not need advanced features like module federation or server side rendering (which doesn't need webpack anymore)
Consider using the next generaton bundlers such as vite/parcel (easy setup), esbuild/rollup (more setup required)
Webpack was/is a fantastic contribution to the frontend world and I'm glad I learned all its intricacies, however, the new bundlers are much faster during development and easier to mantain. It's great when it works but for those inexperienced with it; despite fantastic docs the learning curve can make it a horrible pain to debug.
To clarify, I'm not a maintainer on any of these projects - just a dev who enjoys good tooling. In today's landscape, webpack is comparable to using a sledgehammer to crack a nut.
*** End of Edit ***
Webpack newbie here, I was told by webpack cli that I needed to provide an alias for crypto as webpack no longer includes default node libraries. Now I'm getting this error, other answers haven't helped so much. crypto-browserify is trying to access process.browser. Can anyone shed more light? I was told by cli to install stream-browserify too so i did.
React v17, Babel 7.12.9, webpack 5.6.0
webpack.common.js
const paths = require('./paths');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const dotenv = require('dotenv-webpack');
module.exports = {
entry: [paths.src + '/index.js'],
output: {
path: paths.build,
filename: '[name].bundle.js',
publicPath: '/',
},
plugins: [
new dotenv(),
new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
{
from: paths.public,
to: 'assets',
globOptions: {
ignore: ['*.DS_Store'],
},
},
],
}),
new HtmlWebpackPlugin({
title: 'Webpack Boilerplate',
// favicon: paths.src + '/images/favicon.png',
template: paths.src + '/template.html',
filename: 'index.html',
}),
],
resolve: {
fallback: {
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify'),
},
},
module: {
rules: [
// javascript
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
// images
{
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
type: 'asset/resource',
},
// Fonts and SVGs
{
test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
type: 'asset/inline',
},
// CSS, PostCSS, and Sass
{
test: /\.(scss|css)$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
esModule: true,
sourceMap: true,
importLoaders: 1,
modules: {
auto: true,
namedExport: true,
},
},
},
{ loader: 'postcss-loader', options: { sourceMap: true } },
{ loader: 'sass-loader', options: { sourceMap: true } },
],
},
],
},
};
webpack.dev.js
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const common = require('./webpack.common');
module.exports = merge(common, {
mode: 'development',
// Control how source maps are generated
devtool: 'inline-source-map',
// Spin up a server for quick development
devServer: {
historyApiFallback: true,
contentBase: paths.build,
open: true,
compress: true,
hot: true,
port: 8080,
},
plugins: [
// Only update what has changed on hot reload
new webpack.HotModuleReplacementPlugin(),
],
});
In webpack 5 automatic node.js polyfills are removed. In the migration docs it is mention that
Try to use frontend-compatible modules whenever possible.
It's possible to manually add a polyfill for a node.js core module.
An error message will give a hint on how to achieve that.
Package authors: Use the browser field in package.json to make a
package frontend-compatible. Provide alternative
implementations/dependencies for the browser.
See this issue.
Now you can refer this PR and check the libs that were removed and install them.
Next add alias for the lib in your webpack config.
For ex.
resolve: {
alias: {
process: "process/browser"
}
}
Update:
This can also be done using ProvidePlugin
package.json
"devDependencies": {
...
"process": "0.11.10",
}
webpack.config.js
module.exports = {
...
plugins: [
new webpack.ProvidePlugin({
process: 'process/browser',
}),
],
}
npm i process was all I needed.
Hope the correction I proposed will be accepted and released soon
I have this problem for HtmlWebpackPlugin, I added 'templateParameters' parameter to HtmlWebpackPlugin and it was fixed for me:
new HtmlWebpackPlugin({
baseUrl: '/',
template: 'app/index.html',
templateParameters(compilation, assets, options) {
return {
compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options,
},
process,
}
},
chunksSortMode: 'auto',
minify: {
collapseWhitespace: false,
},
cache: true,
}),
1. npm i dotenv-webpack
2. //Define dotenv in your webpack config
const Dotenv = require('dotenv-webpack');
plugins: [
new Dotenv({
path: './.env', // Path to .env file (this is the default)
safe: true, // load .env.example (defaults to "false" which does not use dotenv-safe)
})
],

Images not displaying on production build, only in dev (webpack/sass-loader)

When running my app on webpack dev server, all my image files are working whether as img tags in my index.html or background-image: url()..
Running my project though in production build, I am getting file reference errors that they cannot be found.
GET file:///img/featured.png net::ERR_FILE_NOT_FOUND
GET file:///img/header-img1-1.jpg net::ERR_FILE_NOT_FOUND
I added the copy webpack plugin as I thought this would move all images from my src/img folder to my img folder inside dist.
Should I be using the contentBase option for webpack-dev-server? Or is the copy-webpack-plugin not getting the correct reference? Super confused
Project tree:
- webpack.config.js
- package.json
- .babelrc
- src
- js
- index.js
- ...
- img
- ALL IMAGES LOCATED HERE
- scss
- layout
- landing.scss
- brands.scss
- base
- index.html
inside landing.scss
i have used
background: url('~/img/img-title.png')
same in other files like brands.scss
background: url('~/img/img-title.png')
Which has all worked fine, and I think I've confused myself with how images are referenced with webpack/sass loader, and can't seem to work out how to get the image paths to work for both dev/production, i can only seem to get one working at a time.
production tree:
- dist
- css
- img
- js
- index.html
webpack.config.js:
const path = require('path');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractPlugin = new ExtractTextPlugin({
filename: 'css/main.css'
});
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ScriptExtPlugin = require('script-ext-html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = (env) => {
const isProduction = env.production === true
return {
entry: './src/js/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
use: 'babel-loader'
},
{
test: /\.css$|\.scss$/,
include: path.resolve(__dirname, 'src'),
use: extractPlugin.extract({
fallback: "style-loader",
use: [
{ loader: 'css-loader', options: { importLoaders: 2, sourceMap: true }},
{ loader: 'postcss-loader', options: { sourceMap: true, plugins: () => [autoprefixer] }},
{ loader: 'sass-loader', options: { sourceMap: true }},
],
})
},
{
test: /\.html$/,
use: ['html-loader']
},
{
test: /\.(jpe?g|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1000,
name: 'img/[name].[ext]',
}
}
]
}
]
},
plugins: [
extractPlugin,
new HtmlWebpackPlugin({
filename: 'index.html',
inject: true,
template: './src/index.html'
}),
new ScriptExtPlugin({
defaultAttribute: 'async'
}),
new CleanWebpackPlugin(['dist']),
new CopyWebpackPlugin([
{from:'src/img',to:'img'}
]),
]
}
}
I think you're using different folder structure on production than on local, i.e. on local, it's just http://localhost:PORT/app, but on prod, it must be similar to http://produrl/Some_Folder/app
Now coming to actual issue - It's your CSS loader.
By default css-loader, has url=true, causing all URLs to be mapped relative to root. Hence this works for you -
background: url('~/img/img-title.png')
but this doesn't
background: url('../../img/img-title.png')
Just set url=false, and you'll be able to provide relative URL and it'll load for all enviorments correctly.
While the accepted answer may works in your specific scenario, I think there is a better solution that do not involve disabling css-loader url() handling and will works better in most of situation.
Tilde ~ problem
When you use ~ to import something in css, css-loader will search for that file inside node_modules. Your images are inside src/img folder so you do not need tilde ~ to import your images.
url() problem
sass-loader doesn't not resolve url() correctly if they are not in the same directory of the entry-file.
In your specific example you import some urls inside src/scss/layout/landing.scss and src/scss/layout/brands.scss but I guess your main scss entry point is inside src/scss folder.
Note: for "main scss entry point" I mean the scss file that you import inside your javascript entry point src/js/index.js
So, in your example, every images imported within a scss file that is not inside src/scss folder will trow an error.
To solve this problem use resolve-url-loader which resolves relative paths in url() statements based on the original source file.
[
{ loader: 'css-loader'}, // set `importLoaders: 3` if needed but should works fine without it
{ loader: 'postcss-loader'},
{ loader: 'resolve-url-loader' }, // add this
{ loader: 'sass-loader',
// sourceMap is required for 'resolve-url-loader' to work
options: { sourceMap: true }
}
]
CopyWebpackPlugin is optional
Based on your configuration you do not need CopyWebpackPlugin because your images are already handle by url-loader.
Note: url-loader doesn't output your images but inline them, images are outputted by file-loader when the file is greater than the limit (in bytes).
file-loader will output your images in dist/img folder, because you set name: 'img/[name].[ext]', and you set output.path: path.resolve(__dirname, 'dist').
Hey I think your issue is just in how you're referencing the image in your scss.
Based on your folder structure it should be:
background: url('../../img/img-title.png')
You could modify the "publicPath" URL (which is relative to the server root) to match the file structure.
//webpack.config.js
...
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "assets/images/",
publicPath: "/other-dir/assets/images/"
}
}
]
}
]
}

Webpack with requirejs/AMD

I'm working on a new module for an existing project that still uses requireJS for module loading. I'm trying to use new technologies for my new module like webpack (which allows me to use es6 loaders using es6 imports). It seems like webpack can't reconcile with requireJS syntax. It will say things like: "Module not found: Error: Can't resolve in ".
Problem: Webpack won't bundle files with requireJS/AMD syntax in them.
Question: Is there any way to make webpack play nice with requireJS?
My final output must be in AMD format in order for the project to properly load it. Thanks.
I had the same question and I managed to achieve it. Below is the same webpack.config.js file.
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
let basePath = path.join(__dirname, '/');
let config = {
// Entry, file to be bundled
entry: {
'main': basePath + '/src/main.js',
},
devtool: 'source-map',
output: {
// Output directory
path: basePath + '/dist/',
library: '[name]',
// [hash:6] with add a SHA based on file changes if the env is build
filename: env === EnvEnum.BUILD ? '[name]-[hash:6].min.js' : '[name].min.js',
libraryTarget: 'amd',
umdNamedDefine: true
},
module: {
rules: [{
test: /(\.js)$/,
exclude: /(node_modules|bower_components)/,
use: {
// babel-loader to convert ES6 code to ES5 + amdCleaning requirejs code into simple JS code, taking care of modules to load as desired
loader: 'babel-loader',
options: {
presets: ['es2015'],
plugins: []
}
}
}, { test: /jQuery/, loader: 'expose-loader?$' },
{ test: /application/, loader: 'expose-loader?application' },
{ test: /base64/, loader: 'exports-loader?Base64' }
]
},
resolve: {
alias: {
'jQuery': 'bower_components/jquery/dist/jquery.min',
'application': 'main',
'base64': 'vendor/base64'
},
modules: [
// Files path which will be referenced while bundling
'src/**/*.js',
'src/bower_components',
path.resolve('./src')
],
extensions: ['.js'] // File types
},
plugins: [
]
};
module.exports = config;

Optimal webpack.config with webpack 2 for AngularJS 1.x app?

I want to set up an Angular 1.x app from scratch using webpack 2.
I am having trouble finding the best configuration for webpack.config, with optimal entry and output for production (meaning, all code, style and templating minified and gziped with no code repetition).
My main problem is how to set up webpack.config so that it recognizes all partials within the folder structure of my project, like these:
My current config file, for reference (which can't see subfolders):
var HtmlWebpackPlugin = require( 'html-webpack-plugin' );
var ExtractTextPlugin = require( 'extract-text-webpack-plugin' );
var path = require( 'path' );
module.exports = {
devServer: {
compress: true,
contentBase: path.join( __dirname, '/dist' ),
open: true,
port: 9000,
stats: 'errors-only'
},
entry: './src/app.js',
output: {
path: path.join( __dirname, '/dist' ),
filename: 'app.bundle.js'
},
module: {
rules: [ {
test: /\.scss$/,
use: ExtractTextPlugin.extract( {
fallback: 'style-loader',
use: [
'css-loader',
'sass-loader'
],
publicPath: '/dist'
} )
} ]
},
plugins: [
new HtmlWebpackPlugin( {
hash: true,
minify: { collapseWhitespace: true },
template: './src/index.html',
title: 'Prov'
} ),
new ExtractTextPlugin( {
filename: 'main.css',
allChunks: true
} )
]
};
Note that this isn't an exhaustive solution, as there are many optimizations one can make in the frontend, and I've kept the code snippets fairly short.
With webpack, there are a few routes that you can take to include partials into your app.js.
Solution 1
You can import/require your partials within app.js as such:
app.js
var angular = require('angular');
var proverbList = require('./proverb/list/proverb.list');
// require other components
// set up your app as normal
This allows the app.bundle.js to include your component js files in the main bundle. You can also use html-loader to include templates in the final bundle.
This isn't ideal, as all it does is create a large bundle.js (which doesn't leverage multiple downloads with http2 nor does it allow loading of components/files when the user explicitly requires it).
Solution 2
Importing partials as separate entry files into your webpack bundle:
webpack.config.js
const globby = require('globby');
const sourceDir = 'src';
var webpackentry = {
app: `${__dirname}/src/app.js`
};
const glob = globby.sync(`${__dirname}/${sourceDir}/**/*.js`)
.map((file)=>{
let name = file.split('/').pop().replace('.js', '');
webpackentry[name] = file;
});
const config = {
entry: webpackentry,
...
}
The second solution is unorthodox but it can be useful if you wanted to split all your partials as <script> tags in your html (for example if your company/team uses that as a means to include your directive/components/controllers), or if you have an app-2.bundle.js.
Solution 3
Use CommonsChunkPlugin:
webpack.config.js
let webpackentry = {
vendor: [
'module1',
'module2',
'module3',
]
}
...
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor'] //... add other modules
})
]
CommonsChunkPlugin allows webpack to scrawl through your entry files and discern common modules that are shared among them. This means that even if you are importing module1 in different files, they will be compiled only once in your final bundle.

Categories

Resources