用Webpack构建简单前端项目(修订版)

这篇文章是一年前写的,当时还用着Webpack1.x,而如今Webpack已经是3.x版本了,如果放着不更新难免会误人子弟。感谢一些网友的正面反馈,最近总算也抽出点时间来更新该文章。

0. 说点废话

从文章最初发布到如今已经整整过去一年了,这一年里面好事没做多少,坏事倒是做了一大堆(包括问候一些产品经理)。在这一年里我接触过前后端分离项目,也接触过一些基于Ruby On Rails的全栈式项目。然而这一年来我却并没有掌握多少流行的前端框架,唯一能够确定的是

  1. 写页面的时候能够有意识地用上HTML5的标签。
  2. 熟悉基本的CSS,能够根据设计图,写出酷炫(或者不酷炫)的页面。
  3. 对JavaScript的了解更为深入(不只是停留在Hello World的层面)。
三剑客

或许我还不能算是一只合格的前端狗,我没有熟练任何框架(如果JQuery也算的话),也没有精力去折腾各种各样的框架,我只想安安静静写样式以及交互罢了。

1. 前言

今天的主题是Webpack,我似乎有点跑题了。关于如何用Webpack去搭建前端项目,Webpack官方文档已经有较为详细的说明,我们只需要自己着跟着文档搭建,掌握了套路之后便可根据自己的需求去搜索相关的插件来使用。

我这个Webpack脚手架并不是什么最佳实践,它只是我能想到的最简单的实践,平时可以用来开发静态页面。如果只是用来开发静态页面那我觉得它应该具有如下功能

  1. 简单易懂的目录结构。
  2. 能够自动编译Sass,CoffeeScript等静态资源文件。
  3. 修改HTML,CSS,JavaScript之后能够动态刷新页面,不需要手动进行刷新。

下面我们逐步来实现这些功能,或者你可以直接从Github(这个不是master分支)上获取相关代码。

2. Webpack构建简单的前端脚手架

从零开始搭建Webpack服务没有比官方文档更详细的了,我这里就顺着文档简单讲讲构建流程。

1) 初始化项目,安装Webpack

mkdir static-page && cd static-page  # 创建并移动到项目目录
npm init -y  # 生成项目信息,并把信息存放到 package.json文件中
npm install --save-dev webpack # 安装webpack,由于只在开发环境下会用到,这里用了`--save-dev`标识

完成之后我们目录下会有这些文件

> ls
node_modules package.json
  1. node_modules 用来存放我们通过npm命令安装的软件。
  2. package.json 文件记录该项目的元信息,以及一些依赖包信息。

2) 创建页面文件,以及js入口文件

创建一个index.html文件用于存放我们的页面内容,我把它放在dist/目录里面,以及一个名为index.js的webpack入口文件,我把它放在src/目录下面。

目录结构大概如下

├── dist
│   └── index.html
├── node_modules
├── package.json
└── src
    └── index.js

PS: 所谓入口文件就是从这个文件中引入的资源都会被Webpack统一打包处理,无论它是图片资源,样式资源,还是JS资源。Webpack会根据配置对不同类型的资源文件进行不同方式的处理。

<!-- dist/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <h1>Ruby</h1>
  </body>
</html>
// src/index.js
document.body.style.background = 'red'

简单起见,这里的js只做了改变背景色的操作。大家都能看出来,目前两个文件是还没有关联的,接下来我想办法让他们关联起来。这个时候就需要先配置Webpack,这里我采用了官方的配置。文件放在根目录下的 webpack.config.js文件中

// webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

配置文件都用js来写。写过js的人应该很容易就可以理解,它所代表的任务是解析入口文件./src/index.js然后对资源进行处理,最后把处理好的资源统一输出到./dist/bundle.js文件中。

配置好之后运行命令

> ./node_modules/webpack/bin/webpack.js # 运行我们一开始安装的Webpack

Hash: 15871b00d29beee17361
Version: webpack 3.8.1
Time: 63ms
    Asset     Size  Chunks             Chunk Names
bundle.js  2.51 kB       0  [emitted]  main
   [0] ./src/index.js 33 bytes {0} [built]

它会自动寻找当前目录下的webpack.config.js配置文件,然后编译并打包相应的文件,现在我们的目录结构大概会是这样了

.
├── dist
│   ├── bundle.js
│   └── index.html
├── node_modules
├── package.json
├── src
│   └── index.js
└── webpack.config.js

期望的出口文件已经生成,接下来只需要在html里面引入这个入口文件便可, 加上一行<script src="bundle.js"></script>

<html>
  ...
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

直接在浏览器打开index.html页面就能看到如下效果。

直接浏览器显示

这样第一点就已经完成了,它有良好的目录结构,不过现在看来这种简单的目录结构我们自己也懂得怎么构建,用Webpack的必要性似乎不大。接下来我们看看如何用Webpack方便地管理Sass等静态资源。

3) 编译并打包Sass文件

现代的前端领域,为了方便样式文件的管理与开发,我们一般会在项目引入Sass,或者Less这些技术,然而,浏览器却无法直接解析这类型的样式文件,也就是说如果要用到生产环境中,我们必须把这些资源进行预编译

那么Webpack如何管理Sass资源呢?很简单,我们只需要在入口文件src/index.js里面引入Sass的文件便可。我们首先创建一个src/example.scss的文件,并像下面这般引入。

// src/example.scss /
body {
    h1 {
        color: #fff;
        font-size: 40px;
        font-family: fantasy;
    }
}
// src/example.scss
import './example.scss';

document.body.style.background = 'red'

接下来在根目录下运行webpack的命令

./node_modules/webpack/bin/webpack.js

发现会有报错信息

ERROR in ./src/example.scss
Module parse failed: Unexpected token (1:5)
You may need an appropriate loader to handle this file type.
| body {
|     h1 {
|         color: #fff;
 @ ./src/index.js 1:0-24

Webpack还是非常人性化的,它告诉我们缺少了合适的Loader用来加载对应的Sass文件,如果没有对应的加载器则无法加载对应的资源文件。而Webpack对应的Sass加载器在这里

只需要按照文档的说法,安装缺少的加载器与编译工具便可

npm install style-loader sass-loader node-sass css-loader --save-dev

具体每一个包有什么作用,文档会提到,这里不详细说。接下来只需要把加载器的配置放到webpack.config.js文件里面便可。

// webpack.config.js
module.exports = {
    ...
    module: {
        rules: [{
            test: /\.scss$/,
            use: [{
                loader: "style-loader" // creates style nodes from JS strings
            }, {
                loader: "css-loader" // translates CSS into CommonJS
            }, {
                loader: "sass-loader" // compiles Sass to CSS
            }]
        }]
    }
};

然后再次运行Webpack的命令, 便可以编译通过了。

如果我们不想要每次修改资源都运行一次Webpack的命令,而是想让Webpack监控我们的文件改动,并自动打包,我们可以在命令后面加上--watch标识

> ./node_modules/webpack/bin/webpack.js --watch

Webpack is watching the files…

Hash: 691c616891a1a6c230b3
Version: webpack 3.8.1
Time: 698ms
    Asset     Size  Chunks             Chunk Names
bundle.js  19.1 kB       0  [emitted]  main
   [0] ./src/index.js 65 bytes {0} [built]
   [1] ./src/example.scss 1.15 kB {0} [built]
   [2] ./node_modules/css-loader!./node_modules/sass-loader/lib/loader.js!./src/example.scss 237 bytes {0} [built]
    + 3 hidden modules

这样每次我们改动资源文件,Webpack就会自动重新编译打包,我们只管刷新页面便可。下面是我把字体颜色改成绿色之后直接刷新页面的结果。

修改文件后直接刷新页面

由于我们的Webpack服务开启了--watch模式,我们不需要再次手动去运行Webpack命令重新打包资源。

4) 页面自动刷新

如果每次改了样式文件之后还要手动刷新的话,还是有点麻烦,效率还不够高。有没有办法修改前端文件之后自动刷新页面?这个时候请出神器webpack-dev-server.

npm install --save-dev webpack-dev-server

简单配置一下webpack.config.js文件,加上下面配置

module.exports = {

    .....
    devServer: {
        contentBase: './dist'
    },
};

接下来运行命令

./node_modules/webpack-dev-server/bin/webpack-dev-server.js
Project is running at http://localhost:8081/
webpack output is served from /

便可启动服务,我们只需要在浏览器访问http://localhost:8081/这个地址便可。

此时简单改变一下我们的js文件的内容,改变背景色

import './example.scss';

document.body.style.background = 'blue'

我们不再需要手动刷新页面了,webpack会自动被重新打包,并使得页面自动刷新。

修改静态资源自动刷新

但这里有一个问题,如果我们去修改没有被入口文件托管的文件,比如index.html文件,就算我们修改html文件的内容,页面也不会自动更新。

改HTML手动刷新

可见修改index.html文件后需要要手动刷新才行,要怎么使得当HTML文件被修改后自动刷新页面呢?很简单

修改webpack.config.js配置文件,在devServer上面加上watchContentBase: true这个配置便可。

.....
module.exports = {
    ....
    devServer: {
      contentBase: './dist',
      watchContentBase: true
    },
    ....
};

结果如下

自动刷新

可见,当我们修改index.html文件的时候网页会自动刷新。

5) 还有点小问题

这个问题是我后来才发现的,我们在通过webpack命令生成了一个叫bundle.js的文件,但是很奇怪的是,当我们删除了这个文件之后运行webpack-dev-server这个服务的话,它并不会重新生成这个文件。

> ls dist/
index.html

上面是我删除了dist/bundle.js并运行webpack-dev-server之后的结果,dist/目录下并不会重新生成bundle.js文件。但是我们的服务并不会提示我们说找不到bundle.js这个文件。我们的一切服务依然正常运行。

页面依然能够刷出来

这是因为webpack-dev-server会把打包好的数据存在内存中,并不会做文件IO操作,所以我们看不到对应文件的生成。

因此,如果我们使用webpack-dev-server来辅助开发的话其实是不会生成对应出口文件的,从内存中加载数据往往效率更高。

3. 尾声

有经验的webpack使用者来说或许不屑于像我这样做,况且如今不同的框架官方都对webpack配置进行了深度定制。在项目初始化的时候我们大可以站在巨人的肩膀上直接构建项目脚手架。使用如create-react-appvue-cli等脚手架工具来初始化我们的项目。大家可以根据自己的技术栈来选择合适的工具。

前端技术着实让人眼花缭乱,技术本身也参差不齐,各种技术都有他们的优缺点,我以为能够结合场景解决实际问题的方案才能算是最佳实践,我不排斥折腾,但我并不推荐瞎折腾。当如今前端技术让你难以选择,并感到焦虑的时候,我建议可以先考虑从基础入手,就是下面这三位

HTML + CSS + JavaScript

流行前后端分离的今天我们就一定要把我们的项目前后端分离吗?流行使用Vue,React这些框架的今天我们就必须抛弃JQuery吗?个人不敢苟同,前后端分离的项目固然有它的优势。如果你正在使用前后端分离的方式去构建一个简单的博客系统,或许你该静下心来想想,这种选择是否只是在增加开发难度?

当你手上有锤子的时候,看什么都像钉子。

很感谢看到这里。

Happy Coding and Writing !!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349