一次webpack体验

目录结构

project
        - css
            - bootstrap.min.css
            - jb.css
        - fonts
            - 一些bootstrap的字体
        - images
            - 一些项目用到的图片
        - js
            - bootstrap.min.js
            - jquery.min.js
            - jb.js
        - index.html
        - favicon.ico复制代码

项目背景

这个是公司要作的一个官方网站。因为项目比较简单,要求是单页的,没有页面跳转,因此只有一个 .html 文件。项目用了比较常规的 bootstrap + jquery 的开发,这个也没啥好说的。考虑到 CDN 的可控性,因此把全部 bootstrap 的资源都下载到了本地进行引用。项目开始时是用了常规的 js 和 css 引用(css 放前面,js 放后面),在开发完成后,发现有时间多余,就考虑用 webpack 对他进行处理一下,以巩固和学习一下 webpack 所用到的知识css

初始化工做

1. 初始化

npm init

先初始化一个 package.json 文件来管理咱们 webpack 所依赖的文件包。一路无脑回车便可。复制代码

2. 安装 webpack

想要用 webpack ,那么你首先确定要安装 webpack 才能够啊。用如下命令:

    npm install webpack --save复制代码

3. webpack.config.js

在根目录下新建一个 webpack.config.js 文件,用来对 webpack 进行配置。
当有这个文件后,咱们系能够在命令行中用如下命令来启动配置好的 webpack 了。

    webpack --config webpack.config.js复制代码

4. 修改 webpack 打包命令

以上虽然也能够启动配置好的 webpack。可是每次要输这么一串命令好像有点太长了(懒啊)。因此在 package.json 中修改这样一项:

    "script": {

      + "start": "webpack --config webpack.config.js",

        "test": "echo \"Error: no test specified\" && exit 1"
    }复制代码

这样的话咱们就能够在命令行中少敲几个键盘了。直接用如下命令,就等同于上面的命令了:html

npm start复制代码

好了,到这里,初始化工做就作完了,那么开始咱们的 webpack 配置吧node

webpack.config.js

1. 哪里来的入口文件?

什么事入口文件

webpack 建立应用程序全部依赖的关系图(dependency graph)。图的起点被称之为入口起点(entry point)。入口起点告诉 webpack 从哪里开始,并根据依赖关系图肯定须要打包的内容。能够将应用程序的入口起点认为是根上下文(contextual root) 或 app 第一个启动文件jquery

跟其余的 spa 应用不同,这样的普通应用,其全部依赖都来自于 index.html 文件。若是说要有入口文件的话,怎么也应该是 index.html 他自己吧。可是 webpack
基本都是用 .js 文件做为入口文件,用 .html 做为入口文件的...(反正我是没有见到过)。至于这里有啥缘由的话,你们就参考一下这篇文章吧。(其实我也不懂)webpack

因此说,无论怎么样,咱们都须要有个入口文件。git

那就无论怎么样,咱们常常看到的 webpack 的配置都是这样的github

module.exports = {
        entry: './index.js'
    }复制代码

那么咱们无论三七二十一,先在根目录下新建一个 index.js,而后让他做为咱们的入口文件。web

index.js

要知道,对于咱们原来的项目而言,咱们根本就是不须要这么一个 index.js 文件的(没有他,咱们能够活得更好)。可是咱们又不得不建立了这样一个文件。那么问题来了,这么建立出来的文件,里面又该放什么内容呢?咱们总不应救这么建立一个空文件就算了吧。npm

在考虑这个问题的时候,咱们能够先去看下 webpack 官方的那个很经典的图(我很懒,就不放图了,你们本身去网上找吧)。webpack 把左边乱七八糟的 .js .css .png .jpg .sass。。。等等文件所有打包成了静态资源。也就是说,webpack 打包的是除 html 外的全部资源,那么咱们是否是只要把这些资源都放到入口文件中那么就可让 webpack 帮咱们打包了呢?json

可是等等。其余的都没有问题,什么 css 啊,什么 js 啊,都好说,由于用来也不过这么几个,可是图片呢,字体呢?我在项目中用了那么多图片,要所有再在 index.js 里面再写一遍!天呐!这是要命的啊!那么我能不能偷懒下,就只写 css 和 js 呢,其余乱七八糟的我先无论?那就先这么来吧。修改咱们的 index.js 文件,添加如下内容。

require('./css/bootstrap.min.css')
    require('./css/jubang.css')
    require('./js/jquery.min.js')
    require('./js/bootstrap.min.js')
    require('./js/jb.js')复制代码

先这样把他看成咱们的入口文件吧

2. 配置出口文件

出口文件就很好配置了,将他打包到根目录下的 dist 目录中。嗯 ~ 这很常见!

var path = require('path');
    module.exports = {
        entry: './index.js',
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname, 'dist')
        }
    }复制代码

3. 配置 loader

这个不知道怎么配置,就先看这篇文章吧。

因此说,到这里咱们的 webpack.config.js 就是这样的:

var path = require('path');

    module.exports = {
        entry: './index.js',
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname, 'dist')
        },
        module: {
            rules: [{
                test: /\.css$/,
                use: [
                    'style.loader',
                    'css-loader'
                ]
            }, {
                test: /\.(png|jpg|svg|git)$/,
                use: [
                    'file-loader'
                ]
            }, {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    'file-loader'
                ]
            }]
        }
    }复制代码

这里咱们用到了三个 loader,须要先安装下

npm install css-loader style-loader file-loader --save复制代码

这三个 loader 的做用你们仍是本身去网上查找吧

4. 第一次打包

配置到这里,咱们能够先来打包一下,有问题再改嘛!

命令行切换到项目目录下,执行如下命令:

    npm start


打包结束后,项目的目录结构

    project
        - css
        - dist
        - fonts
        - images
        - js
        - node-modules
        - favicon.ico
        - index.html
        - index.js
        - package.json
        - webpack.config.js

咱们能够看到,项目根目录下面多出来一个 dist 的目录。没错,这个就是咱们 webpack 打包后文件生成的目录,至于为何会是 dist 目录,那是由于你在 webpack.config.js 的 output 中设置的 path。


如今咱们来查看下 webpack 打包出了什么东西

        - dist
            - xxxx.jpg
            - xxxx.woff2
            - xxxx.jpg
            - xxxx.svg
            - bundle.js
            - xxxx.ttf
            - xxxx.eot
            - xxxx.woff复制代码

注:xxxx表明一串数字和字母的组合,为了表示方便就这么写了

打包文件中生成了一个 .js 文件,两个 .jpg 文件,四个字体文件(.woff二、.ttf、.eot、.woff),和一个 .svg 文件

咱们来看下这是个类型的文件都来自哪里吧复制代码

1. bundle.js

bundle.js 是咱们根据咱们入口文件,将咱们在入口文件中全部的依赖资源都打包进去生成的。这个也是咱们最主要要关注的文件。

2. .jpg

两个 .jpg 文件是从哪里来的呢?查看了两张图片以后,其实咱们会知道,这两个图片都是在咱们本身写的 jb.css 中用来做为 background-image 引入的。咱们说了,webpack 会根据入口文做为起点,并根据依赖关系图来进行打包的。换句话说,咱们在入口文件中依赖了 jb.css,而 jb.css 依赖了两张 .jpg 图片,因此 webpack 根据依赖分析,将这两张图片也都一块儿打包进来了。

3. 字体文件 + svg

四个字体文件的来源就须要咱们对 bootstrap 有必定了解了。若是熟悉 bootstrap 的同窗确定会知道,在 bootstrap 的依赖里面,他正是依赖了这些字体,也就是说这些字体文件是从 bootstrap.min.css 文件中被打包进来的。其实我在作这个项目的时候,把 bootstrap 的源码弄到本地的时候,会发现里面有一个 fonts 的文件夹,也就是咱们项目根目录下的 fonts 文件夹,这里会有四个一样文件结尾的字体文件和一个 .svg 结尾的 svg 文件。而这五个文件不就是咱们这里多出来的五个文件嘛

若是还不放心的话,咱们能够再作个验证。修改 webpack.config.js 文件

{
        test: /\.(png|jpg|svg|git)$/,
        use: [
        -    'file-loader'
        +    'file-loader?name=[hash:8].[name].[ext]'
        ]
    }, {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
        -    'file-loader'
        +    'file-loader?name=[hash:8].[name].[ext]'
        ]
    }复制代码

咱们把图片和字体文件,在 file-loader 处理后让他的名字就变成 ’8位hash值-原文件名-后缀名‘的格式,那么咱们就能够比对这几个文件的来源了。
从新打包后(你得先删除原来的 dist 文件夹),咱们就能够发现咱们的猜想是正确的!

4. 遗留问题

虽然咱们的第一次打包成功了,可是仍是留下了几个问题没有解决:第一,个人 js、css、字体、图片等资源都被打包进了 dist 目录,可是做为咱们的项目最主要的 index.html 文件呢?没有这个文件,咱们打包出来的东西还有什么意义呢!。第二,个人 images 文件夹里有那么多图片,你这个 webpack 打包后为何就只有两张图片了,其余的呢?

那么接下来让咱们急需解决。

5. html-webpack-plugin

要解决第一个问题,咱们须要用到 html-webpack-plugin 插件。这个插件的具体说明能够查看这里。这个插件的做用是能够将 html 文件打包,并自动添加对打包后的 output 文件的引用。具体如何使用,请先安装:

npm install html-webpack-plugin --save复制代码

修改配置文件:

var path = require('path');
    +   var HtmlWebpackPlugin = require('html-webpack-plugin');

在 module 后面加

    plugins: [
        new HtmlWebpackPlugin({
            template: './index.html'
        })
    ]复制代码

咱们在配置文件中引入了一个插件,并向 HtmlWebpackPlugin 构造函数传递了一个对象参数,在这个对象参数中,咱们指明了一个 template 字段,表面咱们要打包的 html 的文件源。而后咱们从新打包,再查看咱们的目录就能够发现 dist 目录下多出了一个 index.html。因为这个项目自己就是一个简单的不依赖任何环境的项目,因此若是正常的话咱们直接打开 index.html 页面就能在浏览器里正常显示了。虽然不知道会怎么样,可是咱们仍是打开来试试吧。

当咱们打开 index.html 在浏览器中显示的时候,咱们发现浏览器中好多图片都不见了。细想咱们的项目代码,发现除了在 jb.css 中的背景图被正确显示之外,其余的定义在 img 标签中的图片没有一张是显示出来的。

因此虽然这个文件配置还有点问题没解决,那么咱们先来解决 html 中的 img 问题吧,也就是咱们上面提到的第二个问题。

6. html-withimg-loader

要解决第二个问题(也就是 html 中的 img 问题),咱们须要用到 html-whithimg-loader,具体关于这个怎么用能够查看这里

修改配置文件,直接在 rules 中再添加一条配置规则

{
        test: /\.(html|htm)$/,
        use: [
            'html-withimg-loader'
        ]
    }复制代码

这条配置规则代表,全部要处理的 html 文件首先会通过 html-withimg-loader 这个 loader 处理。就是这么简单能将咱们第二个问题解决吗?试试看吧,事件是检验真理的惟一标准。

修改资源目录

从新打包,再查看 dist 目录,这一查看没关系,发现 dist 目录下多了好多图片文件,密密麻麻,乱七八糟的,这些该不会就是咱们 html 中的图片吧。按住本身的强迫症,先找到 index.html (咱们最关心的仍是他嘛),打开后再浏览器查看效果。发现果真,咱们的图片都已经在了,并且样式也差很少对了。可是这么乱七八糟的 dist 目录,怎么会是咱们这种强迫症患者所想要的结果呢!咱们想要的是图片都放在图片文件夹下,字体都放在字体文件夹下,其余的比较少的就先让他在外面呆着吧。说干就干,咱们来调整一下咱们的配置文件

{
            test: /\.(png|jpg|svg|git)$/,
            use: [
            -    'file-loader?name=[hash:8].[name].[ext]'
            +    'file-loader?name=images/[hash:8].[name].[ext]'
            ]
        }, 
        {
            test: /\.(woff|woff2|eot|ttf|otf)$/,
            use: [
            -    'file-loader?name=[hash:8].[name].[ext]'
            +    'file-loader?name=fonts/[hash:8].[name].[ext]'
            ]
        } 复制代码

自动删除 dist

还有一个问题我已经忍了好久了,每次打包前,咱们都须要手动先去删除上次打包留下来的 dist 目录,这个就烦了,虽然只是一个 delete 的事情,可是作多了也烦啊!咱们想能不能让 webpack 自动帮咱们作了这件事,让咱们不须要手动去删除。还好 webpack 够智能,总能知足你提出来的各类无理取闹。不过咱们先要装一个插件:

npm install clean-webpack-plugin --save复制代码

而后再配置文件中添加对这插件的引用

var HtmlWebpackPlugin = require('html-webpack-plugin');
    +   var CleanWebpackPlugin = require('clean-webpack-plugin');复制代码

在 plugins 中添加对这个插件的使用

new CleanWebpackPlugin(['dist'])复制代码

这样咱们就能不用手动删除 dist 文件夹了。

从新打包下试试吧!

打包完后咱们在查看 dist 目录就瞬间感受清爽多了有木有!

- dist
        - fonts
            - 一些字体文件
        - images
            - 一些图片文件

        - bundle.js
        - index.html复制代码

修改 index.html

将打包后的项目再次在浏览器中查看,并查看控制台会发现,控制台报了一堆错误。其中有几个是对一些 css、js 文件引用的错误。由于咱们把须要用的 css、js 都打包进了 bundle.js 中了。而咱们原来的项目是经过静态资源引用的方式一个个导入 html 文件中的。因此,当咱们 webpack 打包成功后,就不须要对这些资源进行引用了,咱们只须要对 bundle.js(咱们打包后的文件)进行引用就能够了,所幸的是,打包后的文件 webpack 已经自动帮咱们引用了。因此直接在原来项目中的 index.html 中干掉那些 css、js 就能够了。而后从新打包后就没有这些资源找不到的乱七八糟的错误了。

可是,有一个小问题就是关于咱们的 .ico 文件。这是咱们网站的图标文件。他的引用错误该如何解决呢?咱们能够在生成 html 的时候,将这个问题先给解决了。修改配置文件

new HtmlWebpackPlugin({
        template: './index.html',
    +    favicon: path.resolve(__dirname, './favicon.ico')
    })复制代码

这样的话咱们的图标文件也就有了。

7. 关于 jquery

虽然一些乱七八糟的引用错误解决了,可是控制台留下了一个让咱们很是头疼的问题:jquery 的引用问题:

Uncaught Error: Bootstrap's JavaScript requires jQuery复制代码

这里咱们须要用到 expose-loader 这个东西,关于他,能够查看这里,废话很少说:

npm install expose-loader --save复制代码

在 module 的 rules 中再添加一个 loader

{
        test: require.resolve('./js/jquery.min.js'), // 引入 jquery
        use: [{
            loader: 'expose-loader',
            options: '$'
        }, {
            loader: 'expose-loader',
            options: 'jQuery'
        }]
    }复制代码

固然,网上或许有其余方法关于引入 jquery 的,这里只是说一种。而后再打包咱们的页面就没有问题了:各类资源都有了,js 写的效果也出现了。

8. 提取 css

虽然网站看上去没啥问题了,可是细心的同窗确定会发现:当咱们打开网站的时候,他会先出现一个没有样式的页面,而后一闪而逝,最后才出现咱们预期的样子。这是为何呢?

缘由很好理解,由于咱们把 css 和 js 都打包进了同一个 bundle.js 里面了。可是,这个 bundle.js 是在页面最后面才加载进来的。也就是说,咱们的样式被放在了页面的底部被加载。这彻底不符合咱们的预期啊。咱们但愿的是样式在 head 中加载,而 js 脚本才放在页面底部加载。因此咱们就不能把 css 和 js 一块儿打包进 bundle.js 中了。

extract-text-webpack-plugin

详细资料看这里

npm install extract-text-webpack-plugin --save复制代码

增长 require

var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');复制代码

修改 css rules

{
        test: /\.css$/,
        use: ExtractTextWebpackPlugin.extract[{
            fallback: 'style-loader',
            use: 'css-loader'
        }]
    }复制代码

增长 plugin

new ExtractTextWebpackPlugin('style.css')复制代码

打包,而后咱们会发现 dist 中多了一个 style.css,而后再 index.html 的 head 中的多了对这个 css 的引用

9. 其余

1. 压缩 js

增长 plugin

new webpack.optimize.UglifyJsPlugin({
        compress: {
            warnings: false
        }
    })复制代码

2. 压缩 html

new HtmlWebpackPlugin({
    template: './index.html',
    favicon: path.resolve(__dirname, './favicon.ico'),
    minify: {
        removeAttributeQuotes: true,
        removeComments: true,
        removeEmptyAttribute: true,
        collapseWhitespace: true
    }
}),复制代码

3. 优化图片

{
        test: /\.(jpg|png|gif|svg)$/,
        - use: 'file-loader?name=images/[hash:8].[name].[ext]'
        + use: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]'
    }复制代码

总结

暂时就先那么多吧,没时间写了,之后再说。第一次发文,求轻虐。

参考文档

webpack(v3.5.5)中文文档

相关文章
相关标签/搜索