reactjsnode.jselectroncraco

Open File Explorer On Button Click in React


I am trying to make it so that when clicking a button, the file explorer will open to a specific directory path. I have the project and files I want to access all in the same directory. Here's a link to my site: https://nfsdownload.teleporthq.app/

If I use:

require('child_process').exec('start "" "c:\\test"');

I get an error that webpack_require_ exec isn't a function.

If I use:

function openFile(path) {
    window.open(path, "_blank");
  }

<button type="button" className="nfs-slideshow-button BIG button">
                <span className="nfs-slideshow-text02 Button1" onclick={ openFile("C:\\NeedForSpeed\\nfsUnderground")}>
                  <span className="nfs-slideshow-text03">PLAY</span>
                  <br></br>

I get "not allowed to load local resource" and "server responded with a status of 404" due to browser security settings. Would this go away if I compiled my project into an exe somehow?

Using electron:

const {shell} = require('electron') // deconstructing assignment

shell.showItemInFolder('filepath') // Show the given file in a file manager. 
shell.openPath('folderpath') // Open the file in the default

<button type="button" className="nfs-slideshow-button BIG button">
                <span className="nfs-slideshow-text02 Button1" onClick={ shell.openPath('C:/NeedForSpeed/nfsUnderground')}>
                  <span className="nfs-slideshow-text03">PLAY</span>
                  <br></br>
                </span>

I get:

ERROR in ./node_modules/electron/index.js 1:11-24
Module not found: Error: Can't resolve 'fs' in 'C:\NeedForSpeed\ReactApp\node_modules\electron'
ERROR in ./node_modules/electron/index.js 2:13-28
Module not found: Error: Can't resolve 'path' in 'C:\NeedForSpeed\ReactApp\node_modules\electron'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
    - add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
    - install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
    resolve.fallback: { "path": false }

I am unsure of how to fix this due to the project being made with craco, so I don't have the typical webpack.config.js file. Here is my package.json:

{
  "name": "need-for-speed-download",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "@craco/craco": "^7.0.0-alpha.0",
    "electron": "^28.0.0",
    "prop-types": "15.7.2",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-helmet": "^6.1.0",
    "react-router-dom": "^5.2.0"
  },
  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test --env=jsdom",
    "eject": "craco eject"
  },
  "engines": {
    "node": "18.x"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "react-scripts": "^5.0.1"
  }
}

Here's my craco.config.js:

module.exports = {
  reactScriptsVersion: "react-scripts",
  style: {
    css: {
      loaderOptions: () => {
        return {
          url: false,
        };
      },
    },
  },
};

And here is the js file I am trying to add the file opener to:

import React from 'react'

import PropTypes from 'prop-types'

import './nfs-slideshow.css'

const NfsSlideshow = (props) => {
  const {shell} = require('electron')
  return (
    <div className="nfs-slideshow-container">
      <div
        data-thq="slider"
        data-navigation="true"
        data-pagination="true"
        className="nfs-slideshow-slider swiper"
      >
        <div data-thq="slider-wrapper" className="swiper-wrapper">
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs1994 swiper-slide"
          >
            <div className="nfs-slideshow-container01">
              <img
                alt="https://assets-prd.ignimgs.com/2022/08/31/needforspeed1-1661936473788.jpg?width=300&amp;crop=1%3A1%2Csmart&amp;auto=webp"
                src="https://hips.hearstapps.com/hmg-prod/images/roa110120fea-nfs-008-1604351948.jpg?resize=980:*"
                className="nfs-slideshow-image"
              />
              <h1 className="nfs-slideshow-text">{props.nfs1994_heading}</h1>
              <h1 className="nfs-slideshow-text01">{props.nfs1994_year}</h1>
              <button type="button" className="nfs-slideshow-button BIG button">
                <span className="nfs-slideshow-text02 Button1" onClick={ shell.openPath('C:/NeedForSpeed/nfsUnderground')}>
                  <span className="nfs-slideshow-text03">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-hot-pursuit3 swiper-slide"
          >
            <div className="nfs-slideshow-container02">
              <img
                alt="https://static.wikia.nocookie.net/nfs/images/2/28/NFSIIIHP_Boxart.jpg/revision/latest?cb=20191028081942&amp;path-prefix=en"
                src="https://assets-prd.ignimgs.com/2022/05/13/nfs3hp-1652477699912.jpg"
                className="nfs-slideshow-image01"
              />
              <h1 className="nfs-slideshow-text05">
                {props.nfs3HotPursuit_nfs}
              </h1>
              <h1 className="nfs-slideshow-text06">
                {props.nfs3HotPursuit_year}
              </h1>
              <h1 className="nfs-slideshow-text07">
                {props.nfs3HotPursuit_title}
              </h1>
              <button
                type="button"
                className="nfs-slideshow-button01 BIG button"
              >
                <span className="nfs-slideshow-text08 Button1">
                  <span className="nfs-slideshow-text09">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-high-stakes swiper-slide"
          >
            <div className="nfs-slideshow-container03">
              <img
                alt="https://static.wikia.nocookie.net/nfs/images/9/90/NFSHS_Boxart.jpg/revision/latest?cb=20191027140115&amp;path-prefix=en"
                src="https://upload.wikimedia.org/wikipedia/en/e/e2/NFS_High_Stakes_box.jpg"
                className="nfs-slideshow-image02"
              />
              <h1 className="nfs-slideshow-text11">
                {props.nfsHighStakes_nfs}
              </h1>
              <h1 className="nfs-slideshow-text12">
                {props.nfsHighStakes_year}
              </h1>
              <h1 className="nfs-slideshow-text13">
                {props.nfsHighStakes_title}
              </h1>
              <button
                type="button"
                className="nfs-slideshow-button02 BIG button"
              >
                <span className="nfs-slideshow-text14 Button1">
                  <span className="nfs-slideshow-text15">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-porche-unleashed swiper-slide"
          >
            <div className="nfs-slideshow-container04">
              <img
                alt="https://static.wikia.nocookie.net/nfs/images/d/d8/NFSPUBoxArt.png/revision/latest?cb=20220304213938&amp;path-prefix=en"
                src="https://assets-prd.ignimgs.com/2022/03/25/nfsporsche-1648251035942.jpg"
                className="nfs-slideshow-image03"
              />
              <h1 className="nfs-slideshow-text17">{props.nfsPorche_nfs}</h1>
              <h1 className="nfs-slideshow-text18">{props.nfsPorche_year}</h1>
              <h1 className="nfs-slideshow-text19">{props.nfsPorche_title}</h1>
              <button
                type="button"
                className="nfs-slideshow-button03 BIG button"
              >
                <span className="nfs-slideshow-text20 Button1">
                  <span className="nfs-slideshow-text21">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-hot-pursuit2 swiper-slide"
          >
            <div className="nfs-slideshow-container05">
              <img
                alt="https://assets-prd.ignimgs.com/2022/01/21/need-for-speed-hot-pursuit-2-ps2-button-1642795801243.jpg"
                src="https://upload.wikimedia.org/wikipedia/ru/9/99/%D0%9E%D0%B1%D0%BB%D0%BE%D0%B6%D0%BA%D0%B0_%D0%B8%D0%B3%D1%80%D1%8B_Need_for_Speed_Hot_Pursuit_2.jpg"
                className="nfs-slideshow-image04"
              />
              <h1 className="nfs-slideshow-text23">
                {props.nfsHotPursuit2_nfs}
              </h1>
              <h1 className="nfs-slideshow-text24">
                {props.nfsHotPursuit2_year}
              </h1>
              <h1 className="nfs-slideshow-text25">
                {props.nfsHotPursuit2_title}
              </h1>
              <button
                type="button"
                className="nfs-slideshow-button04 BIG button"
              >
                <span className="nfs-slideshow-text26 Button1">
                  <span className="nfs-slideshow-text27">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-underground swiper-slide"
          >
            <div className="nfs-slideshow-container06">
              <img
                alt="https://www.giantbomb.com/a/uploads/scale_medium/8/87790/1897548-box_nfsug.png"
                src="https://assets-prd.ignimgs.com/2022/03/25/nfsundergroundgba-1648241328415.jpg"
                className="nfs-slideshow-image05"
              />
              <h1 className="nfs-slideshow-text29">{props.nfsUng_nfs}</h1>
              <h1 className="nfs-slideshow-text30">{props.nfsUng_year}</h1>
              <h1 className="nfs-slideshow-text31">{props.nfsUng_title}</h1>
              <button
                type="button"
                className="nfs-slideshow-button05 BIG button"
              >
                <span className="nfs-slideshow-text32 Button1">
                  <span className="nfs-slideshow-text33">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-underground2 swiper-slide"
          >
            <div className="nfs-slideshow-container07">
              <img
                alt="https://m.media-amazon.com/images/M/MV5BNTZlZTZiZjktYWJlZi00NTU1LWJiMmQtOTEzNmFlZWE3NjNlXkEyXkFqcGdeQXVyNTgyNTA4MjM@._V1_FMjpg_UX1000_.jpg"
                src="https://assets-prd.ignimgs.com/2022/01/21/need-for-speed-underground-2-button-crop-1642797115202.jpg"
                className="nfs-slideshow-image06"
              />
              <h1 className="nfs-slideshow-text35">{props.nfsUng2_nfs}</h1>
              <h1 className="nfs-slideshow-text36">{props.nfsUng2_year}</h1>
              <h1 className="nfs-slideshow-text37">{props.nfsUng2_title}</h1>
              <button
                type="button"
                className="nfs-slideshow-button06 BIG button"
              >
                <span className="nfs-slideshow-text38 Button1">
                  <span className="nfs-slideshow-text39">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-most-wanted swiper-slide"
          >
            <div className="nfs-slideshow-container08">
              <img
                alt="https://static.wikia.nocookie.net/nfs/images/5/5f/NFSMW_BlackEdition_Boxart.jpg/revision/latest?cb=20200606133400&amp;path-prefix=en"
                src="https://e1.pxfuel.com/desktop-wallpaper/683/461/desktop-wallpaper-need-for-speed-most-wanted-black-edition.jpg"
                className="nfs-slideshow-image07"
              />
              <h1 className="nfs-slideshow-text41">{props.nfsMostWant_nfs}</h1>
              <h1 className="nfs-slideshow-text42">{props.nfsMostWant_year}</h1>
              <h1 className="nfs-slideshow-text43">
                {props.nfsMostWant_title}
              </h1>
              <button
                type="button"
                className="nfs-slideshow-button07 BIG button"
              >
                <span className="nfs-slideshow-text44 Button1">
                  <span className="nfs-slideshow-text45">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-carbon swiper-slide"
          >
            <div className="nfs-slideshow-container09">
              <img
                alt="https://images.igdb.com/igdb/image/upload/t_cover_big_2x/co209k.jpg"
                src="https://images.stopgame.ru/games/logos/8065/need_for_speed_carbon-square_1.jpg"
                className="nfs-slideshow-image08"
              />
              <h1 className="nfs-slideshow-text47">{props.nfsCarbon_nfs}</h1>
              <h1 className="nfs-slideshow-text48">{props.nfsCarbon_year}</h1>
              <h1 className="nfs-slideshow-text49">{props.nfsCarbon_title}</h1>
              <button
                type="button"
                className="nfs-slideshow-button08 BIG button"
              >
                <span className="nfs-slideshow-text50 Button1">
                  <span className="nfs-slideshow-text51">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-prostreet swiper-slide"
          >
            <div className="nfs-slideshow-container10">
              <img
                alt="https://upload.wikimedia.org/wikipedia/en/1/16/NFS_ProStreet_cover.png"
                src="https://cdn2.steamgriddb.com/file/sgdb-cdn/grid/8bb604aef2c0b402c5006bba0e536e3e.png"
                className="nfs-slideshow-image09"
              />
              <h1 className="nfs-slideshow-text53">{props.nfsProstreet_nfs}</h1>
              <h1 className="nfs-slideshow-text54">
                {props.nfsProstreet_year}
              </h1>
              <h1 className="nfs-slideshow-text55">
                {props.nfsProstreet_title}
              </h1>
              <button
                type="button"
                className="nfs-slideshow-button09 BIG button"
              >
                <span className="nfs-slideshow-text56 Button1">
                  <span className="nfs-slideshow-text57">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-undercover swiper-slide"
          >
            <div className="nfs-slideshow-container11">
              <img
                alt="https://downloadwap.com/thumbs4/games/preview/2020d/img/368748_need_for_speed_under_1.jpg"
                src="https://assets-prd.ignimgs.com/2022/03/25/nfsundercover-1648241420268.jpg"
                className="nfs-slideshow-image10"
              />
              <h1 className="nfs-slideshow-text59">{props.nfsUnder_nfs}</h1>
              <h1 className="nfs-slideshow-text60">{props.nfsUnder_year}</h1>
              <h1 className="nfs-slideshow-text61">{props.nfsUnder_title}</h1>
              <button
                type="button"
                className="nfs-slideshow-button10 BIG button"
              >
                <span className="nfs-slideshow-text62 Button1">
                  <span className="nfs-slideshow-text63">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-shift swiper-slide"
          >
            <div className="nfs-slideshow-container12">
              <img
                alt="https://assets-prd.ignimgs.com/2022/08/31/nfsshiftpsp-1661952573028.jpg"
                src="https://static.wikia.nocookie.net/nfs/images/3/3d/NFSS_Boxart.jpg/revision/latest?cb=20180301170009&amp;path-prefix=en"
                className="nfs-slideshow-image11"
              />
              <h1 className="nfs-slideshow-text65">{props.nfsShift_nfs}</h1>
              <h1 className="nfs-slideshow-text66">{props.nfsShift_year}</h1>
              <h1 className="nfs-slideshow-text67">{props.nfsShift_title}</h1>
              <button
                type="button"
                className="nfs-slideshow-button11 BIG button"
              >
                <span className="nfs-slideshow-text68 Button1">
                  <span className="nfs-slideshow-text69">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-shift2-unleashed swiper-slide"
          >
            <div className="nfs-slideshow-container13">
              <img
                alt="https://www.gamingdragons.com/images/game_img/nfss2u.jpg"
                src="https://assets-prd.ignimgs.com/2022/04/04/shift2unleashed-1649108537152.jpg"
                className="nfs-slideshow-image12"
              />
              <h1 className="nfs-slideshow-text71">{props.nfsShift2_nfs}</h1>
              <h1 className="nfs-slideshow-text72">{props.nfsShift2_year}</h1>
              <h1 className="nfs-slideshow-text73">{props.nfsShift2_title}</h1>
            </div>
            <button type="button" className="nfs-slideshow-button12 BIG button">
              <span className="nfs-slideshow-text74 Button1">
                <span className="nfs-slideshow-text75">PLAY</span>
                <br></br>
              </span>
            </button>
          </div>
          <div
            data-thq="slider-slide"
            className="nfs-slideshow-nfs-the-run swiper-slide"
          >
            <div className="nfs-slideshow-container14">
              <img
                alt="https://m.media-amazon.com/images/M/MV5BZjBlMGFlYTMtZTY0NS00YTgwLWFjNjMtODUwNWE5NDBiNzk1XkEyXkFqcGdeQXVyNTgyNTA4MjM@._V1_.jpg"
                src="https://www.giantbomb.com/a/uploads/original/9/93770/2392938-3.jpg"
                className="nfs-slideshow-image13"
              />
              <h1 className="nfs-slideshow-text77">{props.nfsRun_nfs}</h1>
              <h1 className="nfs-slideshow-text78">{props.nfsRun_year}</h1>
              <h1 className="nfs-slideshow-text79">{props.nfsRun_title}</h1>
              <button
                type="button"
                className="nfs-slideshow-button13 BIG button"
              >
                <span className="nfs-slideshow-text80 Button1">
                  <span className="nfs-slideshow-text81">PLAY</span>
                  <br></br>
                </span>
              </button>
            </div>
          </div>
        </div>
        <div
          data-thq="slider-pagination"
          className="nfs-slideshow-slider-pagination swiper-pagination swiper-pagination-bullets swiper-pagination-horizontal"
        >
          <div
            data-thq="slider-pagination-bullet"
            className="swiper-pagination-bullet swiper-pagination-bullet-active"
          ></div>
        </div>
        <div
          data-thq="slider-button-prev"
          className="nfs-slideshow-slider-button-prev swiper-button-prev"
        ></div>
        <div
          data-thq="slider-button-next"
          className="nfs-slideshow-slider-button-next swiper-button-next"
        ></div>
      </div>
      <div className="nfs-slideshow-container15">
        <h1 className="nfs-slideshow-text83">
          if you have any issues running any games,
        </h1>
        <a
          href="https://path/to/drivers"
          target="_blank"
          rel="noreferrer noopener"
          className="nfs-slideshow-link"
        >
          <h1 className="nfs-slideshow-text84">download these drivers</h1>
        </a>
      </div>
    </div>
  )
}

NfsSlideshow.defaultProps = {
  nfsUnder_nfs: 'Need for Speed',
  nfsHighStakes_title: 'High Stakes',
  nfsHotPursuit2_year: '2002',
  nfsUng2_year: '2004',
  nfsShift_year: '2009',
  nfsHighStakes_nfs: 'Need for Speed',
  nfsPorche_year: '2000',
  nfsUng2_title: 'Underground 2',
  nfsShift2_year: '2011',
  nfsCarbon_year: '2006',
  nfs3HotPursuit_year: '1998',
  nfsPorche_title: 'Porche Unleashed',
  nfsMostWant_nfs: 'Need for Speed',
  nfsProstreet_year: '2007',
  nfsUng_nfs: 'Need for Speed',
  nfsUng_title: 'Underground',
  nfsCarbon_nfs: 'Need for Speed',
  nfsUnder_title: 'Undercover',
  nfsProstreet_title: 'Prostreet',
  nfsProstreet_nfs: 'Need for Speed',
  nfsHotPursuit2_title: 'Hot Pursuit 2',
  nfsHighStakes_year: '1999',
  nfsRun_nfs: 'Need For Speed',
  heading2: 'Heading',
  nfsUnder_year: '2008',
  nfs1994_year: '1994',
  nfs3HotPursuit_title: 'Hot Pursuit',
  nfsShift2_nfs: 'Need For Speed',
  nfsHotPursuit2_nfs: 'Need for Speed',
  heading: 'Heading',
  nfsShift_nfs: 'Need for Speed',
  nfsRun_title: 'The Run',
  nfsMostWant_year: '2005',
  nfsMostWant_title: 'Most Wanted',
  nfs3HotPursuit_nfs: 'NEED FOR SPEED III',
  nfs1994_heading: 'THE NEED FOR SPEED',
  nfsCarbon_title: 'Carbon',
  nfsShift_title: 'Shift',
  nfsShift2_title: 'Shift 2: Unleashed',
  nfsUng2_nfs: 'Need for Speed',
  nfsPorche_nfs: 'Need for Speed',
  nfsUng_year: '2003',
  nfsRun_year: '2011',
}

NfsSlideshow.propTypes = {
  nfsUnder_nfs: PropTypes.string,
  nfsHighStakes_title: PropTypes.string,
  nfsHotPursuit2_year: PropTypes.string,
  nfsUng2_year: PropTypes.string,
  nfsShift_year: PropTypes.string,
  nfsHighStakes_nfs: PropTypes.string,
  nfsPorche_year: PropTypes.string,
  nfsUng2_title: PropTypes.string,
  nfsShift2_year: PropTypes.string,
  nfsCarbon_year: PropTypes.string,
  nfs3HotPursuit_year: PropTypes.string,
  nfsPorche_title: PropTypes.string,
  nfsMostWant_nfs: PropTypes.string,
  nfsProstreet_year: PropTypes.string,
  nfsUng_nfs: PropTypes.string,
  nfsUng_title: PropTypes.string,
  nfsCarbon_nfs: PropTypes.string,
  nfsUnder_title: PropTypes.string,
  nfsProstreet_title: PropTypes.string,
  nfsProstreet_nfs: PropTypes.string,
  nfsHotPursuit2_title: PropTypes.string,
  nfsHighStakes_year: PropTypes.string,
  nfsRun_nfs: PropTypes.string,
  heading2: PropTypes.string,
  nfsUnder_year: PropTypes.string,
  nfs1994_year: PropTypes.string,
  nfs3HotPursuit_title: PropTypes.string,
  nfsShift2_nfs: PropTypes.string,
  nfsHotPursuit2_nfs: PropTypes.string,
  heading: PropTypes.string,
  nfsShift_nfs: PropTypes.string,
  nfsRun_title: PropTypes.string,
  nfsMostWant_year: PropTypes.string,
  nfsMostWant_title: PropTypes.string,
  nfs3HotPursuit_nfs: PropTypes.string,
  nfs1994_heading: PropTypes.string,
  nfsCarbon_title: PropTypes.string,
  nfsShift_title: PropTypes.string,
  nfsShift2_title: PropTypes.string,
  nfsUng2_nfs: PropTypes.string,
  nfsPorche_nfs: PropTypes.string,
  nfsUng_year: PropTypes.string,
  nfsRun_year: PropTypes.string,
}

export default NfsSlideshow

Solution

  • First, it's important to know that for security reasons, various security features are activated by default on your BrowserWindow, and unless you are sure security doesn't apply on your app, you should not disable them. This is the default recommended configuration:

    new BrowserWindow({
      webPreferences: {
        contextIsolation: true,
        nodeIntegration: false,
        webSecurity: true,
        sandbox: true
      }
    });
    

    When configured like this, you will get require error when trying to require/import something you're not allowed to.

    In the other hand, when you get this error:

    Module not found: Error: Can't resolve 'fs' in 'xxx'
    

    It means you're trying to use Electron and/or Node.js APIs into your renderer (i.e. your React code), which – apart from being unsecure – your bundler (webpack) is not configured for.

    If you need to call Node.js/Electron stuff from your React code without disabling security, you need to use a preload file and IPC. In addition, make sure to read about sandboxing.

    Finally, for the not allowed to load local resource error, this is because of webSecurity. It's not clear what you mean by "open file explorer", but maybe what you want is to use a dialog. Otherwise, if using IPC doesn't solve the issue, you may have to use a custom protocol.