webpack深入浅出系列

ES6模块与CommonJS模块的主要区别

加载时机ES6模块编译时输出,即模块在编译阶段就已经确定了依赖关系;而CommonJS模块运行时才加载,即运行到某个require语句时才加载对应的模块。
(也就是说,es6的模块化是在编写程序的时候就开始有优化校验和静态分析,而commonjs只有在程序运行的时候再找所谓的对应关系)

语法差异:ES6模块使用exportimport进行模块的导出和导入;而CommonJS模块使用module.exportsexports导出,使用require导入。

设计哲学:ES6模块更注重静态分析和代码优化,而CommonJS模块更多考虑了运行时的行为。
es6模块导入需要完整的文件名后缀以及在script标签中写入type=module,而CommonJS模块又不需要等等。更是由于前端开发中存在多种模块化标准(如 ES6 模块、CommonJS、AMD 等)以及不同类型的资源(如 JavaScript、CSS、图片等),Webpack工具 就通过自己的方式来统一管理这些模块和资源。

webpack基本概念

Webpack 是一个静态资源打包工具。

  1. 它会以一个或多个文件作为打包的入口,将我们整个项目所有文件编译组合成一个或多个文件输出出去。
  2. 输出的文件就是编译好的文件,就可以在浏览器引入运行了。
  3. 我们将 Webpack 输出的文件叫做 bundle(打包)。

在前端开发中,Bundle 是指通过打包工具(如 Webpack、Vite、Rollup 等)将项目的多个模块和资源文件(如 JavaScript、CSS、图片等)整合为一个或多个打包文件,以便在浏览器中更高效地加载和执行。
Bundle 的目的是优化代码的加载和执行,避免重复请求和依赖的冗余加载。通常,打包工具会根据依赖关系将模块整合在一起,进行以下几种优化处理:

  1. 合并文件:将分散的文件合并为一个或多个较少的文件,减少浏览器请求次数。
  2. 压缩代码:去除空格、注释,短化变量名,减少文件体积。
  3. 代码拆分(Code Splitting):根据页面访问情况,将代码拆分成多个 Bundle 文件,按需加载,提高首屏加载速度。
  4. Tree Shaking:移除未使用的代码,减少打包文件大小。
  5. 缓存优化:通过生成带有哈希值的文件名,确保修改后的文件在浏览器中被正确更新缓存。

示例

假设项目中有多个模块文件,如 index.jsstyle.cssutils.js 等。通过 Webpack 配置打包后,它们会被打包成一个或多个 Bundle 文件,比如 main.bundle.jsvendor.bundle.js 等,这些文件将被插入到 HTML 中。

为什么 Bundle 重要?

  • 提升加载效率:通过压缩和合并,减少网络请求数量。
  • 提高代码复用性:共享库或通用功能可以打包到单独的文件中,多个页面共享使用。
  • 便于代码维护:打包工具会自动管理模块依赖,避免手动控制加载顺序或依赖冲突。
    打包(Bundle)可以说是现代前端项目优化和模块管理的核心步骤,尤其在大型应用中表现尤为显著。

Webpack 本身功能是有限的:
只有两种模式以及多种配置
开发模式:仅能编译 JS 中的 ES Module 语法
生产模式:能编译 JS 中的 ES Module 语法,还能压缩优化JS 代码
Webpack 本身功能比较少,只能处理 js 资源,一旦遇到 css 等其他资源就会报错。
所以我们学习 Webpack,就是主要学习如何处理其他资源。

5 大核心概念

  • entry(入口)

    指示 Webpack 从哪个文件开始打包

  • output(输出)

    指示 Webpack 打包完的文件输出到哪里去,如何命名等

  • loader(加载器)

    webpack 本身只能处理 js、json 等资源,其他资源需要借助 loader,Webpack 才能解析

  • plugins(插件)

    扩展 Webpack 的功能

  • mode(模式)主要由两种模式:

    开发模式:development
    生产模式:production

Webpack 配置文件

在项目根目录下新建文件:webpack.config.js

module.exports = {
  // 入口
  entry: "",
  // 输出
  output: {},
  // 加载器
  module: {
    rules: [],
  },
  // 插件
  plugins: [],
  // 模式
  mode: "",
};

Webpack 是基于 Node.js 运行的,所以采用 Common.js 模块化规范

修改配置文件部分示例

// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
  // 入口
  // 相对路径和绝对路径都行
  entry: "./src/main.js",
  // 输出
  output: {
    // path: 文件输出目录,必须是绝对路径
    // path.resolve()方法返回一个绝对路径
    // __dirname 当前文件的文件夹绝对路径
    path: path.resolve(__dirname, "dist"),
    // filename: 输出文件名
    filename: "main.js",
  },
  // 加载器
  module: {
    rules: [],
  },
  // 插件
  plugins: [],
  // 模式
  mode: "development", // 开发模式
};

此时不能处理样式等资源
Webpack 能力都通过 webpack.config.js 文件进行配置,来增强 Webpack 的功能。
Webpack 是一种现代 JavaScript 应用的打包工具,通过将代码及其依赖项打包成静态文件,方便在浏览器中加载和运行。以下是 Webpack 的一些核心概念:

1. Entry(入口)

  • 作用:Webpack 开始构建的起点,定义依赖关系图的根文件。
  • 配置:指定入口文件的路径,通常是应用的主文件,比如 index.js
  • 多入口:支持多入口配置,用于生成多个 Bundle 文件,适合多页面应用。
  • 例子
    module.exports = {
      entry: './src/index.js', // 单入口
      // 或者多入口
      entry: {
        app: './src/app.js',
        admin: './src/admin.js'
      }
    };
    

2. Output(输出)

  • 作用:定义 Webpack 如何命名、生成打包后的文件及输出路径。
  • 主要参数
    • path:打包文件的输出路径。
    • filename:打包后文件的名称。
  • 例子
    module.exports = {
      output: {
        path: __dirname + '/dist',
        filename: '[name].bundle.js' // [name] 用于多入口生成不同文件名
      }
    };
    

3. Loaders(加载器)

  • 作用:处理非 JavaScript 文件,如 CSS、图片、字体等,将它们转换为 Webpack 能够理解的模块。
  • 常用 Loaders
    • babel-loader:将 ES6+ 转译成 ES5。
    • css-loader:负责将 Css 文件编译成 Webpack 能识别的模块,从而允许 JavaScript 中 import CSS 文件。
    • style-loader:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容。也就是把 CSS 注入到 DOM 中。此时样式就会以 Style 标签的形式在页面上生效。
    • file-loader:处理文件资源,返回文件 URL。
  • 例子
    module.exports = {
      module: {
        rules: [
          { test: /\.js$/, use: 'babel-loader' },
           // 用来匹配 .css 结尾的文件 
           // use 数组里面 Loader 执行顺序是从右到左
          { test: /\.css$/, use: ['style-loader', 'css-loader'] }
        ]
      }
    };
    

4. Plugins(插件)

  • 作用:执行范围更广的任务,如优化、压缩、资源管理等。
  • 常用 Plugins
    • HtmlWebpackPlugin:生成 HTML 文件并自动注入打包后的资源。
    • DefinePlugin:在编译时创建全局常量。
    • MiniCssExtractPlugin:将 CSS 提取到单独文件。
  • 例子
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
      plugins: [
        new HtmlWebpackPlugin({ template: './src/index.html' })
      ]
    };
    

5. Mode(模式)

  • 作用:定义打包的模式,有 development(开发)和 production(生产)两种模式。
  • 影响
    • development 模式:启用代码映射和调试,未压缩的输出。
    • production 模式:启用优化、Tree Shaking、代码压缩等。
  • 例子
    module.exports = {
      mode: 'development' // 或 'production'
    };
    

6. Chunk(代码块)

  • 作用:Webpack 根据模块之间的依赖关系生成的代码块。通常将主代码和第三方依赖(如 node_modules)打包成不同的 Chunk,以实现更高的缓存和按需加载。
  • 配置:通过 optimization.splitChunks 来拆分代码块。

7. Module(模块)

  • 作用:模块是应用的独立单元,Webpack 会递归解析入口文件所依赖的模块,形成依赖关系图。
  • 支持的模块类型:ES6 模块、CommonJS、AMD 模块等。

8. Dependency Graph(依赖图)

  • 作用:Webpack 会从入口文件出发递归构建所有模块的依赖关系图,确保所有依赖项都被打包在最终的输出文件中。

9. Tree Shaking

  • 作用:移除未使用的代码,减少打包后的文件体积。
  • 启用条件:需要使用 ES6 模块语法(import / export),并且在 production 模式下默认启用。

Webpack 的这些概念帮助开发者灵活地控制模块化、打包、优化等过程,在开发和生产环境中构建高效的前端应用。

开发模式介绍

开发模式顾名思义就是我们开发代码时使用的模式。
这个模式下我们主要做两件事:

  1. 编译代码,使浏览器能识别运行:
    开发时我们有样式资源、字体图标、图片资源、html 资源等,webpack 默认都不能处理这些资源,所以我们要加载配置来编译这些资源
  2. 代码质量检查,树立代码规范
    提前检查代码的一些隐患,让代码运行时能更加健壮。

提前检查代码规范和格式,统一团队编码风格,让代码更优雅美观。


其实模块化在前端程序设计中有很多的体现的地方
前端模块化是指将代码分解成独立、可复用的模块,以便于维护、扩展和复用。随着项目复杂度的增加,模块化显得尤为重要。前端的模块化可以分为以下几类:

1. 文件模块化

  • 传统的文件划分:根据功能将文件划分成不同文件夹,例如 componentsutilsservices 等,这种方式在项目初期非常普遍。
  • 按页面/功能划分:把每个页面作为一个模块,如 userPage.jsadminPage.js。在大型项目中,通常按功能划分多个目录层次,提升代码结构的清晰度。

2. 模块化方案

  • ES6 模块 (ESM):使用 importexport,这是目前最主流的模块化标准,得到了浏览器和 Node.js 的支持。
  • CommonJS:通过 requiremodule.exports 实现的模块化方案,主要用于 Node.js 后端开发。
  • AMD (Asynchronous Module Definition):通过 definerequire 来定义模块,适合于浏览器端的异步模块加载,经典库有 RequireJS
  • UMD (Universal Module Definition):兼容 AMD、CommonJS 和全局变量方式,适用于一些跨平台的库。

3. 组件化框架的模块化

  • React:基于组件的开发模型,每个组件就是一个独立的模块。使用 HooksContext 等可以在组件之间共享状态和逻辑。
  • Vue:通过 SFC (单文件组件) 将 HTML、CSS、JavaScript 集成在一个文件中,每个 .vue 文件就是一个模块。
  • Angular:采用模块化的结构,通过 NgModules 来组织代码。每个 NgModule 是一组组件、指令、服务的集合。

4. CSS 模块化

  • CSS Modules:生成局部作用域的 CSS,避免全局样式污染。
  • 预处理器 (如 SASS/SCSS):提供嵌套、变量、混入等功能,让 CSS 更具模块化能力。
  • CSS-in-JS:将 CSS 写在 JavaScript 中,如 styled-componentsEmotion,适用于 React 等框架,可以将样式与逻辑模块化结合。

5. 打包工具的模块化

  • Webpack:通过 entryoutputmodule 等配置实现模块化打包。loadersplugins 使得资源可以模块化地加载和处理。
  • Vite:基于 ESM 的打包工具,启动速度快,适合现代化前端项目。
  • Rollup:专注于打包库文件,生成更小的文件体积,非常适合编写 npm 库时使用。

6. 路由模块化

  • 动态路由加载:根据用户访问的路由按需加载对应模块,可以减少初次加载时间。
  • 嵌套路由:将不同的页面划分为嵌套路由结构,方便分层控制页面和组件,常见于 Vue RouterReact Router

7. 状态管理模块化

  • Redux:把状态拆分为不同的 slice,每个模块的状态独立,便于管理和维护。
  • Vuex:将状态存储到各个模块中,并提供 gettersmutationsactions,适合 Vue 项目。
  • Context API / Zustand:对 React 项目来说,可以通过 Context API 创建共享的状态模块;Zustand 提供更轻量的解决方案。

8. API 层的模块化

  • 接口封装:将每个功能的接口封装成独立模块,如 userAPI.jsproductAPI.js,便于调用和统一管理。
  • 服务层 (Service):将所有与后端的交互逻辑集中在一个服务层中,和具体的业务模块解耦。

模块化在现代前端开发中不可或缺,通过合理的模块划分和使用,可以显著提升项目的可维护性和扩展性。


点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部