从零开始的web前端学习-Node
Node.js 使开发者可以搭建服务器端的 JavaScript 应用程序,即编写数据接口、提供网页资源浏览等功能实现,为前端工程化做铺垫
Node.js 基于浏览器引擎进行封装,支持 ECMAScript 标准语法的同时拥有独立的 API,但 Node.js 环境没有 DOM 和 BOM
前端工程化指开发项目直到上线,过程中集成的所有工具和技术
1fs模块
fs 模块封装与本机文件系统进行交互的方法和属性
const fs = require('fs') // 加载 fs 模块
fs.writeFile('.../test.txt', 'hello world', err => { // 向 test.txt 文件中写入 hello world
  if(err) console.log(err)
  else console.log('successfully wrote')
})
fs.readFile('.../test.txt', (err, data) => {
  if(err) console.log(err)
  else console.log(data.toString()) // data 是十六进制的 buffer 数据流对象
})
2path模块
Node.js 环境中应当使用绝对路径
__dirname 内置变量能够获取当前 JavaScript 文件目录的绝对路径
path.join() 会使用特定于平台的分隔符作为定界符,将所有路径片段连接成为绝对路径
const path = require('path')
path.join('__dirname', '相对路径')
3http模块
web 服务程序:用于提供网上信息浏览功能
const http = require('http')
const server = http.createServer()
server.on('request', (req, res) => {
  res.setHeader('Content-Type', 'text/plain;charset=utf-8') // 设置响应头,响应内容类型为普通文本,编码格式为 utf-8
  res.end('欢迎使用 web 服务') // 设置响应体内容,结束本次请求与响应
})
server.listen(3000, () => { // 分配端口号
  console.log('web 服务启动成功')
})
4Node.js模块化
Node.js 环境中,每个文件都被视为一个单独的模块
CommonJS 标准:模块导入或导出的语法标准
module.exports = { // 导出
  对外属性名: ...
}
require('模块名或路径') // 导入
注意:导入时,内置模块直接写模块名(fs、path、http),自定义模块写文件路径
ECMAScript 标准
export default { // 默认导出
  对外属性名: ...
}
import 变量名 from '模块名或路径' // 默认导入
export const baseURL = '...' // 命名导出
import baseURL from '模块名或路径' // 命名导入,baseURL 是与模块中变量同名的变量
注意:
Node.js 默认支持 CommonJS 标准语法,若需要使用 ECMAScript 标准语法,应在运行模块所在文件夹新建 package.json 文件,并设置 {"type": "module"}
对于 ECMAScript 标准,按需加载时使用命名导出和导入,全部加载时使用默认导出和导入,但 ES6 标准默认使用严格模式,所以可能会出现问题
5包
包就是将模块、代码以及其他资料聚合成一个文件夹
- 项目包:主要用于编写项目和业务逻辑
- 软件包:封装工具和方法进行使用
注意:根目录中,必须存在 package.json 文件,即记录包的清单信息
{
  "name": "cz_utils", // 软件包名称
  "version": "1.0.0", // 软件包当前版本
  "description": "常用工具", // 软件包简短描述
  "main": "index.js", // 软件包入口点,导入软件包时默认引入的模块文件,集成所有模块属性和方法
  "author": "Ha", // 软件包作者
  "license": "MIT" // 软件包许可证(商用后可用作者名字宣传)
}
6软件包管理器npm
npm 使用
- 初始化清单文件:npm init -y(终端),得到 package.json 文件
- 下载软件包:npm i 软件包名称(终端)
- 使用软件包:require('软件包名称')
若要删除软件包:npm uni 软件包名称(终端),添加 -g 则代表删除全局软件包
安装所有依赖:npm i,根据 package.json 文件下载所有依赖
全局软件包 nodemon
- 本地软件包:当前项目内使用,封装属性和方法,存在于 node_modules
- 全局软件包:本机所有项目使用,封装命令和工具,存在于系统设置的位置
nodemon 作用是替代 node 命令,检测代码更改,自动重启程序
nodemon 使用
- 安装:npm i nodemon -g,-g 代表安装至全局环境中
- 运行:nodemon XXX.js,类似于 node 命令行执行 JavaScript 文件
7Webpack
Webpack 是用于 JavaScript 应用程序的静态模块打包软件
静态模块指的是编写代码过程中的 html、css、JavaScript、图片等固定内容的文件
打包,即将静态模块内容进行压缩、整合、转译等
Webpack 使用
- 新建并初始化项目,编写业务源代码
- 下载 Webpack:npm i webpack webpack-cli --save-dev(--save-dev 即开发环境使用),下载至当前项目中(实现版本独立,互不影响),并配置局部自定义命令:"script": {"build": "webpack"}(package.json 文件)
- 运行打包命令:npm run build,自动产生 dist 分发文件夹,文件夹中存有压缩和优化后用于最终运行的代码
Webpack 修改入口和出口:./src/index.js(默认入口文件),./dist/main.js(默认出口文件)
- 项目根目录,新建 webpack.config.js 配置文件
- 导出配置对象,配置入口、出口文件的路径
- 重新打包观察
注意:只有和入口产生直接或间接的引入关系,才会被打包
const path = require('path')
module.exports = {
  entry: path.resolve(__dirname, 'src/login/index.js'), // 打包入口文件
  output: {
    path: path.resolve(__dirname, 'dist'), // 打包出口目录
    filename: './login/index.js', // 打包出口文件
    clean: true // 生成打包内容前,清空出口目录
  }
}
8Webpack生成html文件
- 下载 html-webpack-plugin 软件包:npm i html-webpack-plugin --save-dev
- 配置 webpack.config.js,让 Webpack 拥有插件功能
- 重新打包观察效果
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  ...
  plugins: [ // plugin 为插件属性
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '.../login.html') // 模板文件
      filename: path.resolve(__dirname, '.../index.html') // 输出文件
    })
  ]
}
9Webpack打包css代码
Webpack 默认仅能支持 JavaScript 代码,则需要引入加载器解析识别 css 代码
- css-loader:解析 css 代码
- style-loader:将解析后的 css 代码插入至 DOM
- 准备 css 文件代码加载到入口文件中
- 下载 css-loader 和 style-loader 本地软件包:npm i css-loader style-loader --save-dev
- 配置 webpack.config.js,让 Webpack 拥有加载器功能
- 重新打包观察效果
module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.css$/i, // 匹配以 css 结尾的文件,不区分大小写
        use: ['style-loader', 'css-loader'] // 逆序加载
      }
    ]
  }
}
注意:若使用第三方库,如 bootstrap,也需要在入口文件中进行加载,否则第三方库效果不会实现
优化-提取 css 代码
- 下载 mini-css-extract-plugin 本地软件包:npm i mini-css-extract-plugin --save-dev
- 配置 webpack.config.js,让 Webpack 拥有插件功能
- 重新打包观察效果
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'] // mini-css-extract-plugin 插件与 style-loader 加载器不兼容使用
      }
    ]
  },
  plugins: [
    ...
    new MiniCssExtractPlugin({
      filename: '.../index.css' // 相对路径,输出的 css 位置及文件
    })
  ]
}
优化-压缩过程
- 下载 css-minimizer-webpack-plugin 本地软件包:npm i css-minimizer-webpack-plugin --save-dev
- 配置 webpack.config.js,让 Webpack 拥有插件功能
- 重新打包观察效果
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'] // mini-css-extract-plugin 插件与 style-loader 加载器不兼容使用
      }
    ]
  },
  plugins: [
    ...
    new MiniCssExtractPlugin()
  ],
  optimization: {
    minimizer: [
      '...', // 保留 JavaScript 压缩
      new CssMinimizerPlugin()
    ]
  }
}
10Webpack打包less代码
less-loader:将 less 代码编译成 css 代码
- 准备 less 文件代码引入至入口文件中
- 下载 less 和 less-loader 本地软件包:npm i less less-loader --save-dev
- 配置 webpack.config.js,让 Webpack 拥有加载器功能
- 重新打包观察效果
module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.less$/i, // 匹配以 less 结尾的文件,不区分大小写
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
      }
    ]
  }
}
11Webpack打包图片
Webpack5 内置资源模块(字体、图片等)打包,无需额外加载器
- 配置webpack.config.js,让 Webpack 拥有资源模块(以图片打包为例)功能
- 重新打包观察效果
module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.{png|jpg|jpeg|gif}$/i, // 匹配图片文件,不区分大小写
        type: 'asset',
        generator: {
          filename: 'asset/[hash][ext][query]' // 输出目录由 output 参数设置
        }
      }
    ]
  }
}
注意:
type: 'asset' 以 8KB 为默认临界值,当文件大于 8KB 时,发送一个单独的文件并导出 URL 地址;若小于 8KB,则导入至 JavaScript 文件中并导出一个 data URL(base64 字符串)
占位符 [hash] 对模块内容进行算法计算,得到映射的数字字母组合的字符串
占位符 [ext] 使用当前模块原本的占位符,如 .png 等字符串
占位符 [query] 保留引入文件时代码中的查询参数(只有 URL 下生效)
JavaScript 中引入本地图片资源需要用 import 方式,若是网络图片 http 地址则字符串可以直接书写
import imgObj from '.../test.img'
const theImg = document.createElement('img')
theImg.src = imgObj // 若为网络图片则直接赋值,不用 import
12Webpack搭建开发环境
配置 webpack-dev-server 快速开发应用程序,能够启动 Web 服务,自动检测代码变化,热更新到网页
- 下载 webpack-dev-server 软件包到当前目录:npm i webpack-dev-server --save-dev
- 配置 webpack.config.js,设置模式为开发模式,并配置自定义命令:"scripts": {"dev": "webpack serve --open"}(package.json 文件),--open 指自动打开默认浏览器
- 启动开发服务器,查看热更新效果:npm run dev
module.exports = {
  ...
  mode: 'development' // 打包-development 模式,使用相关内置优化
}
注意:
dist 目录和打包内容是在内存里
webpack-dev-server 借助 http 模块创建 8080 默认 Web 服务,并且默认以 public 文件夹作为服务器根目录,webpack-dev-server 还会根据配置,打包相关代码在内存当中,以 output.path 作为服务器根目录(可以手动输入路径访问 dist 目录内容)
若需要以另一页面为默认服务网址,可以在 public 文件夹下创建 index.html 文件实现自动跳转
打包模式:告知 Webpack 使用相应模式的内置优化
| 模式名称 | 模式名字 | 特点 | 场景 | 
|---|---|---|---|
| 开发模式 | development | 调试代码,实时加载、模块热替换等 | 本地开发 | 
| 生产模式 | production | 压缩代码,资源优化、轻量化等 | 打包上线 | 
设置打包模式:
- 配置文件:在 webpack.config.js 配置文件中设置 mode 选项
- 命令行:在 package.json 命令行设置 mode 参数,命令行优先级高于配置文件
 "scripts": {"build": "webpack --mode=production", "dev": "webpack serve --open --mode=development"}
应用:开发模式下用 style-loader 内嵌 css 更高效,在生产模式下提取 css 代码
webpack.config.js 配置导出函数(局限性在于仅接受两种生产模式)
借助 cross-env 软件包命令,设置参数区分环境
- 下载 cross-env 软件包到当前项目:npm i cross-env --save-dev
- 配置自定义命令,传入参数名和值(会绑定到 process.env 对象下):"scripts": {"build": "cross-env NODE_ENV=production webpack --mode=production", "dev": "cross-env NODE_ENV=development webpack server --open --mode=development"}
- 在 webpack.config.js 中区分不同环境使用不同配置
- 重新打包观察效果
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader']
      },
      {
        test: /\.less$/i, // 匹配以 less 结尾的文件,不区分大小写
        use: [process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
      }
    ]
  }
}
配置不同的 webpack.config.js 文件(适用于多种模式差异较大情况)
13前端-注入环境变量
cross-env 设置的环境变量只在 Node.js 环境中生效,前端代码无法访问 pross.env.NODE_ENV,可以使用 Webpack 内置的 DefinePlugin 插件解决,插件能够在编译时将前端代码中匹配的变量名替换为值或表达式
const webpack = require('webpack')
module.exports = {
  ...
  plugins: [
    ...
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) // 转换
    })
  ]
}
14Webpack调错
代码被压缩混淆,无法确定源代码位置,而 source map 可以准确追踪 error 和 warning 在原始代码中的位置,需要在 webpack.config.js 文件中配置 devtool 选项
module.exports = {
  ...
  devtool: 'inline-source-map' // 将源码的位置信息一起打包在 JavaScript 文件内
}
注意:source map 仅适用于开发环境,不要在生产环境中使用,防止被轻易查看源码位置
const config = {...} // 原 module.exports 导出内容
if (process.env.NODE_ENV === 'development') { // 仅开发环境使用
  config.devtool = 'inline-source-map'
}
module.exports = config
15Webpack解析别名
解析、创建 import 引入路径的别名,确保模块引入更加简洁,Webpack 中常在 webpack.config.js 文件中配置解析别名 @ 代表 src 绝对路径
const config = {
  ...
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }  
  }
}
16Webpack优化-CDN技术
CDN,即内容分发网络,指一组分布在各个地区的服务器,能够将静态资源文件或者第三方库放在 CDN 网络中的各个服务器中,供用户就近请求获取
开发模式使用本地第三方库,生产模式下使用 CDN 加载引入
- 在模板 html 中引入第三方库的 CDN 地址并用模板语法判断
<% if (htmlWebpackPlugin.options.useCdn) { %>
  <link href='CDN 资源地址' ...>
<% } %>
- 配置 webpack.config.js 中 externals 外部扩展选项(防止某些 import 的包被打包)
if (process.env.NODE_ENV === 'production') { // 生产模式使用
  config.externals = {
    key: value
  }
}
const config = {
  ...
  plugins = [
    new HtmlWebpackPlugin({
      useCdn: process.env.NODE_ENV === 'production'
    })
  ]
}
注意:
config.externals 中的 key 指代码中 import from 后面的模块表示字符串,value 指替换在原地的变量名(要和 CDN 中暴露在全局的变量一致),简单理解 key 指 from 后面的字符串,value 指 import 前面的字符串,特例不适用
17Webpack多页面打包
单页面:单个 html 文件,以切换 DOM 的方式实现不同业务逻辑展示
多页面:多个 html 文件,以切换页面实现不同业务逻辑展示
- 准备源码(html、css、JavaScript)放入相应位置,并用模块化语法导出
- 下载 form-serialize 包并导入到核心代码中使用
- 配置 webpack.config.js 多入口和多页面的设置
const config = {
  ...
  entry: {
    '模块名1': path.resolve(__dirname, 'src/入口1.js')
    '模块名2': path.resolve(__dirname, 'src/入口2.js')
  },
  output: {
    path: path.resolve(__dirname, 'dist')
    filename: './[name]/index.js'
  },
  plugins: [
    ...
    new HtmlWebpackPlugin({
      template: './public/页面1.html', // 模板文件
      filename: './路径1/index.html', // 输出文件
      useCdn: process.env.NODE_ENV === 'production',
      chunks: ['模块名1']
    }),
    new HtmlWebpackPlugin({
      template: './public/页面2.html' // 模板文件
      filename: './路径2/index.html' // 输出文件
      useCdn: process.env.NODE_ENV === 'production'
      chunks: ['模块名2']
    }),
    new MiniCssExtractPlugin({ // 压缩 CSS
      filename: './[name]/index.css'
    })
  ]
}
优化-分割公共代码:将 2 个以上页面引用的公式代码提取
配置 webpack.config.js 的 splitChunks 分割功能
const config = {
  optimization: {
    splitChunks: { 
      chunks: 'all', // 所有模块都进行分割
      cacheGroups: { // 分隔组
        commons: { // 抽取公共模块
          minSize: 0, // 抽取的 chunk 最小字节大小
          minChunks: 2, // 最小引用数
          reuseExistingChunk: true, // 当前 chunk 包含已从主 bundle 中拆分的模块,则它将被重用
          name(module, chunks, cacheGroupKey) { // 分离出模块文件名
            const allChunksNames = chunks..map((items => item.name).join('~')) // 模块名1~模块名2
            return './js/${allChunksNames}' // 输出至 dist 目录下位置
          }
        }
      }
    }
  }
}
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号