Webpack现在风靡一时。 它在GitHub上拥有30,000颗星,并已被JavaScript世界中的一些知名人士所接受,例如React和Angular。
但是,您无需从事大型项目即可利用Webpack。 Webpack主要是一个打包程序,因此,您也可以使用它来打包您想考虑的任何资源或资产。
在本文中,我将向您展示如何安装和配置Webpack,然后使用它为具有少量资产的简单静态站点创建缩小的捆绑包。
但是为什么要这么做呢?
好问题。 很高兴你问!
这样做的主要原因之一是最大程度地减少了您向服务器发出的HTTP请求的数量。 随着平均网页的增长,您可能会包括jQuery,一些字体,一些插件以及各种样式表和您自己的一些JavaScript。 如果您要为这些资产中的每一个发出网络请求,那么事情很快就会加起来,您的页面可能会变得很呆滞。 但是,如果将以上所有内容都捆绑在一起,该问题就会消失。
Webpack还使简化代码变得更容易,进一步减小了代码的大小,并且使您可以按自己的喜好编写资产。 例如,在本文中,我将演示如何使Webpack将ES6转换为ES5。 这意味着您可以使用最新的最新语法编写JavaScript(尽管可能尚不完全支持),然后为几乎可在所有地方运行的浏览器ES5提供服务。
最后,这是一个有趣的学习练习。 是否在自己的项目中使用这些技术取决于您自己,但是随着学习的进行,您将对Webpack的工作方式,工作方式以及它是否很适合您有充分的了解。
起床并跑步
您需要做的第一件事是在计算机上安装Node和npm。 如果尚未安装Node,则可以从Node网站下载它 ,也可以在版本管理器的帮助下下载并安装它 。 就我个人而言,我更喜欢第二种方法,因为它允许您在多个版本的Node之间切换,并且消除了许多权限错误,否则可能会看到您使用管理员权限安装Node软件包。
我们还需要一个框架项目。 这是我早些时候做的 。 为了使其在您的机器上运行,您应该从GitHub克隆项目并安装依赖项。
git clone https://github.com/sitepoint-editors/webpack-static-site-example
cd webpack-static-site-example
npm i
这将把jQuery以及Slick Slider和Lightbox2 (我们将在网站上使用的两个插件)安装到项目根目录中的node_modules
文件夹中。
之后,您可以在浏览器中打开index.html
并浏览该站点。 您应该会看到以下内容:
如果您需要任何上述步骤的帮助,为什么不前往我们的论坛并提出问题 。
将Webpack引入项目
接下来,我们需要安装Webpack。 我们可以使用以下命令执行此操作:
npm i webpack --save-dev
这将安装的WebPack并将其添加为一个devDependency
您package.json
文件:
"devDependencies": {
"webpack": "^3.2.0"
}
接下来,我们将创建一个dist
文件夹,其中将包含捆绑的JavaScript。
mkdir dist
现在,我们可以尝试从命令行运行Webpack,以查看其设置是否正确。
./node_modules/webpack/bin/webpack.js ./src/js/main.js ./dist/bundle.js
我在这里所做的是告诉Webpack将src/js/main.js
的内容捆绑到dist/bundle.js
。 如果一切都正确安装,您应该在命令行中看到类似以下内容的输出:
Hash: 1856e2c19ecd9b2d9026
Version: webpack 3.2.0
Time: 50ms
Asset Size Chunks Chunk Names
bundle.js 2.67 kB 0 [emitted] main
[0] ./src/js/main.js 192 bytes {0} [built]
Webpack将在dist
文件夹中创建bundle.js
文件。 如果您在选择的文本编辑器中查看该文件, main.js
在底部看到一堆样板文件和main.js
的内容。
自动化我们的设置
现在,如果每次我们要运行Webpack时都必须在终端中键入以上所有内容,那将很烦人。 因此,让我们创建一个可以运行的npm脚本 。
在package.json
,将scripts
属性更改为如下所示:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack ./src/js/main.js ./dist/bundle.js"
},
注意,我们如何保留Webpack模块的完整路径,因为从脚本运行时,npm会自动在node_modules
文件夹中查找该模块。 现在,当您运行npm run build
,应该和以前一样发生。 酷吧?
创建一个Webpack配置文件
注意我们如何将文件路径传递到bundle并将输出文件路径作为参数传递给Webpack? 好吧,我们可能应该更改它,并在配置文件中指定它们。 以后再使用装载机时,这将使我们的生活更轻松。
在项目根目录中创建一个webpack.config.js
文件。
touch webpack.config.js
并添加以下代码。
module.exports = {
entry: './src/js/main.js',
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
}
}
并将npm脚本更改为以下内容:
"scripts": {
...
"build": "webpack"
},
在webpack.config.js
我们将束的入口和输出位置指定为配置对象的属性,然后将其导出。 再次运行一切,它应该都像以前一样工作。
包括捆绑
现在我们有了Webpack为我们生成一个包,下一步我们要做的是将它包含在某个地方。 但是首先,让我们创建一个不同的入口点,以便我们实际上可以需要main.js
这将是src/js
目录中名为app.js
的文件。
touch src/js/app.js
将以下内容添加到app.js
:
require('./main.js');
并因此更改webpack配置:
entry: './src/js/app.js',
再次运行npm run build
来重新创建捆绑软件。 一切都应该像以前一样工作。
现在,如果看一下index.html
您会发现在JavaScript方面没有太多进展。 在文件的底部,我们包括jQuery和一个名为main.js
的文件,该文件负责在您单击Read more…链接时显示更多信息。
让我们编辑index.html以包括bundle而不是main.js
查看文件的底部。 您应该看到:
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script src="./src/js/main.js"></script>
</body>
</html>
更改为:
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script src="./dist/bundle.js"></script>
</body>
</html>
在浏览器中刷新页面,并让自己确信Read more…链接仍然有效。
捆绑jQuery。
接下来,让我们将jQuery添加到包中。 这将减少页面发出的HTTP请求的数量。 为此,我们必须像这样更改app.js
文件:
window.$ = require('jquery');
require('./main.js');
这里我们需要jQuery,但是当我们使用npm安装它时,我们不必包括完整路径。 我们还将其通常的$
别名添加到全局window
对象,以便其他脚本可以访问它。
更改index.html
以删除jQuery脚本标签:
<script src="./dist/bundle.js"></script>
</body>
</html>
运行npm run build
然后再次在浏览器中刷新页面,以使自己相信Read more…链接仍然有效。 是吗 好!
捆绑CSS
查看index.html
,我们向网络发出请求的唯一另一件事就是CSS。 如您所见,我们在页面顶部包含main.css
,而该文件又导入了四个CSS文件。
尽管在Webpack的标准配置中,它只能处理JavaScript,但我们也可以使用称为loader的东西将其捆绑到CSS中。 从Webpack文档 :
加载程序是应用于模块源代码的转换。 它们允许您在导入或“加载”文件时对其进行预处理。 因此,加载程序有点像其他构建工具中的“任务”,并提供了一种强大的方式来处理前端构建步骤。 加载程序可以将文件从其他语言(例如TypeScript)转换为JavaScript,也可以将内嵌图像转换为数据URL。 加载程序甚至允许您执行诸如直接从JavaScript模块导入CSS文件之类的操作!
因此,让我们更改app.js
:
// CSS
require('../css/main.css');
// JavaScript
window.jQuery = window.$ = require('jquery');
require('./main.js');
并且我们需要更改webpack.config.js
以告知它在遇到以.css
结尾的文件时运行哪个加载器:
module.exports = {
...
module: {
loaders: [
{
test: /\.css$/,
loaders: [
'style-loader',
'css-loader'
]
}
]
}
}
如您所见,我指定了两个加载器: css-loader和style-loader 。 在这两者之间,css-loader将CSS转换为JavaScript模块,然后style-loader在运行时将JavaScript模块导出的CSS注入<style>标记中。 让我们同时安装:
npm i --save-dev css-loader style-loader
现在,让我们使用npm run build
再次运行Webpack,看看会发生什么。
Hash: 3699b503299ce447108d
Version: webpack 3.2.0
Time: 409ms
Asset Size Chunks Chunk Names
bundle.js 289 kB 0 [emitted] [big] main
[1] ./src/js/app.js 97 bytes {0} [built]
[2] ./src/css/main.css 1.01 kB {0} [built]
[3] ./node_modules/css-loader!./src/css/main.css 494 bytes {0} [built]
[4] ./node_modules/css-loader!./src/css/fonts.css 353 bytes {0} [built]
[5] ./src/fonts/open-sans/OpenSans-ExtraBold.ttf 271 bytes {0} [built] [failed] [1 error]
[6] ./node_modules/css-loader!./src/css/layout.css 219 bytes {0} [built]
[7] ./node_modules/css-loader!./src/css/styles.css 1 kB {0} [built]
[8] ./node_modules/css-loader!./src/css/responsive.css 359 bytes {0} [built]
[12] ./src/js/main.js 192 bytes {0} [built]
+ 4 hidden modules
ERROR in ./src/fonts/open-sans/OpenSans-ExtraBold.ttf
Module parse failed: /home/jim/Desktop/webpack-static-site-example/src/fonts/open-sans/OpenSans-ExtraBold.ttf Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
@ ./node_modules/css-loader!./src/css/fonts.css 6:131-183
@ ./node_modules/css-loader!./src/css/main.css
@ ./src/css/main.css
@ ./src/js/app.js
哦,不! 发生了什么? 检查输出,似乎src/css/fonts.css
中存在错误。 如果打开该文件并查看第5行,您会看到我们包括一个自定义字体( src/fonts/open-sans/OpenSans-ExtraBold.ttf
),而Webpack不知道该怎么做。
但是不用担心,我们已经做到了! 我们只需要使用另一个加载器。 这次url-loader可以将诸如字体和图像之类的资产转换为Data URLs ,然后可以将其添加到捆绑软件中:
module.exports = {
...
module: {
loaders: [
{
test: /\.css$/,
loaders: [
'style-loader',
'css-loader'
]
},
{
test: /\.ttf$/,
loaders: [
'url-loader'
]
}
]
}
}
当然,我们需要安装它:
npm install url-loader --save-dev
现在构建应该运行了。 通过删除CSS包含,重新创建捆绑包和刷新页面来进行测试。
捆绑第三方图书馆
现在,让我们将注意力转向photos.html
。 由于我们正在使用两个库Slick Slider和Lightbox2,这两个库均依赖jQuery,因此该页面上还有更多内容。 幸运的是,我们可以应用我们学到的技术将这些技术包括在捆绑软件中。
像这样更改app.js
:
// CSS
require('slick-carousel/slick/slick.css')
require('slick-carousel/slick/slick-theme.css')
require('lightbox2/dist/css/lightbox.min.css')
require('../css/main.css');
// JS
window.$ = require('jquery');
window.slick = require('slick-carousel');
window.lightbox = require('lightbox2');
require('./main.js')
另外,从文档的开头删除CSS include,从脚注删除脚本包括。 这应该给我们:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>I Can Haz Cheeseburger?</title>
</head>
<body>
...
<script src="dist/bundle.js"></script>
<script>
$('.slick-slider').slick({
dots: true,
arrows: false,
infinite: true,
speed: 500,
fade: true,
cssEase: 'linear'
});
</script>
</body>
</html>
尽管没有什么可以阻止我们在捆绑包中包含Slick初始化代码,但我将其保留在此页面上,因为我们只想在这里使用它。
现在让我们运行Webpack看看会发生什么:
ERROR in ./node_modules/slick-carousel/slick/ajax-loader.gif
Module parse failed: /home/jim/Desktop/webpack-static-site-example/node_modules/slick-carousel/slick/ajax-loader.gif Unexpected character '' (1:7)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
@ ./node_modules/css-loader!./node_modules/slick-carousel/slick/slick-theme.css 6:119-147
@ ./node_modules/slick-carousel/slick/slick-theme.css
@ ./src/js/app.js
ERROR in ./node_modules/slick-carousel/slick/fonts/slick.eot
Module parse failed: /home/jim/Desktop/webpack-static-site-example/node_modules/slick-carousel/slick/fonts/slick.eot Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
@ ./node_modules/css-loader!./node_modules/slick-carousel/slick/slick-theme.css 6:309-337 6:362-390
@ ./node_modules/slick-carousel/slick/slick-theme.css
@ ./src/js/app.js
糟糕,另一个错误! 这次似乎是slick-theme.css
文件出现问题,该文件引用了gif格式的图像。 Webpack不知道该如何处理gif,因此它会举起手臂并停止工作。 但是我们知道该怎么办,对吗?
将以下内容添加到webpack.config.js
:
{
test: /\.(svg|gif|png|eot|woff|ttf)$/,
loaders: [
'url-loader'
]
}
您会注意到我已经更改了正则表达式以匹配其他几种文件类型。 Slick或Lightbox2都需要这些。 再次运行Webpack,并确保它完整无误。
刷新页面,并确保自己一切正常。
一些画龙点睛。
我们几乎完成了,但是有几件事我们可以改进。
处理未样式化内容的闪烁
页面加载时,您是否注意到未样式化内容的闪烁 ? 这可以通过利用<script>标记的阻止性质并将include移到文件顶部来解决。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>I Can Haz Cheeseburger?</title>
<script src="dist/bundle.js"></script>
</head>
<body>
...
</body>
</html>
缩小捆绑
我们还可以使用p
标志( 生产的缩写)运行Webpack,并将其最小化
在package.json
:
"scripts": {
...
"build": "webpack -p"
},
在webpack.config.js
:
module.exports = {
entry: './src/js/app.js',
output: {
path: __dirname + '/dist',
filename: 'bundle.min.js'
},
module: {
...
}
}
并在index.html
和photos.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>I Can Haz Cheeseburger?</title>
<script src="./dist/bundle.min.js"></script>
</head>
<body>
...
</body>
</html>
这将包大小减小到480kb。 对于某些CSS,JS和其他一些资产,这似乎有点过分,但请记住,其中的222kb是字体。
将ES6转换为ES5
您还可以安装babel-loader,并让Webpack通过它运行JavaScript文件,从而将ES6转换为ES5。
npm install babel-core babel-loader babel-preset-es2015 --save-dev
在webpack.config.js
:
{
test: /\.js$/,
loader: 'babel-loader?presets[]=es2015'
},
当然,您可以将ES6换成几乎所有您喜欢的JavaScript语言编译语言。
结论
所以你有它。 在本文中,我演示了如何使用Webpack捆绑一个简单的静态站点,该过程减少了发出的HTTP请求数量,从而使该站点可能更灵活,响应速度更快。 我还演示了如何使Webpack缩小生成的包,从而显着减小文件大小,以及如何使用babel-loader装入ES6。
即使不是所有人都可以使用这种策略,也希望通过遵循该策略,您可以深入了解Webpack的功能以及它的工作方式。 对于那些希望进一步探索Webpack的人,我建议使用Webpack 2和模块捆绑的初学者指南 ,它会更深入一些。
如果您有任何疑问或意见,我们很高兴在下面的讨论中听到他们的意见。