无法构建作为编辑过的 node_modules 包的 React 项目

问题描述

我不得不编辑一个 npm 包 react-scrollspy-nav,因为我注意到没有“this”的闭包,它给了我一个“无法读取 null 错误属性”,但问​​题是'不关心那个问题。我在 node_modules 中编辑了已安装包的文件夹,但功能是从那里的 dist 文件夹提供的,所以我需要构建应用程序,然后我将使用 patch-package 模块来保存 pacthes/ 文件夹中的更改。但是 yarn build 命令给了我一个错误,webpack 无法解析 index.js 和 ScrollSpyNav.js 文件。这是日志,请帮我解决这个问题:

yarn run v1.22.10
$ webpack --mode production && npm run test
Hash: 3f65f4938c304814a23b
Version: webpack 4.46.0
Time: 22075ms
Built at: 02.07.2021 15:13:13
 3 assets
Entrypoint app = app.js style.css
Entrypoint ScrollspyNav = ScrollspyNav.js
[0] multi ./src/index.js ./src/scss/app.scss 40 bytes {1} [built]
[1] ./src/index.js 325 bytes {1} [built] [Failed] [1 error]
[2] multi ./src/lib/ScrollspyNav.js 28 bytes {0} [built]
[3] ./src/lib/ScrollspyNav.js 344 bytes {0} [built] [Failed] [1 error]
[4] ./src/scss/app.scss 41 bytes [built]
[6] ./node_modules/css-loader/dist/cjs.js??ref--5-2!./node_modules/sass-loader/dist/cjs.js??ref--5-3!./src/scss/app.scss 3.35 KiB [built]
    + 2 hidden modules

ERROR in ./src/lib/ScrollspyNav.js 153:6
Module parse Failed: Unexpected token (153:6)
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
|   render() {
|     return(
>       <div data-nav="list">
|         { this.props.children }
|       </div>
 @ multi ./src/lib/ScrollspyNav.js ScrollspyNav[0]

ERROR in ./src/index.js 5:16
Module parse Failed: Unexpected token (5:16)
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
| import App from './App';
|
> ReactDOM.render(<App/>,document.getElementById('root'));
|
 @ multi ./src/index.js ./src/scss/app.scss app[0]
Child extract-text-webpack-plugin node_modules/extract-text-webpack-plugin/dist node_modules/css-loader/dist/cjs.js??ref--5-2!node_modules/sass-loader/dist/cjs.js??ref--5-3!src/scss/app.scss:
    Entrypoint undefined = extract-text-webpack-plugin-output-filename
    [0] ./node_modules/css-loader/dist/cjs.js??ref--5-2!./node_modules/sass-loader/dist/cjs.js??ref--5-3!./src/scss/app.scss 3.35 KiB {0} [built]
        + 1 hidden module
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [0] ./node_modules/html-webpack-plugin/lib/loader.js!./src/index.html 644 bytes {0} [built]
    [2] (webpack)/buildin/global.js 472 bytes {0} [built]
    [3] (webpack)/buildin/module.js 497 bytes {0} [built]
        + 1 hidden module
error Command Failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

这是这些文件

import React,{ Component } from 'react'; const SCROLLSPY_NAV_NAMESPACE = "react-scrollspy-nav";

/**
 * ScrollspyNav component. Refer to below for the props it receives
 */
class ScrollspyNav extends Component {
  constructor(props) {
    super(props);

    this.props = props;
    this.scrollTargetIds = this.props.scrollTargetIds;
    this.activeNavClass = this.props.activeNavClass;
    this.scrollDuration = Number(this.props.scrollDuration) || 1000;
    this.headerBackground = this.props.headerBackground === "true" ? true : false;
    this.offset = this.props.offset || 0;

    this.onScroll = this.onScroll.bind(this);

    if(this.props.router && this.props.router === "HashRouter") {
      this.homeDefaultLink = "#/";
      this.hashIdentifier = "#/#";
    } else {
      this.homeDefaultLink = "/";
      this.hashIdentifier = "#";
    }
  }

  /**
   * Scroll event handler. It checks the current window offset and compares it with the pageYOffset of each
   *  target sections. It highlights the nav link when scrolling to a corresponding section
   */
  onScroll() {
    console.log("scroll event called");
    let scrollSectionOffsetTop;
    this.scrollTargetIds.forEach((sectionID,index) => {
      if (!document.getElementById(sectionID)) {
        console.warn(`${SCROLLSPY_NAV_NAMESPACE}: no element with id ${sectionID} present in the DOM`);
        return;
      }

      scrollSectionOffsetTop = document.getElementById(sectionID).offsetTop - (this.headerBackground ? document.querySelector("div[data-nav='list']").scrollHeight : 0);
  
      if (window.pageYOffset - this.offset >= scrollSectionOffsetTop && window.pageYOffset < scrollSectionOffsetTop + document.getElementById(sectionID).scrollHeight) {
        this.getNavLinkElement(sectionID).classList.add(this.activeNavClass);
        this.clearOtherNavLinkActiveStyle(sectionID)
      } else {
        this.getNavLinkElement(sectionID).classList.remove(this.activeNavClass);
      }
  
      if (window.innerHeight + window.pageYOffset >= document.body.scrollHeight && index === this.scrollTargetIds.length - 1) {
        this.getNavLinkElement(sectionID).classList.add(this.activeNavClass);
        this.clearOtherNavLinkActiveStyle(sectionID);
      }
    });
  }

  easeInOutQuad(current_time,start,change,duration) {
      current_time /= duration/2;
      if (current_time < 1) return change/2*current_time*current_time + start;
      current_time--;
      return -change/2 * (current_time*(current_time-2) - 1) + start;
  };

  /**
   * Perform scroll animation with given start place,end place and duration
   * @param {Number} start
   * @param {Number} to
   * @param {Number} duration
   */
  scrollTo(start,to,duration) {
    let change = to - start,currentTime = 0,increment = 10;

    let animateScroll = () => {
        currentTime += increment;
        let val = this.easeInOutQuad(currentTime,duration);
        window.scrollTo(0,val);
        if(currentTime < duration) {
            setTimeout(animateScroll,increment);
        }
    };

    animateScroll();
  }

  /**
   * Get the nav link element with a given sectionID that the nav link links to
   * @param {String} sectionID
   */
  getNavLinkElement(sectionID) {
    return document.querySelector(`a[href='${this.hashIdentifier}${sectionID}']`);
  }

  /**
   * Given a nav href url,get its clean sectionID based on if there is hash router identifier or not
   * @param {String} navHref
   */
  getNavToSectionID(navHref) {
    return navHref.includes(this.hashIdentifier) ? navHref.replace(this.hashIdentifier,"") : "";
  }

  /**
   * Clear the highlight style on the non-current viewed nav elements
   * @param {String} excludeSectionID 
   */
  clearOtherNavLinkActiveStyle(excludeSectionID) {
    this.scrollTargetIds.map((sectionID,index) => {
      if (sectionID !== excludeSectionID) {
        this.getNavLinkElement(sectionID).classList.remove(this.activeNavClass);
      }
    });
  }

  componentDidMount() {
    if (document.querySelector(`a[href='${this.homeDefaultLink}#']`)) {
      document.querySelector(`a[href='${this.homeDefaultLink}#']`).addEventListener("click",(event) => {
        event.preventDefault();
        this.scrollTo(window.pageYOffset,this.scrollDuration);
        window.location.hash = "";
      });
    }

    document.querySelector("div[data-nav='list']").querySelectorAll("a").forEach( (navLink) => {
      navLink.addEventListener("click",(event) => {
        event.preventDefault();
        let sectionID = this.getNavToSectionID(navLink.getAttribute("href"));

        if(sectionID) {
          if (document.getElementById(sectionID)) {
            let scrollTargetPosition = document.getElementById(sectionID).offsetTop - (this.headerBackground ? document.querySelector("div[data-nav='list']").scrollHeight : 0);
            this.scrollTo(window.pageYOffset,scrollTargetPosition + this.offset,this.scrollDuration);
          } else {
            console.warn(`${SCROLLSPY_NAV_NAMESPACE}: no element with id ${sectionID} present in the DOM`);
          }
        } else {
          this.scrollTo(window.pageYOffset,this.scrollDuration);
        }
      });
    })

    window.addEventListener("scroll",this.onScroll);
  }

  componentwillUnmount() {
    window.removeEventListener("scroll",this.onScroll);
  }

  render() {
    return(
      <div data-nav="list">
        { this.props.children }
      </div>
    );
  }
}

export default ScrollspyNav;

Index js 是模板,只是通常:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App/>,document.getElementById('root'));

这里是 webpack.config.json :

const path = require('path'),WebpackShellPlugin = require("webpack-shell-plugin"),HtmlWebpackPlugin = require("html-webpack-plugin"),htmlWebpackPlugin = new HtmlWebpackPlugin({
        template: path.join(__dirname,"src/index.html"),filename: "index.html"
    }),ExtractTextPlugin = require("extract-text-webpack-plugin"),extractSass = new ExtractTextPlugin({
        filename: "style.css"
    });

module.exports = {
    entry: {
        app: [
            path.join(__dirname,"./src/index.js"),path.join(__dirname,"./src/scss/app.scss")
        ],ScrollspyNav: [
            path.join(__dirname,"./src/lib/ScrollspyNav.js")
        ]
    },output: {
       path: path.join(__dirname,"dist"),filename: "[name].js",libraryTarget: 'umd'
    },devtool: process.env.NODE_ENV === "production" ? "#hidden-source-map" : "#inline-source-map",module: {
        rules: [
            {
                test: /\.(js|jsx)$/,include: [
                    path.resolve(__dirname,'src'),],use: "babel-loader",exclude: /(node_modules)/,},{
                test: /\.s?css$/,use: extractSass.extract({
                    use: [{
                        loader: "css-loader",options: {
                            sourceMap: true
                        }
                    },{
                        loader: "sass-loader",options: {
                            sourceMap: true,sassOptions: {
                                outputStyle: 'compressed',}
                    }],fallback: "style-loader"
                })
            },{
                test: /\.md$/,loader: "raw-loader",options: {}
            }
        ]
    },plugins: [
        extractSass,htmlWebpackPlugin
    ],resolve: {
        extensions: [".js",".jsx"],modules: [
            'node_modules',devServer: {
        contentBase: './dist',publicPath: '/',port: 3001
    }
};

我在项目中唯一编辑的内容是:1) 在 Scroll Component 中添加了一些控制台日志,并从 webpack shell 插件删除了预构建脚本。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)