前端模块化开发实验(一)——模块概念以及webpack基础配置

现在web 应用前后端分离,前端独立成一个专业,并且还工程化了,这个事实对于 经历过早期Web1.0和2.0的开发者而言,刚接触时应该是比较新奇的。

应用软件网络化,web services 成为不可阻挡的 软件应用的风潮。作为一名技术开发者,一名经历过早期web开发的人,我最感兴趣是 前端工程化的概念——什么东西被工程组件化了。

前端工程模块化的发展

有过早期经验有开发者应该知道,一支web应用 都是由多页组成的,页面在后端“渲染”生成;每个页面的交互功能都由自己js实现,当页面交互功能比较多时,都会让开发者在维护上的头痛。

当页面交互功能需求增长时,业界第一反应不是工程化技术,而是结构化和动态化技术。动态化是AJAX和Jquery的流行,结构化是第一代的MVC框架的出现,例如Backbone, Angular1。

前端MVC框架的出现应该是前端工程化的肇始,但它不成熟,尤其是第一代的。我个人为像webpack这样 module bundle工具出现才是 前端工程化 的真正的到来。为什么这么说,因为webpack 等 module bundle工具引入工程最需要“web模块”的概念。

工程化最主要技术基础,是分立制作的 工程构件,每种构件有自己的 独特的专业和特性。这话什么意思?意思是真正工程化是,我们可以独立制作不同功能的构件,然后根据需求像 拼积木那样 搭建想要的复杂功能。

web前端工程化最大的困难是,它 (web app)可怎么被分割为不同逻辑功能构件。有 webpack 使用经验的人都知道,不但js模块可以import,连css , 图片,字体都可以 import,这就是现在发展的 成果。但是在 webpack出现之前,只有 js 能被模块化,而且存在多种技术(commonjs, requirejs, AMD)。

前端模块化的基础原理

要对 web前端 工程化,第一 要件是清晰掌握 web app的本质形式,和它的可能逻辑构成;第二,是在第一个条件之上找 到一种技术实现,包括1)构件的表达,2)构件复合的机制,例如 webpack 处理 css 样式 就是一种工程化技术例子;而 MVC,MVVM是web app逻辑构成 比较流行的努力。

工程化成熟利好表现是,我们可以使用标准工程构件 分析、分解、设计和开发 我们的需求。在过去,web app 以页面为单位进行分析,设计和开发的,那是一种直观的未成熟的结构化开发。现在,有了webpack ,我们可以使用“web模块”进行工程化建构。

本系列文将以一个简单的例子,演示一下目前 前端工程化的样子——以webpack为例子,演示不同 web模块种类,及它们的复合原理,并且定制一个相对应的webpack配置。

我们选择一支简单但比较全面的web app 前端实现,演示可能的逻辑构件,和构件复合原理。

web 模块

在开始 1)分析需求和2)配置webpack之前,我们必须理解 何为 「标准工程构件模块」,以及有什么样的种类。

作为一种运行在web浏览器上的应用程序,主要有以下几种构件模块:

  • 第一,与用户交互和与DOM有关联的 构件模块,可定名为 V 模块
  • 第二,样式模块,因为样式有自己的复杂性,可独立专业制作;
  • 第三,包括 图片,字体等的 资源模块;资源可理解为 JS程序 特别的外部程序数据,通过url连接;
  • 第四,还有一种 和以上三种都不同的 通用模块
  • 第五,React ,Vue 的模块,此模块 本文暂不处理;
  • 第六,还有一个特别的模块,就是 index模块

对这些模块类型需要补充几点:

  • 第一,除了index模块,所有模块都是由 webpack loader处理,并“打包”入 bundle的;
  • 第二,index模块 负责加载 bundle(通过scripte标签),包括外链的css ;
  • 第三,这里的“模块”是 web 逻辑的,与 JS的语言程序模块不同,JS模块可理解为物理模块;
  • 第四,样式和资源模块没有独立意义,它们都是为构建V 模块准备的;

一支 web app逻辑构成 标准是,它至少有一个index模块,一个或以上的V模块;V模块可选的由一个或以上的 样式和资源模块组成。

Welcome world应用

为了保证例子的基础 且全面 演示 一支 web 前端应用,我选择了一个 特别的Welcome world应用(相对于传统hello world)。功能非常简单,主页面有一个输入框,提示输入名字,点击后 显示欢迎语:XXX ,欢迎来到前端世界(Welcome to Web world)。

结构上,它由一个index 模块,两个 V模块(一个layout和一个主体内容),V模块会有一些样式,和图片。

为了支持这些 三种模块类 型的开发,我们必须配置webpack的 index插件,babel , css , asset loader。开始动手吧。

webpack 和 index模块

webpack 的工作 就是将 所有具有依赖关系的“web模块”打包成一个 bundle.js文件,然而 .js 自己并不会运行,在浏览器上要依赖一个页面执行它,这就是index.html。

index.html可直接在发布目录上手动创建,但是,更多理由表明,和bundle.js并行的 index 也应该要由 “源文件” 动态编译 ,和打包发布。「源文件」这个概念要特别解释一下,位于 src目录 的所有数据 都是 web模块 的「 源文件」,它不能直在浏览器上运行,必须进行“编译”和打包。

webpack 安装配置


$ mkdir modular-web-frontend-webpack-js && cd modular-web-frontend-webpack-js
$ npm init -y
$ npm i -D webpack webpack-cli
webpack.config.js

const path = require('path')

module.exports = {
  entry: {
    main: path.resolve(\_\_dirname, './src/index.js'),
  },
  output: {
    path: path.resolve(\_\_dirname, './dist'),
    filename: '\[name\].bundle.js',
  },
}

package.json

"scripts": {
    "build": "webpack --mode development"
}

index插件及和index模块

由于 index.html 在 bundle.js之外,故不由loader处理,由plugin处理(html-webpack-plugin)。

安装index 插件并配置webpack,创建src源文件目录,并在 src目录内创建 index 模块的”源文件“ —— index.template.html。

$ npm i -D html-webpack-plugin

webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  /* ... */

  plugins: [    
  new HtmlWebpackPlugin({      
    title: 'Hello Web world!!',      
    template: path.resolve(__dirname, './src/index.template.html'), 
    filename: 'index.html', 
   }),  
],}

src/index.template.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>

  <body>
    <div id="root"></div>
  </body>
</html>

bundle入口 index.js

index 模块 负责加载 bundle.js,所以 bundle.js可以 看成是 index模块 的子模块。而我们常常也将 bundle的入口模块也定名为index,这会引起困惑,不过也证明了它们之间有逻辑上的关系。这关系就是:

  1. index.html是由index插件生成的,boundle.js(index.js入口)由于loader生成的;
  2. index.template.html才对应index.js,同属于源文件模块;
  3. 与其他V有独立的DOM节点不同,index.js只负责访问index.html的根节点,并且只它(作为bundle一部分)访问

index.js主要任务,加载程序入口模块(下面的app.js),和挂接到index.html的根节点上:

import Greeting from './app.js'

// Append Greeting node to the DOM
const approot = document.querySelector('#root')
approot.append(Greeting)

程序入口 app.js和第一个V模块

这个模块是 整个程序的起点。此模块现在是访问DOM的,是一个简单的V模块,因为只是演示。实际项目中,这个模块会比较复杂,一般都不是V模块,而是为 更复杂V模块准备条件的特殊模块。

src/app.js

// Create Greeting node
const Greeting = document.createElement('h1');
Greeting.textContent = 'Hello Web World!'

export default Greeting;

webpack dev server

到此我们可以进行 编译、打包和测试了,打包好的数据会在发布目录dist上。为了完整,我们还要安装开发服务器(webpack-dev-server),不必每次修改都完整的打包、发布和测试。另外,还要安装清理插件(clean-webpack-plugin)。

npm i -D webpack-dev-server

webpack.config.js配置

const webpack = require('webpack')

module.exports =  {
  /* ... */
  mode: 'development',
  devServer: {
    historyApiFallback: true,
    static: path.resolve(__dirname, './dist'),
    open: true,
    compress: true,
    hot: true,
    port: 8080,
  },

  plugins: [
    /* ... */
    // Only update what has changed on hot reload
    new webpack.HotModuleReplacementPlugin(),
  ],
})

package.json

"scripts": {
  "start": "webpack serve"
}

Clean webpack plugin

npm install clean-webpack-plugin --save-dev

webpack.config .js

...
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
  /* ... */

  plugins: [
    /* ... */
    new CleanWebpackPlugin(),  ],
}

Github源码

这里(https://github.com/nakeman/modular-web-frontend-webpack-js),在tag v0.1上。

裸男
Nakeman.cn 2023 Build by Gatsby and Tailwind, Deploy on Netlify.