Search code examples
javascriptwordpresswebpackthree.jsbundle

Three.js cube is not rendering after bundling – Webpack, Wordpress


I’m trying to integrate three.js with wordpress via webpack. The problem is that, 3d cube is not appearing inside canvas.

<div class="div" id="canvas"></div>

is empty.

If I would put app.js code into <script>, inside page.php, using CDN src, it works. (the way without bundling)

But I thought it will be nice to bundle it just as other scripts.

Source:

app.js:

import "./example.js";

example.js:

import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
$("#canvas").append( renderer.domElement );

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 5;

function animate() {
requestAnimationFrame( animate );

cube.rotation.x += 0.01;
cube.rotation.y += 0.01;

renderer.render( scene, camera );


};

animate();

page.php:

<?php

get_header();
?>


<main id="home-primary" class="site-main">
<div class="div" id="canvas"></div>


</main><!-- #main -->

<?php
get_footer();

webpack.config.js:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
var path = require('path');

// change these variables to fit your project
const jsPath= './js';
const cssPath = './css';
const outputPath = 'dist';
const localDomain = 'http://localhost:8888/jakubtrz-portfolio';
const entryPoints = {
  // 'app' is the output name, people commonly use 'bundle'
  // you can have more than 1 entry point
  'app': jsPath + '/app.js',
  'style': cssPath + '/main.scss',

};

module.exports = {
  entry: entryPoints,
  output: {
    path: path.resolve(__dirname, outputPath),
    filename: '[name].js',
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),

    // Uncomment this if you want to use CSS Live reload
    
    new BrowserSyncPlugin({
      proxy: localDomain,
      //files: [ outputPath + '/*.css' ]
      files: ['style.css', 'js/**/*.js', '**/*.php'],
      injectCss: true,
    }, { reload: false, }),
    
  ],
  module: {
    rules: [
      {
        test: /\.s?[c]ss$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader'
        ]
      },
      {
        test: /\.sass$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'sass-loader',
            options: {
              sassOptions: { indentedSyntax: true }
            }
          }
        ]
      },
      {
        test: /\.(jpg|jpeg|png|gif|woff|woff2|eot|ttf|svg)$/i,
        use: 'url-loader?limit=1024'
      }
    ]
  },
};

package.json:

"devDependencies": {
    "@babel/cli": "^7.17.0",
    "@babel/core": "^7.17.0",
    "@babel/preset-env": "^7.16.11",
    "@wordpress/scripts": "^19.2.2",
    "autoprefixer": "^10.4.2",
    "babel-core": "^6.26.3",
    "browser-sync": "^2.27.7",
    "browser-sync-webpack-plugin": "^2.3.0",
    "css-loader": "^6.6.0",
    "dir-archiver": "^1.1.1",
    "file-loader": "^6.2.0",
    "mini-css-extract-plugin": "^2.5.3",
    "node-sass": "^7.0.1",
    "rtlcss": "^3.5.0",
    "sass-loader": "^12.4.0",
    "url-loader": "^4.1.1",
    "webpack": "^5.68.0",
    "webpack-cli": "^4.9.2"
  },


  "scripts": {
    "watch": "node-sass sass/ -o ./ --source-map true --output-style expanded --indent-type tab --indent-width 1 -w",
    "compile:css": "node-sass sass/ -o ./ && stylelint '*.css' --fix || true && stylelint '*.css' --fix",
    "compile:rtl": "rtlcss style.css style-rtl.css",
    "lint:scss": "wp-scripts lint-style 'sass/**/*.scss'",
    "lint:js": "wp-scripts lint-js 'js/*.js'",
    "bundle": "dir-archiver --src . --dest ../_s.zip --exclude .DS_Store .stylelintrc.json .eslintrc .git .gitattributes .github .gitignore README.md composer.json composer.lock node_modules vendor package-lock.json package.json .travis.yml phpcs.xml.dist sass style.css.map yarn.lock",
    "build": "webpack --mode production",
    "dev": "webpack --mode development --watch"
  },
  "babel": {
    "presets": [
      "@babel/preset-env"
    ]
  },
  "dependencies": {
    "three": "^0.137.5"
  }
}

No console errors.


Solution

  • According to your comment, you are including the script in the head tag, just move it to the end of the body (footer).

    You are not able to see anything because your script tries to get the canvas element, which does not yet exist at that time. By moving your script to the end, you are ensuring that your page has rendered before your script is ran.

    Using WordPress you can do:

    wp_enqueue_script( 'jakubtrz-portfolio-scripts', get_template_directory_uri() . '/dist/app.js', array(), false, true );
    

    The last argument is the one that indicate WordPress to add the script in the footer. By default, it is false hence, added in the head tag.