『极简』一篇文章让你学会使用webpack

webpack是干什么?


我们每次开发的时候,都需要在页面的head中加载各种js资源,当你加载了jquery和vue全家桶一套以后,你会发现你的页面已经变得非常的臃肿。更别说你还需要要引用一个你自己的index.js文件。

如果你之前接触过sea.js或者require.js的话,你就可以很容易的理解(你没接触过也无所谓)他们的核心思想就是,把所有需要引入的js,都通过一个公用的js文件去加载。并且在这个js文件中赋予一些逻辑性。

所以最后的结果就是,你最后生成的html文件中只会引用一个js文件和一个css文件,这样不但代码变整洁了,页面打开速度也获得了巨大的提升,这就是所谓的前端优化。

webpack就是一个为了解决这个问题而诞生的工具。当然,它绝对没有这么简单,还记得es6吗,还记得less,sass这种高科技语法吗,你直接在html中使用是不行的,因为低端浏览器并不能解析这类语法。但是通过webpack,我们可以集成一个解析器babel来帮助我们实现对这类语法的解析,让低端浏览器实现全兼容。怎么样,webpack是不是很强大?现在让我们更加详细讲解它的奥秘。

如何安装


webpack是基于nodejs语言的,你不会nodejs也没用关系,因为他只有几个简单的命令。

先从nodejs的官方网站下载nodejs,安装完毕以后,打开doc窗口输入:

npm -g i webpack@3.8.1

安装完毕查看一下版本号。



如果能正确显示版本号,说明安装成功!

创建项目


创建一个你想要作为项目的文件夹,然后在这个文件夹上shift+右键在弹出的菜单中选择打开powershell,这个东西是原来那个doc窗口的加强版,功能跟小黑窗一模一样。然后输入:

npm init

你会看到很多需要你输入的东西,不用管,一路回车。


这一步的主要目的是创建一个基于npm的项目,以后,我们安装任何插件,只需要配置这个项目中的package.json文件即可。如果你之前没有使用过npm,你到这一步的时候可能会有点蒙,不要着急,我们继续往下,龙哥的文章向来就是即插即用,就算你不会安装,你把我给你的例子一拷贝,你也可以实现webpack的各种操作,原理什么的你在实战中逐渐体会也完全没问题。

接着你用编辑软件打开刚才输入命令的那个文件夹,你会发现里面有一个package.json文件,改成我这个样子:

{
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.1",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "babel-runtime": "^6.26.0",
    "autoprefixer": "^7.2.3",
    "css-loader": "^0.28.7",
    "style-loader": "^0.21.0",
    "less-loader": "^4.1.0",
    "url-loader": "^0.6.2",
    "file-loader": "^1.1.6",
    "html-webpack-plugin": "^2.30.1",
    "webpack": "^3.8.1",
    "webpack-dev-server": "^2.9.7",
    "webpack-require-http": "^0.4.3",
    "extract-text-webpack-plugin": "^3.0.2"
  },
  "name": "demo",
  "version": "1.0.0",
  "main": "webpack.js",
  "dependencies": {
    "bootstrap": "^3.3.7",
    "html-loader": "^0.5.5",
    "jquery": "^2.1.1",
    "less": "^3.0.4",
    "less-loader": "^4.1.0",
    "style-loader": "^0.21.0",
    "webpack-dev-server": "^2.11.5"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",
    "dev": "webpack-dev-server"
  },
  "author": "",
  "license": "ISC",
  "description": "",
  "babel": {
    "presets": [
      "es2015",
      "react"
    ]
  }
}

刚才我们说了,这个文件主要的作用是,npm在你这个项目中,使用哪些插件。你仔细看我这个文件,里面已经包含了es6解析器,css和less,url图片地址等等各种解析器,甚至规定了webpack的版本。

然后输入一遍

npm install

这一步操作的目的是把配置文件中的内容安装到本地。

webpack.config.js的配置


接着在package.json的同级目录下创建一个webpack.config.js,这个文件的目的主要是为了配置我们的webpack。

像我这样写:

// 引入webpack
const webpack = require('webpack')
// 引入html生成插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 引入css压缩插件
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
    // 入口文件,指向app.js
    entry: {
        index: './src/js/index.js',
    },
    // 出口文件
    output: {
        // 项目的路径
        path: __dirname + '/dist',
        // 增加随机数防止缓存
        //filename: 'js/[name].[hash:5].js',
        // 输出的文件的路径
        filename: 'js/[name].js',
        // 为使用热启动后产生的日志文件设定输入路径
        hotUpdateChunkFilename: 'hot/hot-update.js',
        hotUpdateMainFilename: 'hot/hot-update.json'
    },
    externals:[
        // 让webpack可以加载外部http资源 例如螳螂
        require('webpack-require-http')
    ],
    // webpack-dev-server 环境
    devServer: {
        contentBase: './dist',
        hot: true
    },
    module: {
        // loader放在rules这个数组里面
        rules: [
            {
                //把es6转换成es5
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader'
            },
            {
                test: /\.html$/,
                use: {
                    loader: 'html-loader'
                }
            },
            {
                //识别图片
                test: /\.(png|jpg|gif)$/,
                loader: 'url-loader',
                options: {
                    limit: 4096,
                    name: 'image/[name].[ext]'
                }
            },
            {    
                //压缩css
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    publicPath: "../",
                    use: [
                        {
                            loader: 'css-loader',
                            options:{
                                minimize: true //css压缩
                            }
                        }
                    ]
                })
            },
            {
                //识别字体文件
                test: /\.(woff|woff2|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: 'file-loader?name=./fonts/[name].[ext]'
            },
        ]
    },
    // 将插件添加到webpack中
    plugins: [
        // 开启多页应用 生成html文件
        new HtmlWebpackPlugin({
            //模板文件是哪个
            template: './src/index.html',
            //选择注入哪个文件
            chunks: ['index'],
            //是否添加hash随机数防止缓存
            //hash: true,
            //开启html压缩
            minify:{
                removeComments:true, //移除HTML中的注释
                collapseWhitespace:true//压缩为一行
            },
            // manual根据chunks的位置手动排序
            chunksSortMode: "manual"
        }),
        // 防止webpack一直弹出警告 加载HMR需要的两个插件
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        // 解决加载jquery后 jquery不能获得$符控制权的问题
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery"
        }),
        new ExtractTextPlugin("css/styles.css"),
    ]
}

你现在肯定有点懵,这是干什么呢??上来一顿配置,我都不知道干什么呢。
不用着急,我们先把开发环境配置好,当我们开始使用的时候,我们会逐个讲解这些配置用到的地方!

到了这一步,你的项目文件夹下面,应该有node_modules文件夹,一个package.json文件和一个webpack.config.js文件,好的,然后你再创建两个文件夹,一个叫src,一个叫dist。

全部完成以后是这样的:


到了这一步,webpack的安装和配置就完成了,接下来我们该进入开发环节了。

如何使用


我们新建的两个目录:dist为生成生产环境,src为开发环境
你所有的操作全部在src中完成,我们的最终目的是:
通过小黑窗口中输入一遍webpack命令,把src中的文件压缩优化成为src文件夹中的最终形态。也就说,我们开发的时候,只需要修改src目录中的内容,正式上线的时候,只需要把dist中的文件通过ftp传到服务器就可以了。

这里龙哥需要给你讲一下原理,现在webpack的教程有很多,但是我相信大部分人到了,入口文件那块就差不多放弃了。因为webpack它本身是基于nodejs的,nodejs顾名思义,只能编译js...

所以,你放在项目里面的html啊,css啊甚至图片啊。nodejs一概不承认,或者你可以理解为,它不认识这是什么。

这里我们就需要编写一个文件,让我们把项目中的所有资源都利用起来,并且告知webpack这些资源都是什么,这个文件,就叫做入口文件。这个文件的配置你可以灵活配置,我自己是选择放在src中的js文件夹中,因为这样让它们看起来更加规范一些。

如果你仔细阅读上面的webpack.config.js文件的话,你会发现,里面的entry项就是入口文件的位置。

然后我们来看看这个文件中都写了一些什么东西:

//引入jquery 必须为此写法让插件和全局都获得jquery支持
import $ from 'jquery'
window.$ = $
window.jQuery = $
export default $
//引用bootstrap
// import 'bootstrap';
// import 'bootstrap/dist/css/bootstrap.css';

//加载自己的js
import '../js/time/flipclock.js';

//引用html加载页面上的src资源
import '../index.html';

//引入自己的css
import '../css/index.css';
import '../js/time/flipclock.css';

你会发现,页面,页面上的css和js都是在这个js文件中被引用的。
此时我的html页面上什么也没有引用。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>我的标题</title>
    </head>
    <body>
        <article>
            我的内容
        </article>
    </body>
</html>

你可能会好奇,如果我的html中不引入,那么最后打包完了以后,这个js文件会被加载吗?
答案是会的,webpack会自动加载配置文件中的入口文件到你的html中。

这里我忽然想起了一个情况:那就是,有一些时候,我们需要引入外网的资源,这些资源是不能被打包到项目中的,比如一些crm系统,或者一些站长统计的js。

我们需要使用这个方法:

//引入jquery 必须为此写法让插件和全局都获得jquery支持
import $ from 'jquery'
window.$ = $
window.jQuery = $
export default $
//引用bootstrap
// import 'bootstrap';
// import 'bootstrap/dist/css/bootstrap.css';

//加载自己的js
import '../js/time/flipclock.js';

//引用html加载页面上的src资源
import '../index.html';

//加载外网的js
Promise.all([
    require('http://talk2.bjmantis.net/chat/js/dist/mantis.min.js?123456'),
    require('http://talk2.bjmantis.net/chat/js/dist/register_form.min.js')
]).then(function() {
});

//引入自己的css
import '../css/index.css';
import '../js/time/flipclock.css';

然后让我们来完成这个页面,我添加了一些内容,然后把图片也引入了,当我们感觉编辑的差不多了的时候,在小黑窗中输入:

npm run dev

你会看到这个画面,然后打开窗口中提示的地址就能看到我们的页面。

打包发布项目


当我们感觉页面已经没问题可以打包上线的时候,还是在这个目录上,输入:

webpack

是的,仅仅就需要这么一个单词而已。
然后打开dist目录,你会发现所有的文件webpack已经帮我们打包好了,然后我们把dist目录里面的文件上传到ftp就行了。

webpack常见问题解答

通过上面的学习,我们已经可以通过webpack压缩优化我们的项目了。
但是我想告诉你的是webpack能做的事情远不止如此,我们经过学习,知道了webpack其实是一个打包工具,它把我们项目中用到的插件都合并成了一个js,还可以优化css和img图像。那么,我们常用的插件是哪些?它们又发挥了什么作用?打包出来的页面能否不只是一个spa而是多个页面呢?

常用插件说明(package.json)


package.json中有一项是devDependencies,这一项表示npm包中引用了哪些编译包

插件名称 版本号 作用
babel-core 6.26.0 编译es6
babel-loader 7.1.2 编译es6
babel-plugin-transform-runtime 6.23.0 编译es6
babel-preset-env 1.6.1 编译es6
babel-preset-es2015 6.24.1 编译es6
babel-preset-stage-0 6.24.1 编译es6
babel-runtime 6.26.0 编译es6
autoprefixer 7.2.3 css3自动添加前缀
css-loader 0.28.7 编译css样式表
style-loader 0.21.0 编译css样式表
less-loader 4.1.0 编译less样式表
url-loader 0.6.2 编译图像,能转化为base64就转化,不能转化就通过file插入到页面中
file-loader 1.1.6 编译图像,能转化为base64就转化,不能转化就通过file插入到页面中
html-webpack-plugin 2.30.1 生成html 否则你的项目最后只会有一个压缩的js
webpack 3.8.1 webpack
webpack-dev-server 2.9.7 本地环境启动器
webpack-parallel-uglify-plugin 1.1.0 js压缩工具
webpack-require-http 0.4.3 加载外部文件
extract-text-webpack-plugin 3.0.2" 提取css为一个文件

webpack可否通过多个入口文件打包成多个页面,而不是spa


第一步你需要HtmlWebpackPlugin
在webpack.config中配置成这个样子,生成多个页面。

new HtmlWebpackPlugin({
   template: './src/index.html',
   chunks: ['common', 'index']
}),
new HtmlWebpackPlugin({
   filename: 'list.html',
   template: './src/list.html',
   chunks: ['common', 'list']
}),
new HtmlWebpackPlugin({
   filename: 'detail.html',
   template: './src/detail.html',
   chunks: ['common', 'detail'] //这里是页面中允许加入哪几个js 这里你可以看到require方式的影子
}),


另外就是在入口文件中配置以下就行了。
entry: {
   index: './src/js/index.js',
   list: './src/js/list.js',
   detail: './src/js/detail.js'
},

总结一下


webpack的使用方法就为各位总结到这里啦,极简系列的文章都是龙哥总结的干货。最重要一点讲究即插即用,你完全可以复制本文中的代码到项目中,立刻对你的推广单页或者本地项目做一个优化—webpack可以做的事情远不止我本文中介绍的那些,本文只是介绍使用方法和原理,更多高级玩法还是需要你自己去开发,加油!

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