webpack使用总结

作者: iceman_dev | 来源:发表于2017-02-11 18:11 被阅读3178次

    前言:

    学习webpack的时候,看过它的官网,发现非常难懂,各种内容编排的很乱,并且挺生涩难懂的,和React Native等项目的官网比起来,差太多了,所以如果刚开始接触webpack的话,不建议直接去其官网看。

    一、webpack介绍

    1.1、什么是webpack

    webpack是一个module bundler(模块打包工具),所谓的模块就是在平时的前端开发中,用到一些静态资源,如JavaScript、CSS、图片等文件,webpack就将这些静态资源文件称之为模块。

    webpack支持AMD和CommonJS,以及其他的一些模块系统,并且兼容多种JS书写规范,可以处理模块间的以来关系,所以具有更强大的JS模块化的功能,它能对静态资源进行统一的管理以及打包发布,在官网中用这张图片介绍:

    webpack官网的介绍.png

    它在很多地方都能替代Grunt和Gulp,因为它能够编译打包CSS,做CSS预处理,对JS的方言进行编译,打包图片,代码压缩等等。所以在我接触了webpack之后,就不太想用gulp了。

    1.2、为什么使用webpack

    在自己的学习使用中、和技术交流群里以及和朋友的讨论、网上其他大神的博客中得到一些为什么要使用webpack的原因,webpack的优点,webpack更适用于哪里。

    • 对 CommonJS 、AMD 、ES6的语法做了兼容;

    • 对js、css、图片等资源文件都支持打包;

    • 串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、ES6的支持;

    • 有独立的配置文件webpack.config.js;

    • 可以将代码切割成不同的chunk,实现按需加载,降低了初始化时间;

    • 支持 SourceUrls 和 SourceMaps,易于调试;

    • 具有强大的Plugin接口,大多是内部插件,使用起来比较灵活;

    • webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快;

    webpack最常用与spa应用,主要是vue和React,其实它就非常像Browserify,但是将应用打包为多个文件。如果单页面应用有多个页面,那么用户只从下载对应页面的代码. 当他么访问到另一个页面, 他们不需要重新下载通用的代码。

    webpack也能用于服务端,但是构建后端代码一般都不会用webpack,坑太多了,所以正常情况下只用于前端,这是一个做了很多年前端的朋友告诉我的经验,所以别人已经走过的坑,还是不要去踩了~~~~ 并且我个人觉得后端其实也没必要这么做,因为后端更多的是处理逻辑,以及为前端提供数据.....

    二、基本使用

    2.1、webpack基本运行

    2.1.1、创建基本项目结构

    基本项目结构.png
    基本项目结构.png

    2.1.2、安装全局依赖:

    npm  install  webpack  -g 
    

    2.1.3、创建配置文件

    在项目的根目录创建三个或多个webpack配置文件,我们创建两个:

    • webpack.dev.config.js → 开发环境中用到的配置文件
    • webpack.pub.config.js → 生产环境中用到的配置文件


      添加webpack配置文件.png

    2.1.4、修改配置文件

    注意:开发环境和生产环境的配置是不一样的,具体配置上的差异看后面的内容。

    首先先配置开发环境,写上最基本的内容:

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

    最基本的配置文件中一般含有文件入口和输出文件的配置信息,后期还可以加上loader和各种插件配置使用。

    2.1.5、通过配置文件运行webpack

    • 在根目录运行webpack命令,默认会去查找名称为webpack.config.js的文件执行,如果没有就会报配置信息没有配置的错误。
    webpack
    

    由于我们是将开发环境和发布环境分开的,并没有直接添加webpack.config.js,所以这种方式在我们这里显然是不行的;

    • 通过运行下面的命令进行配置文件的选择
    webpack --config webpack.dev.config.js
    

    命令行输出如下:

    zhongfabindeMacBook-Pro:webpack_test zhongfabin$ webpack --config webpack.dev.config.js
    Hash: d8151fcc7a02add3ec93
    Version: webpack 2.2.1
    Time: 49ms
        Asset     Size  Chunks             Chunk Names
    bundle.js  2.57 kB       0  [emitted]  main
       [0] ./src/js/app.js 63 bytes {0} [built]
    

    在dist中生成了bundle.js:


    生成在dist中的bundle.js.png

    这时候如果想看生成的js是否能用,我们需要将src中的拷贝一份到dist中,并且引入bundle.js(后面可以自动生成index,现在后没学到):


    手动加入index.html.png
    运行效果如下:
    运行效果.png

    注意:在实际的开发中,我们基本上不会用以上这种直接提供的命令,因为用这种方式,我们需要手动的敲打很多字母,在实际的开发中通用的方法都是使用配置文件的方式运行(接下来讲解)。

    2.2、把运行命令配置到npm的script中

    2.2.1、为什么加入到npm的script中

    • npm 是一个非常好用的用来编译的指令,通过 npm 你可以不用去担心项目中使用了什么技术,你只要调用这个指令就可以了,只要你在 package.json 中设置 scripts 的值就可以了。

    • 真正开发的时候你的webpack的命令会敲很长,因为有很多命令需要设置,即便你用了配置文件的方式,但一些--colors --hot这些命令是没法在配置文件中配置的。比如:

    webpack-dev-server --devtool eval --progress --colors --hot --content-base build
    

    所以我们不可能每次都敲这么长,因而我们就把这一大串配置到npm中

    2.2.2、使用步骤

    • 安装webpack,注意:这时候不是全局安装
    npm install --save-dev webpack 
    
    • 配置npm的package.json文件
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev":"webpack --config webpack.dev.config.js",
        "pub":"webpack --config webpack.pub.config.js"
    },
    
    • 在根目录下执行命令
    npm run dev
    

    这样之后就不要敲那么复杂的命令了。

    2.3、为发布目录启动服务

    我们没修改一次就要需要输入 npm run develop 是一件非常无聊的事情,幸运的是,我们可以把让他自己运行,那就是使用webpack-dev-server。

    除了提供模块打包功能,Webpack还提供了一个基于Node.js Express框架的开发服务器,它是一个静态资源Web服务器,对于简单静态页面或者仅依赖于独立服务的前端页面,都可以直接使用这个开发服务器进行开发。在开发过程中,开发服务器会监听每一个文件的变化,进行实时打包,并且可以推送通知前端页面代码发生了变化,从而可以实现页面的自动刷新。

    使用步骤:

    • 安装webpack-dev-server
    npm install --save-dev webpack-dev-server
    
    • 调整npm的package.json中scripts 部分开发命令的配置
    {
        "scripts": {
            "test": "echo \"Error: no test specified\" && exit 1",
            "pub": "webpack --config webpack.pub.config.js",
            "dev": "webpack-dev-server  --config webpack.dev.config.js --devtool eval --progress --colors --hot --content-base src"
        }
    }
    

    在dev的配置中做了以上改变之后,webpack-dev-server 会在 localhost:8080 建立一个 Web 服务器。
    几个参数的解释:

    • --devtool eval:为你的代码创建源地址。当有任何报错的时候可以让你更加精确地定位到文件和行号
    • --progress:显示合并代码进度
    • --colors -- hot:命令行中显示颜色
    • --content-base 指向设置的输出目录
    • 手动访问 http://localhost:8080
      简单来说,当你运行 npm run develop 的时候,webpack会帮你会启动一个 Web 服务器,然后监听文件修改,然后自动重新合并你的代码。真的非常简洁。

    • 注意点

      • 用webpack-dev-server生成bundle.js文件是在内存中的,并没有实际生成;
      • 如果引用的文件夹中已经有bundle.js就不会自动刷新了,你需要先把bundle.js文件手动删除(后期有插件可以完成);
      • 用webstorm的同学注意了,因为webstorm是自动保存的,所以可能识别的比较慢,你需要手动的ctrl+s一下;
    • 几个报错

      • webpack版本的问题
        如果webpack使用的1.x的版本,那么webpack-dev-server也要使用1.x的版本,否则会报如下错误:Connot find module 'webpack/bin/config-yargs'。


        webpack版本引起的报错.png
      • 端口占用问题
        如果已经有一个工程中使用了webpack-dev-server,并且在运行中,没有关掉的话,那么8080端口就被占用了,此时如果在另一个工程中使用webpack-dev-server就会报错:Error: listen EADDRINUSE 127.0.0.1:8080。


        端口占用错误.png

    2.4、浏览器自动刷新

    做完以上的所有步骤之后,可以启动一个服务并监听变化了,但是浏览器你还需要手动刷新一下,我们其实是可以通过下面的这个方法让它自动刷新的。

    修改配置文件中的entry部分,当前entry的的值为:

    entry:path.resolve(__dirname,'src/js/app.js')
    

    将entry的值改为一个数组,除了上面的内容加进去之外,再加其他两句:

    var path = require('path');
    module.exports = {
        entry: [
            'webpack/hot/dev-server',
            'webpack-dev-server/client?http://localhost:8080',
            path.resolve(__dirname,'src/js/app.js')
        ],
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: 'bundle.js'
        }
    }
    

    特别注意:此时用webpack-dev-server生成bundle.js文件是在内存中的,所以在src中的index引入的js文件应该生成的bundle.js,如果还是引入的app.js的话,将会看不到刷新的效果。

    修改js文件.png

    三、常用的加载器

    加载器就是webpack准备的一些预处理工具,比如编译jsx和es6的加载器,处理sass等....

    使用加载器的步骤也很简单,首先是安装依赖,然后在配置文件的module中加一个字段module字段,在module写上loaders,在loaders中写上相应的配置。

    3.1、编译jsx和ES6到原生js

    • 安装以下的依赖
    npm install --save-dev babel-loader babel-core babel-preset-es2015  babel-preset-react 
    
    • 修改开发配置文件
    module: {
        loaders: [
            {
                test: /\.jsx?$/, // 用正则来匹配文件路径,这段意思是匹配 js 或者 jsx
                loader: 'babel',// 加载模块 "babel" 是 "babel-loader" 的缩写
                query: {
                    presets: ['es2015', 'react']
                }
            }
        ]
    }
    
    • 使用
      直接从新运行npm run dev即可

    3.2、加载CSS

    Webpack允许像加载任何代码一样加载 CSS。你可以选择你所需要的方式,但是你可以为每个组件把所有你的 CSS 加载到入口主文件中来做任何事情。

    加载 CSS 需要 css-loader 和 style-loader,他们做两件不同的事情,css-loader会遍历 CSS 文件,然后找到 url() 表达式然后处理他们,style-loader 会把原来的 CSS 代码插入页面中的一个 style 标签中。

    • 首先下载依赖
    npm install --save-dev css-loader   style-loader
    
    • 修改配置文件,在loaders中加上
    {
        test: /\.css$/,
        loader: 'style!css' // 如果有多个加载器,中间用感叹号隔开,多个加载器从右往左执行
    }
    

    “!”用来定义loader的串联关系,"-loader"是可以省略不写的,多个loader之间用“!”连接起来

    • CSS的加载策略
      • 在你的主入口文件中,比如 src/app.js 你可以为整个项目加载所有的 CSS
    import  './project-styles.css';
    
    • 懒加载(推荐使用)
      如果你想发挥应用中多重入口文件的优势,你可以在每个入口点包含各自的 CSS。
      你把你的模块用文件夹分离,每个文件夹有各自的 CSS 和 JavaScript 文件。再次,当应用发布的时候,导入的 CSS 已经加载到每个入口文件中。


      引入CSS.png
    • 使用内联样式取代 CSS 文件
      在 “React Native” 中你不再需要使用任何 CSS 文件,你只需要使用 style 属性,可以把你的 CSS 定义成一个对象,那样就可以根据你的项目重新来考虑你的 CSS 策略。


      内联样式.png

    3.3、加载sass

    • 下载依赖
    npm  install  --save-dev  sass-loader
    
    • 修改配置文件
    {
        test: /\.scss$/,
        loader: 'style!css!sass'
    }
    
    • 使用和导入和CSS的使用方式一致

    3.4、图片处理

    直到 HTTP/2 你才能在应用加载的时候避免设置太多 HTTP 请求。根据浏览器不同你必须设置你的并行请求数,如果你在你的 CSS 中加载了太多图片的话,可以自动把这些图片转成 BASE64 字符串然后内联到 CSS 里来降低必要的请求数,这个方法取决与你的图片大小。你需要为你的应用平衡下载的大小和下载的数量,不过 Webpack 可以让这个平衡十分轻松适应。

    • 下载依赖
    npm  install  --save-dev url-loader file-loader
    
    • 修改配置文件
    {
        test: /\.(png|jpeg|gif|jpg)$/,
        loader: 'url?limit=25000'
    }
    

    加载器会把需要转换的路径变成 BASE64 字符串,在其他的 Webpack 书中提到的这方面会把你 CSS 中的 “url()” 像其他 require 或者 import 来处理。意味着如果我们可以通过它来处理我们的图片文件。
    url-loader 传入的 limit 参数是告诉它图片如果不大于 25KB 的话要自动在它从属的 css 文件中转成 BASE64 字符串。

    • 大图片处理
      在代码中的情况是以下之一:
    div.img{
        background: url(../image/xxx.jpg)
    }
    //或者
    var img = document.createElement("img");
    img.src = require("../image/xxx.jpg");
    document.body.appendChild(img);
    

    你可以这样配置:

    {
        test: /\.(png|jpeg|gif|jpg)$/,
        loader: 'file-loader?name=images/[name].[ext]'
    }
    

    针对上面的两种使用方式,loader可以自动识别并处理。根据loader中的设置,webpack会将小于指点大小的文件转化成 base64 格式的 dataUrl,其他图片会做适当的压缩并存放在指定目录中。

    四、发布配置

    前面一直都在捣鼓config webpack.dev.config.js,也就是一致都在配置开发环境,现在重要配置发布环境了,也就是配置config webpack.pub.config.js,其实发布的配置和开发的配置差不了太多。

    4.1、基础配置

    • 修改npm的package.json文件
      其实相关的配置早就加上去了,就是以下的这句:
    "pub": " webpack --config webpack.pub.config.js  -p",
    

    指向生产的配置文件,并且加上了webpack的cli的-p,他会自动做一些优化

    • 修改webpack.pub.config.js文件
      其实将webpack.dev.config.js中的内容拷贝过来即可,然后修改entry中的一些东西。
    var path = require('path');
    module.exports = {
        entry: path.resolve(__dirname, 'src/js/app.js'),
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: 'bundle.js'
        },
        module: {
            loaders: [
                {
                    test: /\.jsx?$/, 
                    loader: 'babel',
                    query: {
                        presets: ['es2015', 'react']
                    }
                },
                {
                    test: /\.css$/, 
                    loader: 'style!css' 
                },
                {
                    test: /\.scss$/,
                    loader: 'style!css!sass'
                },
                {
                    test: /\.(png|jpeg|gif|jpg)$/,
                    loader: 'file-loader?name=images/[name].[ext]'
                },
            ]
        },
    }
    

    可以看到,其实生产环境的配置和开发的配置没有太大的不同,主要是把不需要的东西给去掉了。

    • 直接运行:npm run pub

    4.2、分离应用和第三方

    4.2.1、何时应该分离

    当你的应用依赖其他库尤其是像 React JS 这种大型库的时候,你需要考虑把这些依赖分离出去,这样就能够让用户在你更新应用之后不需要再次下载第三方文件。当满足下面几个情况的时候你就需要这么做了:

    • 当你的第三方的体积达到整个应用的 20% 或者更高的时候

    • 更新应用的时候只会更新很小的一部分

    • 你没有那么关注初始加载时间,不过关注优化那些回访用户在你更新应用之后的体验

    • 通过手机访问的用户比较多

    4.2.2、修改配置文件

    • 在头部引入webpack
    var webpack=require("webpack");
    
    • 修改entry


      修改entry.png
    • 增加plugins


      增加plugins.png
    • 结果:在dist文件夹中生成两个js文件,一个bundle.js,另一个是vendors.js

    五、常用插件介绍

    webpack提供了丰富的组件用来满足不同的需求,当然了我们也可以自行实现一个组件来满足自己的需求。

    plugins: [
         //your plugins list
     ]
    

    5.1、压缩插件

    这个插件是webpack自带的

    // 用webpack压缩代码,可以忽略代码中的警告
    new webpack.optimize.UglifyJsPlugin({
        compress: {
            warnings: false
        }
    }),
    

    5.2、提取CSS插件

    在webpack中编写js文件时,可以通过require的方式引入其他的静态资源,可通过loader对文件自动解析并打包文件。通常会将js 文件打包合并,css文件会在页面的header中嵌入style的方式载入页面。但开发过程中我们并不想将样式打在脚本中,最好可以独立生成css文件,以外链的形式加载。这时extract-text-webpack-plugin插件可以帮我们达到想要的效果。需要使用npm的方式加载插件,然后 参见下面的配置,就可以将js中的css文件提取,并以指定的文件名来进行加载。

    • 安装依赖
    npm install --save-dev extract-text-webpack-plugin
    
    • 使用
    // 可以新建多个抽离样式的文件,这样就可以有多个css文件了。
    new ExtractTextPlugin("app.css"),
    
    plugins: [
        // 可以新建多个抽离样式的文件,这样就可以有多个css文件了。
        new ExtractTextPlugin("app.css"),
    ]
    

    修改loaders中的配置:

    {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style-loader' , 'css-loader')
    },
    

    注意:我发现这个有一个问题,就是他只能把css抽出来,但是sass的样式不能分离出来。

    5.3、新建index.html页面插件

    • 安装依赖
    npm install --save-dev html-webpack-plugin 
    
    • 使用
    // 自动生成index.html页面插件
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/template.html',
            htmlWebpackPlugin: {
                "files": {
                    "css": ["app.css"],
                    "js": ["vendors.js","bundle.js"]
                }
            },
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeAttributeQuotes: true
            }
        }),
    ]
    

    创建模板文件:template.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="keyword" content="webpack,gulp,git">
        <title>model</title>
    </head>
    <body>
    <div id="app"></div>
    </body>
    </html>
    

    5.4、自动打开浏览器插件

    在开发环境中使用,run之后自动打开浏览器

    • 安装依赖
    npm install --save-dev open-browser-webpack-plugin
    
    • 使用
    // 自动打开浏览器插件
    var OpenBrowserPlugin = require('open-browser-webpack-plugin');
    
    plugins: [
        new OpenBrowserPlugin({url: 'http://localhost:8080/'})
    ]
    

    5.5、删除插件

    在开发环境中使用,run之后自动打开浏览器

    • 安装依赖
    npm install --save-dev clean-webpack-plugin
    
    • 使用
    // 删除文件夹
    var CleanPlugin = require('clean-webpack-plugin');
    
    plugins: [
        // 构建之前先删除dist目录下面的文件夹
        new CleanPlugin(['dist']),
    ]
    

    5.6、去掉react中的警告

    plugins: [
        new webpack.DefinePlugin({
            //去掉react中的警告,react会自己判断
            'process.env': {
                NODE_ENV: '"production"'
            }
        }),
    ]
    

    个人公众号(icemanFE):分享更多的前端技术和生活感悟

    个人公众号.png

    相关文章

      网友评论

      • d270297d9f08:webpack入门教程:http://t.cn/R9fQvdo
      • 149ec0c91c5b:求问一下:
        webpack版本的问题
        如果webpack使用的1.x的版本,那么webpack-dev-server也要使用1.x的版本,否则会报如下错误:Connot find module 'webpack/bin/config-yargs'。
        这时候,应该怎么解决呢?:cold_sweat:
        sicun:楼主, 能给个demo的git地址不
        149ec0c91c5b:@iceman_dev 哦哦,之前那个解决了,谢啦,后来我安装npm install --save-dev extract-text-webpack-plugin的时候,
        +-- extract-text-webpack-plugin@1.0.1
        `-- UNMET PEER DEPENDENCY webpack@2.2.1
        报这个,
        然后我npm list的时候,看到
        npm ERR! peer dep missing: webpack@^1.9.11, required by extract-text-webpack-plu
        gin@1.0.1
        好纳闷。。。我现在版本是2.2.1,最新的。。。
        不知道你有没有遇到过这个问题呢、
        iceman_dev:@空晓_0182 就是版本一致就好了呀
      • 72c36fd38acf:好多错别字~
        iceman_dev:@72c36fd38acf 谢谢指出,一定改正,
      • Nic_ofh:楼主能不能最后附上demo呢,实战过程中好多问题!
        Nic_ofh:@iceman_dev 好的
        iceman_dev:@00e7665810d9 好,我整理一下,然后放上来

      本文标题:webpack使用总结

      本文链接:https://www.haomeiwen.com/subject/rfdnittx.html