javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > Uncaught ReferenceError: require is not defined

TS/JS打包后报Uncaught ReferenceError: require is not defined问题解决办法

作者:python全栈小辉

在开发过程中,我们经常会遇到打包报错的错误,这篇文章主要介绍了TS/JS打包后报Uncaught ReferenceError: require is not defined问题的解决办法,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

TS/JS项目开发环境运行正常,打包部署到浏览器后控制台抛出Uncaught ReferenceError: require is not defined,是前端跨环境开发中最典型的模块规范兼容错误。核心原因是代码中残留了Node.js专属的CommonJS模块语法(require/module.exports),而浏览器原生环境并不支持该语法,打包工具未完成CommonJS到浏览器可识别的ES模块/全局变量的转换,导致执行时无法找到require方法。

本文从错误本质、模块规范差异出发,梳理该错误的6个高频场景(按出现概率排序),覆盖原生代码、TS配置、Webpack/Vite/Rollup打包配置、第三方依赖等所有诱因,提供分工具的可落地配置方案通用排查流程,同时给出TS/JS+主流打包工具的兼容配置模板,彻底解决浏览器端require is not defined问题。

一、核心认知:为什么会报require is not defined?

排查前先明确模块规范差异错误本质,这是解决问题的关键——require并非JS原生语法,而是Node.js为实现CommonJS模块规范新增的方法,浏览器无此内置API,代码中出现未被转换的require就会直接报错。

1.1 两大核心模块规范的环境差异

前端开发中主要用到**CommonJS(CJS)ES模块(ESM)**两种规范,二者的运行环境、语法完全不同,这是错误产生的底层原因:

模块规范核心语法运行环境浏览器原生支持打包工具处理方式
CommonJS导入require('xxx')、导出module.exports/exportsNode.js端(默认)❌ 完全不支持需转换为ESM/浏览器全局变量
ES模块导入import xxx from 'xxx'、导出export default/exportNode.js(需配置)+ 浏览器✅ 现代浏览器原生支持可直接使用,或打包为兼容语法

1.2 错误的3个核心根源

所有require is not defined错误,本质都是代码中存在未被打包工具转换的CommonJS语法,诱因分为三类,无其他例外:

  1. 手写代码混用CommonJS语法:在TS/JS中直接写require/module.exports,打包工具未配置转换规则;
  2. 编译/打包配置错误:TS编译后生成CommonJS代码、打包工具未开启CommonJS转ES模块功能;
  3. 第三方依赖/打包产物残留CJS语法:老版本依赖内部用CommonJS编写、打包工具未处理第三方依赖的CJS语法,或直接运行未打包的Node端代码到浏览器。

1.3 快速判断错误类型(按排查优先级)

根据报错位置和代码场景,可快速定位排查方向,避免盲目修改:

  1. 报错指向自己的代码:手写了require/TS配置错误导致编译出require
  2. 报错指向打包后的vendor.js/第三方依赖:第三方依赖为CJS语法,打包工具未处理;
  3. 直接运行TS/JS文件报错:未经过打包工具处理,直接将Node端代码放到浏览器运行;
  4. 仅生产打包报错/开发正常:打包工具的开发/生产配置不一致,生产环境未开启CJS转换。

二、最高频6大场景:原因+错误示例+可落地解决方案

以下按实际开发中出现概率从高到低排序,覆盖所有require is not defined的触发场景,每个场景均提供错误表现、错误示例、核心原因、针对性解决方案,适配Webpack/Vite/Rollup/纯TS编译等所有项目类型。

场景1:代码中直接使用require/module.exports(最高频,占比40%)

错误表现

报错指向自己的业务代码,如Uncaught ReferenceError: require is not defined at index.js:10,对应行是手写的require

错误示例

// JS/TS中直接使用CommonJS语法(浏览器不支持)
// 错误1:导入用require
const axios = require('axios')
const utils = require('./utils')
// 错误2:导出用module.exports/exports
module.exports = { add: (a,b) => a+b }
exports.get = (id) => ({ id: id })
// 错误3:TS中混用require和import(编译后残留require)
import Vue from 'vue'
const Router = require('vue-router')

核心原因

开发者习惯了Node.js的CommonJS语法,在浏览器端代码中直接手写require/module.exports,打包工具默认未对业务代码的CJS语法做全量转换,导致打包后残留该语法。

解决方案

彻底替换为浏览器原生支持的ES模块语法,这是最根本的解决方法,TS/JS通用,示例:

// 正确1:导入用import
import axios from 'axios'
import utils from './utils'
// 按需导入
import { getToken } from './utils/token'
// 正确2:导出用export default/export
// 默认导出
export default { add: (a,b) => a+b }
// 按需导出
export const get = (id) => ({ id: id })
// 正确3:TS中统一使用ES模块,不混用
import Vue from 'vue'
import Router from 'vue-router'

注意:若需动态导入模块,使用ES模块的import()函数(浏览器/打包工具均支持),替代Node.js的动态require

// 正确:ES模块动态导入
const loadModule = async () => {
  const utils = await import('./utils')
  utils.getToken()
}
// 错误:Node.js动态require(浏览器不支持)
// const utils = require(`./utils/${name}`)

场景2:TS配置错误,编译后生成CommonJS的require(TS项目专属,占比25%)

错误表现

TS项目中未手写任何require,但打包/运行后仍报require is not defined,报错代码是TS编译后的JS文件,包含require/module.exports

核心原因

TS的编译配置文件tsconfig.json中,module字段默认值为CommonJS,TS编译器(tsc)会将ES模块的import/export编译为Node.js的require/module.exports,生成的JS文件直接在浏览器运行就会报错。

解决方案

修改tsconfig.json模块编译配置,让TS编译后生成浏览器/打包工具可识别的ES模块语法,核心修改modulemoduleResolution字段,完整关键配置:

// tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext", // 编译为最新ES语法,可根据项目需求改为ES6/ES2020
    "module": "ESNext", // 核心:编译为ES模块,避免生成require
    "moduleResolution": "Bundler", // 模块解析策略,适配Webpack/Vite/Rollup
    // "moduleResolution": "NodeNext", // 兼容老版本打包工具,二选一
    "esModuleInterop": true, // 兼容CommonJS模块的ES模块导入
    "outDir": "./dist", // 编译输出目录
    "rootDir": "./src", // 源码根目录
    "strict": true // 严格模式(可选,根据项目需求)
  },
  "include": ["./src/**/*"], // 要编译的文件
  "exclude": ["node_modules", "dist"] // 排除的文件
}

关键说明

场景3:Vite项目未配置CommonJS依赖转换(Vite专属,高频)

错误表现

Vite项目开发正常,打包后报require is not defined,报错指向node_modules中的第三方依赖(如老版本的echartsjquery)。

核心原因

Vite天生基于ES模块开发,对CommonJS语法的第三方依赖支持不佳,开发环境中Vite会自动对CJS依赖做临时转换,但生产打包时若未显式配置,会残留require语法,导致浏览器报错。

解决方案

vite.config.js/ts中配置CommonJS依赖转换规则,通过build.commonjsOptions强制Vite处理CJS语法的依赖,同时配置optimizeDeps预构建CJS依赖,完整配置:

// vite.config.js/ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' // Vue项目可选,根据项目调整
import path from 'path'
export default defineConfig({
  plugins: [vue()],
  resolve: { alias: { '@': path.resolve(__dirname, 'src') } },
  // 核心1:预构建CommonJS依赖,转换为ES模块
  optimizeDeps: {
    include: ['echarts', 'jquery'], // 填入你的CJS语法第三方依赖包名
    esbuildOptions: {
      format: 'esm' // 预构建为ES模块
    }
  },
  // 核心2:生产打包时强制转换CommonJS语法
  build: {
    commonjsOptions: {
      transformMixedEsModules: true, // 处理混合了ES和CJS语法的依赖
      include: /node_modules/ // 处理所有node_modules中的CJS依赖
    }
  }
})

兜底方案:若个别依赖仍转换失败,使用vite-plugin-commonjs插件增强转换能力:

# 安装插件
npm install vite-plugin-commonjs --save-dev
// vite.config.js/ts
import { defineConfig } from 'vite'
import commonjs from 'vite-plugin-commonjs'
export default defineConfig({
  plugins: [
    commonjs(), // 注册插件,自动转换CJS语法
    vue()
  ]
})

场景4:Webpack/Rollup配置缺失,未处理CommonJS语法(打包工具专属)

错误表现

Webpack/Rollup项目中,代码用了ES模块,但第三方依赖为CJS语法,打包后报require is not defined,报错指向依赖代码。

核心原因

  1. Webpack:低版本Webpack(<4)需手动安装插件处理CJS,高版本Webpack默认处理,但若配置了externals排除了依赖,会导致未转换;
  2. Rollup:天生基于ES模块,对CJS语法支持差,必须手动安装插件才能处理CJS依赖,否则直接残留require

解决方案

分Webpack和Rollup给出针对性配置,均为开箱即用:

方案1:Webpack项目(高版本/低版本通用)

确保Webpack处理所有CJS依赖,避免externals错误排除,核心配置:

// webpack.config.js
const path = require('path')
module.exports = {
  entry: './src/index.ts',
  output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') },
  resolve: { extensions: ['.ts', '.js', '.json'] },
  module: { rules: [{ test: /\.ts$/, loader: 'ts-loader' }] },
  // 关键:若需配置externals,仅排除CDN引入的依赖,不要排除本地安装的CJS依赖
  externals: {
    // 示例:CDN引入的Vue,排除后不参与打包,浏览器通过全局变量Vue获取
    vue: 'Vue'
  },
  mode: 'production'
}

注意:Webpack5/4默认会将CJS语法转换为浏览器可执行的代码,无需额外插件,避免随意配置externals排除本地依赖是关键。

方案2:Rollup项目(必须安装插件)

安装Rollup的CJS转换插件,处理自身代码和第三方依赖的CJS语法,步骤:

  1. 安装所需插件
npm install @rollup/plugin-commonjs @rollup/plugin-node-resolve --save-dev
  1. Rollup配置文件(rollup.config.js)
// rollup.config.js
import commonjs from '@rollup/plugin-commonjs'
import nodeResolve from '@rollup/plugin-node-resolve'
import typescript from '@rollup/plugin-typescript' // TS项目可选
export default {
  input: './src/index.ts',
  output: [{ file: 'dist/bundle.js', format: 'esm' }], // 输出为ES模块
  plugins: [
    nodeResolve(), // 解析node_modules中的依赖
    commonjs(), // 核心:将CommonJS转换为ES模块
    typescript() // TS编译(可选)
  ]
}

场景5:直接运行未打包的TS/JS文件,未经过编译转换(新手高频)

错误表现

将TS/JS文件直接通过script标签引入浏览器(如<script src="./src/index.ts"></script>),未使用任何打包工具,直接报require is not defined

核心原因

  1. 浏览器无法直接运行TS文件,也无法识别TS/JS中的require和ES模块语法;
  2. 未通过打包工具(Webpack/Vite/Rollup)或编译器(tsc/babel)将代码转换为浏览器可识别的纯JS语法。

解决方案

必须通过工具处理后再引入浏览器,分两种简单方案,新手友好:

方案1:使用打包工具(推荐,适配所有项目)

执行项目的打包命令,将TS/JS打包为单个浏览器可运行的JS文件,再引入:

# Vite项目
npm run build
# Webpack项目
npm run build
# Rollup项目
npx rollup -c

引入打包后的文件(通常在dist目录下):

<!-- 正确:引入打包后的纯JS文件 -->
<script src="./dist/bundle.js"></script>
<!-- 错误:直接引入未打包的TS/JS源文件 -->
<!-- <script src="./src/index.ts"></script> -->

方案2:纯TS项目快速编译(无打包工具)

通过tsc将TS编译为ES模块的JS文件,再通过script标签的type="module"引入:

  1. 场景2修改tsconfig.json,确保编译为ES模块;
  2. 执行TS编译命令:
npx tsc
  1. 引入编译后的JS文件,添加type="module"
<script src="./dist/index.js" type="module"></script>

注意type="module"是浏览器识别ES模块的关键,添加后才能支持import/export

场景6:第三方依赖通过CDN引入,全局变量缺失导致间接报require错误

错误表现

将第三方依赖通过CDN引入(如<script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.common.js"></script>),业务代码中用import/require引入该依赖,打包后报require is not defined

核心原因

  1. CDN引入的依赖会暴露全局变量(如echarts暴露window.echarts),无需再通过import/require引入;
  2. 若业务代码中仍用import/require引入,打包工具会尝试解析该依赖,若配置了externals则会残留require,未配置则会打包失败。

解决方案

两步操作:排除依赖打包 + 业务代码使用全局变量,以echarts为例:

  1. 打包工具中配置externals,排除该依赖(不参与打包):
    • Vite/Webpack/Rollup配置方式一致,以Vite为例:
    // vite.config.js
    export default defineConfig({
      build: { rollupOptions: { externals: { echarts: 'echarts' } } }
    })
  2. 业务代码中直接使用全局变量,不再导入
    // 正确:直接使用CDN暴露的全局变量
    const myChart = echarts.init(document.getElementById('chart'))
    // 错误:继续导入,导致打包残留require
    // import * as echarts from 'echarts'
    // const echarts = require('echarts')

三、主流工具通用配置模板(开箱即用,避免99%的require错误)

结合以上所有解决方案,提供TS+Webpack5、TS+Vite、纯JS+Rollup三大主流项目的完整配置模板,直接复制到项目中即可,从根源上避免require is not defined错误。

模板1:TS+Webpack5项目(通用企业级配置)

包含TS编译、CJS转换、ES模块兼容所有核心配置,直接使用:

// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  entry: './src/index.ts',
  output: {
    filename: 'assets/js/[name].[hash:8].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.json'],
    alias: { '@': path.resolve(__dirname, 'src') }
  },
  module: {
    rules: [
      { test: /\.tsx?$/, loader: 'ts-loader', exclude: /node_modules/ }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ template: './public/index.html' })
  ],
  // 仅排除CDN引入的依赖,本地CJS依赖由Webpack自动转换
  externals: {
    // vue: 'Vue', // 示例:CDN引入Vue时开启
    // echarts: 'echarts'
  },
  mode: 'production'
}
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES6",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "allowJs": true
  },
  "include": ["./src/**/*"],
  "exclude": ["node_modules", "dist"]
}

模板2:TS+Vite项目(前端主流配置)

专为Vite优化,强制转换CJS依赖,适配Vue/React/纯TS项目:

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import commonjs from 'vite-plugin-commonjs'
export default defineConfig({
  plugins: [vue(), commonjs()],
  resolve: { alias: { '@': path.resolve(__dirname, 'src') } },
  optimizeDeps: {
    include: ['echarts', 'jquery'], // 预构建CJS依赖
    esbuildOptions: { format: 'esm' }
  },
  build: {
    commonjsOptions: {
      transformMixedEsModules: true,
      include: /node_modules/
    },
    rollupOptions: {
      externals: { /* echarts: 'echarts' */ }
    }
  }
})
// tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "esModuleInterop": true,
    "strict": true,
    "jsx": "preserve",
    "baseUrl": ".",
    "paths": { "@/*": ["src/*"] }
  },
  "include": ["src/**/*", "vite.config.ts"],
  "exclude": ["node_modules"]
}

模板3:纯JS+Rollup项目(轻量库开发配置)

轻量无冗余,专门处理CJS语法,适配前端库开发:

// rollup.config.js
import commonjs from '@rollup/plugin-commonjs'
import nodeResolve from '@rollup/plugin-node-resolve'
import { babel } from '@rollup/plugin-babel'
export default {
  input: './src/index.js',
  output: [
    { file: 'dist/bundle.esm.js', format: 'esm' }, // 输出ES模块
    { file: 'dist/bundle.umd.js', format: 'umd', name: 'MyLib' } // 输出UMD(兼容浏览器/Node)
  ],
  plugins: [
    nodeResolve(),
    commonjs(), // 核心转换CJS
    babel({ babelHelpers: 'bundled', exclude: /node_modules/ })
  ],
  externals: { /* jquery: '$' */ }
}

四、通用排查流程:三步定位所有require is not defined错误(1分钟搞定)

遇到TS/JS打包后报require is not defined,无需盲目修改配置,按以下三步排查流程执行,1分钟内可定位所有问题根源,适用于所有项目类型:

步骤1:检查代码是否手写了require/module.exports(排除基础问题)

  1. 全局搜索项目代码中的requiremodule.exportsexports.,若有则全部替换为ES模块的import/export
  2. 检查是否有动态require,替换为ES模块的import()异步函数。

步骤2:检查编译/打包配置(核心排查)

  1. TS项目:打开tsconfig.json,确认moduleESNext/ES6moduleResolutionBundler/NodeNext,避免编译出require;
  2. Vite项目:确认配置了build.commonjsOptionsoptimizeDeps,或安装了vite-plugin-commonjs
  3. Rollup项目:确认安装并注册了@rollup/plugin-commonjs@rollup/plugin-node-resolve
  4. Webpack项目:确认未随意配置externals排除本地CJS依赖,高版本Webpack无需额外插件。

步骤3:检查代码运行/引入方式(排除环境问题)

  1. 确认是否直接运行未打包/未编译的TS/JS文件,若是则通过打包工具处理后再引入;
  2. 确认CDN引入的依赖是否被重复导入,若是则配置externals并使用全局变量;
  3. 生产环境报错的话,对比开发/生产的打包配置,确保生产环境开启了CJS转换。

验证方法:每修改一步,重新打包并在浏览器中运行,打开F12→Sources面板,查看打包后的JS文件是否还有require,无则问题解决。

五、高频避坑点(企业开发规范,避免重复踩坑)

  1. 浏览器端代码彻底抛弃CommonJS:永远使用import/export,不手写require/module.exports,从根源避免问题;
  2. TS配置必改module:新建TS项目后,第一时间将tsconfig.jsonmodule改为ESNext,避免编译出require;
  3. Vite项目必配CJS转换:使用Vite开发时,只要引入了老版本CJS依赖,就必须配置build.commonjsOptionsvite-plugin-commonjs
  4. Rollup项目必装commonjs插件:Rollup天生不支持CJS,未安装@rollup/plugin-commonjs必报require错误;
  5. 避免直接引入未处理的TS/JS:浏览器无法运行TS,也无法识别模块语法,必须通过打包/编译工具处理;
  6. CDN依赖不重复导入:CDN引入的依赖通过全局变量使用,不要在代码中import/require,并配置externals排除打包;
  7. 开发/生产配置保持一致:不要在开发环境配置CJS转换,生产环境却删除,导致开发正常生产报错。

六、总结

TS/JS打包后报Uncaught ReferenceError: require is not defined的问题,本质是「环境不兼容」导致的模块语法残留——require是Node.js的CommonJS专属语法,浏览器无此API,打包后代码中只要残留未转换的require,就会触发该错误。

核心解决思路可总结为3个核心动作,三者结合可解决100%的该类错误:

  1. 代码层:彻底替换为ES模块语法(import/export),不手写任何require/module.exports
  2. 编译层:TS项目修改tsconfig.json,确保编译后生成ES模块,不产生require;
  3. 打包层:配置打包工具(Vite/Webpack/Rollup)处理第三方依赖的CJS语法,强制转换为浏览器可识别的代码。

遵循本文的6大高频场景解决方案三步通用排查流程,可快速定位并解决所有require is not defined错误;直接使用主流工具通用配置模板,可从根源上避免99%的该类错误,让TS/JS项目在浏览器端的运行更稳定。

到此这篇关于TS/JS打包后报Uncaught ReferenceError: require is not defined问题解决办法的文章就介绍到这了,更多相关Uncaught ReferenceError: require is not defined内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文