expo / expo-electron-adapter

This package wraps `electron-webpack` and adds support for Expo web and other universal React packages.
MIT License
28 stars 11 forks source link

[Electron] Requiring a file from assets folder doesn't work properly #5

Open FRizzonelli opened 4 years ago

FRizzonelli commented 4 years ago

Description

Hello there! I've found this issue while trying to implement a cross platform application with react-native-web used inside electron. I've followed all setup configuration and everything works smoothly except require of local asset. I'm using some audio and images in my project (with expo AV) and I've placed them inside assets folder and I'm using following code to import them:

await Audio.Sound.createAsync(require("../../../assets/audio/island_exercise_1_1.mp3"))

This works perfectly in react-native-web (running yarn web command), but when I use electron it fails because it seems that requiring an asset conflict with module resolution. On electron if I use

await Audio.Sound.createAsync(require("../../../assets/audio/island_exercise_1_1.mp3").default)

it works, but it's horrible because with RN I can't use dynamic require on mobile, so wrapping the logic in a utility method seems tricky.

I've same problem with source props for Image :(

Expected Behavior

Import with require of an asset works the same way as mobile and web

Environment

Expo CLI 3.24.0 environment info: System: OS: macOS 10.15.2 Shell: 3.2.57 - /bin/bash Binaries: Node: 14.8.0 - /var/folders/zd/nkvx5_tx0f976dl5h43x45jw0000gn/T/yarn--1599129033543-0.8979876647817548/node Yarn: 1.22.4 - /var/folders/zd/nkvx5_tx0f976dl5h43x45jw0000gn/T/yarn--1599129033543-0.8979876647817548/yarn npm: 4.2.0 - ~/.npm-packages/bin/npm Watchman: 4.7.0 - /usr/local/bin/watchman IDEs: Android Studio: 3.5 AI-191.8026.42.35.5791312 Xcode: 11.6/11E708 - /usr/bin/xcodebuild npmPackages: @expo/webpack-config: ^0.12.23 => 0.12.23 expo: ~38.0.8 => 38.0.9 react: ~16.11.0 => 16.11.0 react-dom: ~16.11.0 => 16.11.0 react-native: https://github.com/expo/react-native/archive/sdk-38.0.2.tar.gz => 0.62.2 react-native-web: ~0.11.7 => 0.11.7 npmGlobalPackages: expo-cli: 3.24.0

Electron versions

electron: ^6.0.12 @expo/electron-adapter: ^0.0.15

wrsulliv commented 3 years ago

@FRizzonelli I am having this problem as well. Thanks for the tip on using .default!

FRizzonelli commented 3 years ago

@wrsulliv You're welcome. Hope to find someone who can help us with a better solution tho :)

wrsulliv commented 3 years ago

@FRizzonelli Not sure if this helps, but I'm using this utility function:

unpackAsset.ts

export const unpackAsset = (asset: any) => {
  return asset;
}

unpackAsset.electron.ts

export const unpackAsset = (asset: any) => {
  return asset.default;
}

I invoke throughout the codebase as:

unpackAsset(require('./path/to/image.png'))

Tested this with iOS, Web, and Electron

FRizzonelli commented 3 years ago

@wrsulliv Doing the same, but I'd like to have a working require directly from the platform :)

FRizzonelli commented 3 years ago

Hi @EvanBacon, I saw that you moved the issue in the proper package. Do you have any insight to handle it better?

abnerluan7 commented 2 years ago

I have this simple solution

export const unpackAsset = (asset: any) => { if(typeof asset === 'object'){ return asset.default; } return asset; }

Simbaclaws commented 2 years ago

I'm trying to use a custom threejs loader called OBJLoader and MTLLoader from:

import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';

However, I'm getting this error as well, and I can't seem to load these files any way.

The message I'm getting is:

  ERROR in ./src/assets/models/portal.mtl 1:0
  Module parse failed: Unexpected character '#' (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
  > # Blender MTL File: 'None'
  | # Material Count: 6
  | 
   @ ./src/screens/HomeScreen.js 162:58-96
   @ ./App.js
   @ ./node_modules/expo/AppEntry.js
   @ multi css-hot-loader/hotModuleReplacement ./node_modules/expo/AppEntry.js

  ERROR in ./src/assets/models/portal.obj 1:0
  Module parse failed: Unexpected character '#' (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
  > # Blender v2.93.1 OBJ File: ''
  | # www.blender.org
  | mtllib logo.mtl
   @ ./src/screens/HomeScreen.js 157:58-96
   @ ./App.js
   @ ./node_modules/expo/AppEntry.js
   @ multi css-hot-loader/hotModuleReplacement ./node_modules/expo/AppEntry.js
  Child HtmlWebpackCompiler:
       1 asset
      Entrypoint HtmlWebpackPlugin_0 = __child-HtmlWebpackPlugin_0
      [./node_modules/html-loader/dist/cjs.js?minimize=false!./dist/.renderer-index-template.html] 3.58 KiB {HtmlWebpackPlugin_0} [built]

Is this an issue where webpack can not load these types of files and therefore fails compiling? (MTL and OBJ)? Or is it that the libraries I'm importing this from simply don't support expo electron?

If anyone could point me in the right direction that would be pretty nice.

I also haven't been able to get this to work on web yet... But it's a different issue there...

This is my homepage example:

import React from 'react';
import { View, StyleSheet } from 'react-native';
import ExpoTHREE, { THREE } from 'expo-three';
import { GraphicsView } from 'expo-graphics'
import { Asset } from 'expo-asset';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';

export default class HomeScreen extends React.Component {

  componentDidMount() {
    THREE.suppressExpoWarnings();
  }

  componentWillUnmount() {
    this.mounted = false;
  }

  onGLContextCreated = async({gl}) => {

    this.renderer = new ExpoTHREE.Renderer({gl});
    this.renderer.setSize(gl.drawingBufferWidth, gl.drawingBufferHeight);
    this.renderer.setClearColor(0xffffff);
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(75, gl.drawingBufferWidth / gl.drawingBufferHeight, 0.1, 1000);
    this.camera.position.z = 5;
    this.ambientLight = new THREE.AmbientLight(0xFFFFFF, 0.5);
    this.scene.add(this.ambientLight);
    this.spotlight = new THREE.SpotLight( 0xffffff );   
    this.spotlight.position.set( -60, 150, 100 );   
    this.spotlight.intensity = 6;   
    this.spotlight.distance = 1600;   
    this.spotlight.angle = 0.624;   
    this.spotlight.exponent = 19.3;   
    this.spotlight.decay = 7.7;   
    this.scene.add(this.spotlight);
    this.objFile = Asset.fromModule(require('../assets/models/portal.obj').default);
    await this.objFile.downloadAsync();
    this.mtlFile = Asset.fromModule(require('../assets/models/portal.mtl').default);
    await this.mtlFile.downloadAsync();
    this.mtlLoader = new MTLLoader();

    this.mtlLoader.load(this.mtlFile.localUri, (mtl) => {
      mtl.preload();
      this.portalLoader = new OBJLoader();
      this.portalLoader.setMaterials(mtl);
      this.portalLoader.load(this.objFile.localUri, (obj) => {
          this.portal = obj
          this.portal.rotation.x = 0.2;
          this.spotlight.target = this.portal;
          this.scene.add(this.portal);
          this.mounted = true;
        },
        (xhr) => {
          console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
        },
        (error) => {
          console.log(error);
        })
    },
    (xhr) => {
      console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
    },
    (error) => {
      console.log(error);
    });
  }

  onRender = delta => {
    if (this.mounted == true) {
      this.portal.rotation.y += 0.01;
      this.renderer.render(this.scene, this.camera);
    }
  }

  render() {
    return (
      <View style={{...styles.view}}>
        <GraphicsView style={{ ...styles.container }} onContextCreate={this.onGLContextCreated} onRender={this.onRender} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    alignItems: 'stretch', 
    flex:1
  },
  view: {
    backgroundColor: '#ffffff',
    flex: 1
  }
});

And it only seems to work for mobile so far...