前端与Node.js

前端与Node.js

1. 前端(浏览器环境)

前端通常指的是在浏览器中运行的JavaScript代码。它主要负责用户界面的渲染、交互逻辑和与后端API的通信。

  • 核心运行环境:浏览器(如Chrome、Firefox、Safari等)
  • 核心引擎:V8(Chrome)、SpiderMonkey(Firefox)、JavaScriptCore(Safari)等
  • 宿主对象(Host Objects)
    • window:全局对象,提供浏览器窗口相关的API
    • document:DOM操作接口,用于构建和操作网页结构
    • navigator:获取浏览器信息
    • localStoragesessionStorage:浏览器本地存储
    • fetchXMLHttpRequest:网络请求API
  • 特点
    • 运行在客户端,直接面向用户
    • 受同源策略(Same-Origin Policy)限制
    • 需要考虑浏览器兼容性
    • 代码通常通过HTML文件加载

2. Node.js(服务器端环境)

Node.js是一个基于Chrome V8引擎 构建的JavaScript运行时,它允许JavaScript在服务器端运行。

  • 核心运行环境:Node.js 运行时
  • 核心引擎:V8(与Chrome浏览器相同)
  • 宿主对象
    • global:全局对象(相当于浏览器中的window
    • process:提供进程信息和控制
    • Buffer:处理二进制数据
    • requiremodule.exports:模块系统(CommonJS)
    • fspathhttp等:Node.js内置模块,提供文件系统、网络、路径处理等能力
  • 特点
    • 运行在服务器端,处理业务逻辑、数据存储、API服务等
    • 无浏览器安全限制(如同源策略)
    • 可直接访问操作系统资源(文件系统、网络等)
    • 通常通过命令行启动(node app.js

🌟 关键区别总结

维度 前端(浏览器) Node.js(服务器)
运行环境 浏览器 Node.js 运行时
全局对象 window global
模块系统 ES Modules(主流)、CommonJS(打包工具中) CommonJS(原生)、ES Modules(支持)
网络请求 fetchXMLHttpRequest httphttps 模块,或第三方库
文件系统 无法直接访问(受限) 可通过 fs 模块直接读写
主要用途 UI渲染、用户交互 后端服务、API、脚本工具

为什么Lodash、Axios能在前端和Node.js中"通用"?

这是本文的核心问题。答案是:它们是"环境无关"的JavaScript库,通过巧妙的设计实现了跨平台兼容

我们以 LodashAxios 为例,深入分析其原理。


🔹 案例1:Lodash ------ 纯函数工具库的"环境无关性"

Lodash 是一个提供大量实用函数的JavaScript工具库,如 _.debounce_.cloneDeep_.get 等。

为什么它能跨平台?
  1. 不依赖特定宿主对象

    • Lodash 的函数大多是纯函数(Pure Functions) ,只依赖输入参数,不依赖 windowdocumentfs 等环境特定对象。
    • 例如 _.cloneDeep(obj) 只操作JavaScript原生对象,不涉及DOM或文件系统。
  2. 模块化设计

    • Lodash 支持多种模块格式:CommonJS、ES Modules、UMD(Universal Module Definition)。

    • UMD 是关键!它是一种兼容多种环境的模块包装方式:

      复制代码
      (function (root, factory) {
          if (typeof define === 'function' && define.amd) {
              // AMD
              define([], factory);
          } else if (typeof module === 'object' && module.exports) {
              // CommonJS (Node.js)
              module.exports = factory();
          } else {
              // 浏览器全局变量
              root._ = factory();
          }
      }(typeof self !== 'undefined' ? self : this, function () {
          // Lodash 核心实现
          return _;
      }));
    • 这段代码会自动检测当前环境,选择合适的模块导出方式。

  3. 构建工具支持

    • 在前端项目中,Webpack、Vite等工具会将Lodash打包进最终的bundle.js。
    • 在Node.js中,直接通过 require('lodash') 加载。

结论 :Lodash 之所以通用,是因为它不依赖环境API + 使用UMD兼容多模块系统


🔹 案例2:Axios ------ HTTP客户端的"适配器模式"跨平台方案

Axios 是一个基于Promise的HTTP客户端,用于发送网络请求。

它比Lodash更复杂,因为网络请求在浏览器和Node.js中实现方式完全不同

  • 浏览器 :使用 XMLHttpRequestfetch
  • Node.js :使用 http / https 模块

那么,Axios是如何做到"一套API,两端运行"的?

核心机制:适配器模式(Adapter Pattern)

Axios 内部采用了适配器模式,根据运行环境自动选择合适的HTTP实现。

  1. 默认适配器选择逻辑

    复制代码
    // Axios 源码简化示意
    function getDefaultAdapter() {
      let adapter;
      if (typeof XMLHttpRequest !== 'undefined') {
        // 浏览器环境
        adapter = require('./adapters/xhr');
      } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
        // Node.js 环境
        adapter = require('./adapters/http');
      }
      return adapter;
    }
  2. 浏览器适配器 :使用 XMLHttpRequest 发送请求

  3. Node.js适配器 :使用 http 模块发送请求

  4. 统一的API层

    • 无论底层是XHR还是http模块,Axios向上暴露的API完全一致:

      复制代码
      axios.get('/api/users')
        .then(response => console.log(response.data));
  5. 配置化与可替换

    • Axios 允许开发者手动指定适配器,甚至使用自定义适配器。

结论 :Axios 通过适配器模式,在不同环境中使用不同的底层实现,但对外提供统一的API,从而实现跨平台。


如何判断一个库是否"跨平台通用"?

你可以通过以下几点快速判断:

判断标准 跨平台库(如Lodash) 非跨平台库(如jQuery)
是否依赖DOM/BOM API ❌ 不依赖 ✅ 依赖 documentwindow
是否依赖Node.js内置模块 ❌ 不依赖 fspath ✅ 如 fs-extra 只能在Node.js用
模块格式 支持 UMD 或 ESM + CJS 仅支持 CJS 或仅浏览器
构建方式 可通过CDN引入或npm安装 通常只能npm安装用于Node.js

✅ 推荐的跨平台库:Lodash、Axios、Moment.js(已归档)、Day.js、Zod、Yup等

❌ 仅Node.js库:expressfs-extrachild_process

❌ 仅浏览器库:jquerythree.js(虽可Node运行,但无意义)

特性 CJS (CommonJS) ESM (ES Modules) UMD (Universal)
语法 require() / module.exports import / export 兼容多种
加载方式 同步 异步(支持动态导入) 取决于环境
原生支持 Node.js ✅ 浏览器 ✅ + Node.js ✅ Node.js 从 v12+ 开始支持 (需 .mjs 扩展名或 package.json 中设置 "type": "module" ❌(需构建)
Tree Shaking ❌ 不支持 ✅ 支持 ❌ 通常不支持
适用环境 Node.js 前端 + 现代 Node.js 所有环境(兼容性最强)
典型使用 const _ = require('lodash') import _ from 'lodash' CDN 引入或老项目兼容

实际开发中的常见组合"ESM + CJS"

指的是一个 npm 包同时提供两种格式的构建版本:

  • dist/index.esm.js → 供前端构建工具(Vite/Webpack)使用 ESM
  • dist/index.cjs.js → 供 Node.js 直接 require 使用

例如 package.json 中可能这样配置:

复制代码
{
  "main": "dist/index.cjs.js",
  "module": "dist/index.esm.js",
  "exports": {
    ".": {
      "import": "./dist/index.esm.js",
      "require": "./dist/index.cjs.js"
    }
  }
}

前端工程项目打包

前端打包就是在 Node.js 环境下进行的

  • 谁在干活? → Node.js 进程中的打包工具(Webpack/Vite)
  • 输入是什么? → 你的源码 + node_modules 中的库
  • 输出是什么? → 适合浏览器加载的 .html.js.css.png 等静态文件
  • 为什么必须用 Node.js? → 因为需要文件系统、模块解析、高性能计算等能力,浏览器做不到

1. 代码是如何处理的?

  • 流程

    入口文件 → 递归解析 import → 收集所有模块(含 node_modules)→ 转换(Babel/TS)→ 优化 → 输出 dist/ 静态文件。

  • 关键机制

    • Tree Shaking:仅打包实际使用的代码(需 ESM 模块)。
    • Scope Hoisting:合并模块,减少闭包开销。
    • Code Splitting :自动分包(如 vendor.js),提升缓存利用率。

2. 变量(如 process.env)是如何处理的?

  • 机制构建时静态替换(不是运行时)。

  • 流程

    1. 打包工具读取 Node.js 环境变量(或 .env 文件)
    2. 在配置中定义替换规则(如 Vite 的 define,Webpack 的 DefinePlugin
    3. 源码中的 process.env.NODE_ENV 被替换为字符串(如 'production'
    4. 无用代码被 Tree Shaking 删除
  • ⚠️ 注意

    • 浏览器中没有 process,这是"伪变量"。
    • 敏感信息(如密钥)不应暴露在前端变量中。

3. 开发依赖(devDependencies)如何处理?

  • 不会被打包进前端文件
  • 用途 :仅在 Node.js 构建时使用,如:
    • 打包工具(Vite、Webpack)
    • 编译器(TypeScript、Babel)
    • 代码检查(ESLint、Prettier)
  • 类比:厨师的刀具,不端上餐桌。

4. 生产依赖(dependencies)如何处理?

  • 会被打包,但仅限"被引用"的部分
  • Tree Shaking 生效前提
    • 使用 ESM 语法:import { func } from 'lib'
    • 库支持 ESM 格式(package.jsonmodule 字段)
    • 生产模式构建(mode: 'production'
  • 不会打包
    • 未使用的库或函数(如只用 lodash.debounce,其他函数被摇掉)
    • 全量导入(import _ from 'lodash')会打包整个库(应避免)

✅ 一句话总结

打包是在 Node.js 中运行工具 ,将代码按需打包,通过 静态替换注入变量开发依赖不进前端生产依赖按需打包,最终生成轻量、高效的浏览器可用文件。

相关推荐
zmirror3 小时前
React-Router v6 useNavigate 非组件不生效
前端
红树林073 小时前
BeautifulSoup 的页面中需要获取某个元素的 xpath 路径
前端·python·网络爬虫·beautifulsoup
三小河4 小时前
教你发布一个npm的组织包
前端
青椒a4 小时前
002.nestjs后台管理项目-数据库之prisma(上)
前端
米诺zuo4 小时前
react 中的useContext和Provider实践
前端·react.js
asdfsdgss4 小时前
Angular CDK 自适应布局技巧:响应式工具实操手册
前端·javascript·angular.js
袁煦丞4 小时前
【私人导航员+内网穿透神器】Sun-Panel × cpolar让NAS变身你的数字管家:cpolar内网穿透实验室第564个成功挑战
前端·程序员·远程工作
爱吃的强哥4 小时前
Electron_Vue3 自定义系统托盘及退出二次确认
前端·javascript·electron
袁煦丞4 小时前
开启SSH后,你的NAS竟成私有云“变形金刚”:cpolar内网穿透实验室第645个成功挑战
前端·程序员·远程工作