I am trying to load a gltf file in a nextjs application using threejs.But its not working when i try to run it with nextjs application on react project.This is how i configured next.js with webpack:
const withCSS = require('#zeit/next-css');
const withImages = require('next-images');
const withPlugins = require('next-compose-plugins');
module.exports = withPlugins([
[withCSS, { cssModules: true }],
[withImages],
], {
serverRuntimeConfig: { serverRuntimeConfigValue: 'test server' },
publicRuntimeConfig: { publicRuntimeConfigValue: {apiUrl:process.env.apiUrl.trim()} },
webpack: (config, options) => {
config.module.rules.push({
test: /\.(glb|gltf)$/,
use: {
loader: 'file-loader',
}
})
return config; },exportTrailingSlash: true
});
I am importing the file like this:
import React from 'react';
import * as THREE from 'three';
import GLTFLoader from 'three-gltf-loader';
import TransformControls from './TransformControls.js'
import test2 from "../../../static/images/villa.gltf";
I wrote this function in componentDidmount to load gltf:
this.loader.load(test2, gltf => {
this.gltf = gltf.scene
// ADD MODEL TO THE SCENE
this.scene.add(gltf.scene);
});
This is Network tab when rendering the gltf file
In order to serve assets correctly with file-loader, you have to configure with correct location of _next static dir as following:
{
loader: 'file-loader',
options: {
publicPath: "/_next/static/images", // the path access the assets via url
outputPath: "static/images/", // where to store on disk
}
}
But looks like you might need to set up to load .bin file as well and keep the original name since it will be loaded as the .load function is called:
webpack: (config) => {
config.module.rules.push({
test: /\.(glb|gltf)$/,
use: {
loader: 'file-loader',
options: {
publicPath: "/_next/static/images",
outputPath: "static/images/",
}
},
});
// For bin file
config.module.rules.push({
test: /\.(bin)$/,
use: {
loader: 'file-loader',
options: {
publicPath: "/_next/static/images",
outputPath: "static/images/",
name: '[name].[ext]' // keep the original name
}
},
});
}
And also import the bin file in your component too:
import "../../../static/images/villa.bin";
Related
My extension does not contain any css files when I build it and I don't know what makes it do that. I did not change the Common.tsx that was scaffolded. Neither my own styles or the Azure DevOps UI styling gets packaged or used by components.
Azure DevOps UI documentation says to do this:
https://developer.microsoft.com/en-us/azure-devops/develop/extensions
When consuming the 2.164.0 version or later of the azure-devops-ui package, extensions should import the Azure DevOps global styles in order to get the same look and feel (font family, font sizes, hyperlink treatment, etc.) of Azure DevOps pages. This can be done with the following import:
import "azure-devops-ui/Core/override.css";
This is already done in the Common.tsx by default however.
directory structure
src
│ Common.scss
│ Common.tsx
│
└───Components
└───RESTRequestButton
RESTRequestButton.html
RESTRequestButton.json
RESTRequestButton.scss
RESTRequestButton.tsx
webpack.config.js
const path = require("path");
const fs = require("fs");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const entries = {};
const ComponentsDir = path.join(__dirname, "src/Components");
fs.readdirSync(ComponentsDir).filter(dir => {
if (fs.statSync(path.join(ComponentsDir, dir)).isDirectory()) {
entries[dir] = "./" + path.relative(process.cwd(), path.join(ComponentsDir, dir, dir));
}
});
module.exports = {
entry: entries,
output: {
filename: "[name]/[name].js"
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
alias: {
"azure-devops-extension-sdk": path.resolve("node_modules/azure-devops-extension-sdk")
},
},
stats: {
warnings: false
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader"
},
{
test: /\.s[ac]ss?$/,
use: ["style-loader", "css-loader", "azure-devops-ui/buildScripts/css-variables-loader", "sass-loader"]
},
{
test: /\.css?$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.woff?$/,
use: [{
loader: 'base64-inline-loader'
}]
},
{
test: /\.html?$/,
loader: "file-loader"
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: "**/*.html", context: "src/Components" }
]
})
]
};
Common.tsx
import "azure-devops-ui/Core/override.css";
import "es6-promise/auto";
import * as React from "react";
import * as ReactDOM from "react-dom";
import "./Common.scss";
export function showRootComponent(component: React.ReactElement<any>) {
ReactDOM.render(component, document.getElementById("root"));
}
RESTRequestButton.scss
#import "node_modules/azure-devops-ui/Core/_platformCommon.scss";
RESTRequestButton.tsx (only how I import the styling and how I reference Common.tsx)
import "./RestRequestButton.scss";
import { showRootComponent } from "../../Common";
class RESTRequestButton extends React.Component<{}, {}> {
//a lot of code goes here
}
export default RESTRequestButton;
showRootComponent(<RESTRequestButton />);
The solution was to bump package versions. I set package style-loader to "^3.3.1" and it was fixed.
I tried to use the images in the storybook. that image also inside the storybook project only.
Here is my storybook webpack.config.js file.
const path = require('path');
module.exports = async ({ config }) => {
config.module.rules.push({
test: /\.(sass|scss)$/,
use: ['resolve-url-loader'],
include: path.resolve(__dirname, '../')
});
config.module.rules.push({
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
use: [
{
loader: 'file-loader',
query: {
name: '[name].[ext]'
}
}
],
include: path.resolve(__dirname, '../')
});
return config;
};
this is how I import the images
import arrow from '../../static/arrow.png';
I got the image source like
<img src="data:image/png;base64,ZXhwb3J0IGRlZmF1bHQgX193ZWJwYWNrX3B1YmxpY19wYXRoX18gKyAiQmFubmVyV2Vla2VuZDIucG5nIjs=" alt="test">
I installed file-loader in my next.js project and configured my next.config.js to be like this:
module.exports = {
entry: './src/index.js',
webpack: config => {
const env = Object.keys(process.env).reduce((acc, curr) => {
acc[`process.env.${curr}`] = JSON.stringify(process.env[curr]);
return acc;
}, {});
config.plugins.push(new webpack.DefinePlugin(env));
config.module.rules.push({
test: /\.(png|jp(e*)g|svg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'images/[hash]-[name].[ext]',
},
},
],
});
return config;
}
};
I then have an image in /public/images/book-reading.svg
So I tried to import the image like this in a component I have within /src/components:
import BookReading from '../../public/images/book-reading.svg';
And using it like this:
<img src={BookReading} />
However the image does not show and I get this warning:
Warning: Prop src did not match. Server:
"images/364068d183bb962a8423031f65bab6ad-book-reading.svg" Client:
"/_next/images/364068d183bb962a8423031f65bab6ad-book-reading.svg"
Any ideas?
You need to add the publicPath and the outputPath to file-loader's options.
module.exports = {
webpack: config => {
config.module.rules.push({
test: /\.(png|jp(e*)g|svg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'images/[hash]-[name].[ext]',
publicPath: `/_next/static/images/`,
outputPath: 'static/images',
},
},
],
});
return config;
}
};
This is not your case but for the sake of completeness: if you had used a different basePath, you'd have needed to add it at the beginning of your publicPath.
Source
I am importing the react-slick css files. When i remove cssModules:true from next.config.js file, everything works fine. Any idea why adding cssModules:true creates the problem?
const withCSS = require("#zeit/next-css");
module.exports = withCSS({
cssModules: true,
webpack: config => {
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 100000,
name: "[name].[ext]"
}
}
});
return config;
}
});
I am build an isomorphic app using react, react-router, express and webpack. Now I want to use css modules to import css.
I use import './index.css' in index.jsx, it works fine on client, but doesn't work on server rendering. The error is Error: Cannot find module './index.css'.
components/index.jsx
import React, {Component, PropTypes} from 'react';
import style from './index.css';
class App extends Component {
constructor(props, context) {
super(props, context);
}
render() {
return (
<div id="login">
// ...
</div>
);
}
};
export default App;
server/router/index.js
import url from 'url';
import express from 'express';
import swig from 'swig';
import React from 'react';
import {renderToString} from 'react-dom/server';
import {match, RouterContext} from 'react-router';
import routes from '../../client/routes/routes';
import DataWrapper from '../../client/container/DataWrapper';
import data from '../module/data';
const router = express.Router();
router.get('*', async(req, res) => {
match({
routes,
location: req.url
}, async(error, redirectLocation, props) => {
if (error) {
res.status(500).send(error.message);
} else if (redirectLocation) {
res.status(302).redirect(redirectLocation.pathname + redirectLocation.search);
} else if (props) {
let content = renderToString(
<DataWrapper data={data}><RouterContext {...props}/></DataWrapper>
);
let html = swig.renderFile('views/index.html', {
content,
env: process.env.NODE_ENV
});
res.status(200).send(html);
} else {
res.status(404).send('Not found');
}
});
});
export default router;
webpack.config.dev.js(for webpack-dev-server)
var webpack = require('webpack');
var config = require('./config');
module.exports = {
devtool: 'inline-source-map',
entry: [
'webpack-dev-server/client?http://localhost:' + config.webpackPort,
'webpack/hot/only-dev-server',
'./src/client/entry',
],
output: {
path: __dirname + '/public/js',
filename: 'app.js',
publicPath: 'http://localhost:' + config.webpackPort + '/public/js',
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify('development')
}
})
],
resolve: {
extensions: ['', '.js', '.jsx', '.css']
},
module: {
loaders: [{
test: /\.jsx?$/,
loader: 'react-hot',
exclude: /node_modules/
}, {
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.css$/,
loader: 'style-loader!css-loader?modules',
exclude: /node_modules/
}, {
test: /\.(png|woff|woff2|svg|ttf|eot)$/,
loader: 'url-loader',
exclude: /node_modules/
}]
}
}
I'd recommend using webpack to compile UI code for both client and server side in that case. Just set target: "node" in webpack config to produce bundle which can executed in Node environment.
That article might help for compiling your server side code with Webpack: http://jlongster.com/Backend-Apps-with-Webpack--Part-I
Especially on how to exclude node_modules with the externals key.
A very bare config might look like:
'use strict';
const path = require('path');
const fs = require('fs');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const rootDir = path.resolve(__dirname, '..');
const distDir = path.join(rootDir, 'dist');
const srcDir = path.join(rootDir, 'src');
const localStyles = new ExtractTextPlugin('local.css', { allChunks: true });
const nodeModules = fs.readdirSync('node_modules')
.filter(dir => !dir.startsWith('.'))
.reduce((acc, prop) => {
acc[prop] = 'commonjs ' + prop;
return acc;
}, {});
const loaders = [
{
test: /\.(js|jsx)$/,
include: srcDir,
exclude: /node_modules/,
loader: 'babel',
query: {
cacheDirectory: true,
},
},
{
test: /\.css$/,
include: srcDir,
loader: localStyles.extract(
'style',
'css?modules&localIdentName=[name]-[local]_[hash:base64:5]'
),
},
{
test: /\.json$/,
loader: 'json',
},
];
module.exports = {
target: 'node',
entry: {
server: ['server/index'],
},
output: {
path: distDir,
filename: '[name].bundle.js',
},
externals: nodeModules,
module: {
loaders,
},
plugins: [
localStyles,
],
};
Another solution (Webpack free) could be to use babel-plugin-css-modules-transform
.