对于前端开发者来说,Node.js 已经不仅是服务端语言,更是工程化工具的基石。本文从 Node.js 内置模块入手,贯通模块化标准、npm 包管理,最终落地到 Webpack 打包配置,帮助初学者建立完整的知识链路。
## 1. Node.js 基础:文件操作与路径安全
Node.js 基于 Chrome V8 引擎,让 JavaScript 脱离浏览器运行。执行脚本只需在终端运行 `node 文件名.js`。
### fs 模块:读写文件
`fs` 是 Node.js 内置的文件系统模块。写入文件使用 `fs.writeFile(path, data, callback)`,读取文件使用 `fs.readFile(path, callback)`,读取到的 `data` 是 Buffer 对象,需调用 `.toString()` 转换为字符串。
- const fs = require('fs');
- // 写入
- fs.writeFile('./test.txt', 'Hello FS', (err) => {
- if (err) console.log(err);
- else console.log('写入成功');
- });
- // 读取
- fs.readFile('./test.txt', (err, data) => {
- if (err) console.log(err);
- else console.log(data.toString()); // Hello FS
- });
复制代码
### path 模块:解决相对路径陷阱
Node.js 中相对路径是相对于终端工作目录,而非脚本文件所在目录。不同位置执行脚本可能导致路径找不到。安全做法是使用 `__dirname`(当前文件所在目录的绝对路径)配合 `path.join()` 拼接路径。
- const fs = require('fs');
- const path = require('path');
- const filePath = path.join(__dirname, '..', 'data.txt');
- fs.readFile(filePath, (err, data) => {
- if (err) console.log(err);
- else console.log(data.toString());
- });
复制代码
`path.join()` 会自动根据操作系统规则拼接路径片段。
### 实战:压缩 HTML 文件
前端工程化中常见的一步是压缩 HTML,去除回车和换行符。
- const fs = require('fs');
- const path = require('path');
- fs.readFile(path.join(__dirname, 'public', 'index.html'), (err, data) => {
- const htmlStr = data.toString();
- const resultStr = htmlStr.replace(/[\r\n]/g, '');
- fs.writeFile(path.join(__dirname, 'dist', 'index.html'), resultStr, err => {
- if (err) console.log(err);
- else console.log('HTML压缩成功!');
- });
- });
复制代码
### http 模块:搭建简易 Web 服务
使用内置 `http` 模块创建服务器,监听端口并返回响应。
- const http = require('http');
- const server = http.createServer();
- server.on('request', (req, res) => {
- res.setHeader('Content-Type', 'text/plain;charset=utf-8');
- res.end('欢迎使用 Node.js 创建的 Web 服务');
- });
- server.listen(3000, () => {
- console.log('Web 服务已在 http://localhost:3000 启动');
- });
复制代码
根据请求路径返回不同文件(如 HTML):
- server.on('request', (req, res) => {
- if (req.url === '/index.html') {
- fs.readFile(path.join(__dirname, 'dist/index.html'), (err, data) => {
- res.setHeader('Content-Type', 'text/html;charset=utf-8');
- res.end(data.toString());
- });
- } else {
- res.setHeader('Content-Type', 'text/html;charset=utf-8');
- res.end('404 页面不存在');
- }
- });
复制代码
## 2. 模块化开发:CommonJS 与 ES Modules
Node.js 中每个 `.js` 文件都是一个独立模块,变量作用域隔离。模块化带来代码复用、按需加载、便于协作。
### CommonJS 标准(Node.js 默认)
导出使用 `module.exports`,导入使用 `require()`。
- // utils.js
- const baseUrl = 'http://api.example.com';
- const sumArray = arr => arr.reduce((s, v) => s + v, 0);
- module.exports = {
- url: baseUrl,
- sum: sumArray
- };
- // index.js
- const utils = require('./utils.js');
- console.log(utils.url); // http://api.example.com
- console.log(utils.sum([1,2,3])); // 6
复制代码
内置模块直接写名字(如 `require('fs')`),自定义模块写路径(如 `require('./utils.js')`)。
### ES Modules(ECMAScript 标准)
在 `package.json` 中设置 `"type": "module"` 即可启用 ESM 语法。
**默认导出/导入**:- // utils.js
- const baseUrl = 'http://api.example.com';
- export default { url: baseUrl };
- // index.js
- import utils from './utils.js';
- console.log(utils.url);
复制代码
**命名导出/导入**(按需加载):- // utils.js
- export const baseUrl = 'http://api.example.com';
- export const sumArray = arr => arr.reduce((s, v) => s + v, 0);
- // index.js
- import { baseUrl, sumArray } from './utils.js';
- console.log(baseUrl, sumArray([1,2,3]));
复制代码
选择策略:全部加载用默认导出,按需加载用命名导出。
## 3. npm 包管理
包(Package)是包含 `package.json` 的文件夹,分为项目包和软件包。`package.json` 记录名称、版本、入口文件(`main` 字段)。
常用命令:
- `npm init -y`:快速生成 `package.json`
- `npm i <包名>`:安装本地依赖,记录到 `dependencies`
- `npm i <包名> -g`:全局安装(如 `nodemon`)
- `npm i`:根据 `package.json` 安装所有依赖
**nodemon 全局包**:监听文件变化自动重启应用,替代 `node` 命令。使用 `nodemon app.js` 启动。
## 4. Webpack 模块打包工具
Webpack 从入口出发构建依赖图,将 JS、CSS、图片等打包成静态资源。核心能力:转译、压缩、整合。
### 基础使用
初始化项目并安装:- npm init -y
- npm i webpack webpack-cli --save-dev
复制代码
在 `package.json` 的 `scripts` 中添加命令:- "scripts": {
- "build": "webpack"
- }
复制代码
运行 `npm run build`,默认入口为 `src/index.js`,输出到 `dist/main.js`。
### 核心配置文件 webpack.config.js
通过配置文件自定义打包行为。
- const path = require('path');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- module.exports = {
- // 打包模式:development 或 production
- mode: 'development',
- // 入口
- entry: path.resolve(__dirname, 'src/login/index.js'),
- // 出口
- output: {
- path: path.resolve(__dirname, 'dist'),
- filename: './login/index.js'
- },
- // 插件
- plugins: [
- new HtmlWebpackPlugin({
- template: './public/login.html',
- filename: './login/index.html'
- })
- ],
- // 加载器
- module: {
- rules: [
- {
- test: /\.css$/i,
- use: ['style-loader', 'css-loader'] // 从右向左执行
- },
- {
- test: /\.less$/i,
- use: ['style-loader', 'css-loader', 'less-loader']
- },
- {
- test: /\.(png|jpg|jpeg|gif)$/i,
- type: 'asset',
- generator: {
- filename: 'assets/[hash][ext]'
- }
- }
- ]
- },
- // 路径别名
- resolve: {
- alias: {
- '@': path.resolve(__dirname, 'src')
- }
- },
- // 开发服务器
- devServer: {
- port: 8080,
- open: true,
- hot: true
- }
- };
复制代码
常用加载器说明:
- `css-loader`:解析 `@import` 和 `url()`
- `style-loader`:将 CSS 插入 DOM 的 `<style>` 标签
- `less-loader`:将 Less 编译为 CSS
安装命令:- npm i html-webpack-plugin css-loader style-loader less less-loader mini-css-extract-plugin css-minimizer-webpack-plugin --save-dev
复制代码
### 常用优化配置
- **提取 CSS 为独立文件**:用 `mini-css-extract-plugin` 替代 `style-loader`,利于浏览器缓存
- **压缩 CSS**:使用 `css-minimizer-webpack-plugin`
- **Source Map**:设置 `devtool: 'inline-source-map'` 精确定位源码错误
- **CDN 排除**:通过 `externals` 配置将某些库排除打包,在 HTML 中引入 CDN 链接
- **代码分割**:在 `optimization.splitChunks` 中配置公共代码提取
### 打包模式与环境变量
`mode` 决定内置优化:`development` 启用调试和热更新,`production` 自动压缩。命令行可覆盖:`webpack --mode=production`。
通过 `cross-env` 注入环境变量:- npm i cross-env --save-dev
复制代码
修改 `package.json`:- "scripts": {
- "build": "cross-env NODE_ENV=production webpack",
- "dev": "cross-env NODE_ENV=development webpack serve"
- }
复制代码
在 `webpack.config.js` 中通过 `process.env.NODE_ENV` 判断环境,用 `DefinePlugin` 将变量注入前端代码。
多页面打包只需配置多个 `entry` 和对应的 `HtmlWebpackPlugin` 实例。
## 总结
从 Node.js 文件操作、路径安全,到模块化标准、npm 包管理,再到 Webpack 全配置,本文覆盖了从前端工程化入门所需的核心知识点。掌握这些,你就能自主搭建项目构建流程,实现模块化开发和优化。 |