• webpack配置实践


    首先我们的需求:

    • 打包调试
    • 提取公共代码
    • 压缩
    • 热替换

    1.打包调试

    第一步,我们在目标文件夹下安装webpack(假设已有package.json)
    npm i webpack@ -g
    cnpm i webpack@ --save-dev
    (这里推荐大家安装稳定的2.x版本)

    项目结构如图:


    我们将编写的js代码和样式文件放置在app文件夹内(正常项目开发需要js文件和less文件更规范的组织文件结构,此处仅为演示方便)。

    第二步,我们在目标文件夹下新建webpack.config.js

    module.exports = {
        entry:{
            main:__dirname + '/app/main.js',
        },
        output:{
            path:__dirname + '/public',
            filename:'[name].[id].js',//此格式写法后续会提到为什么
            publicPath:'/public/'
        }
    }

    我们已经完成了webpack最基础的部分:添加了文件的输入和输出。入口是app文件夹内的main.js文件,出口为public文件夹。接下来我们来处理各种文件的解析,就是大名鼎鼎的loader的舞台了。假设我们使用es6less开发,那么我们需要:
    npm i babel-loader babel-core babel-preset-es2015 babel-preset-stage-0 --save-dev

    npm i less less-loader css-loader style-loader --save-dev

    接下来我们只需要在modules字段下把这些loader加进去:

    module.exports = {
        devtool:'cheap-module-eval-source-map',//多种选择,选择最适合自己的
        entry:{
            main:__dirname + '/app/main.js',
        },
        output:{
            path:__dirname + '/public',
            filename:'[name].[id].js',
            publicPath:'/public/'
        },
        module:{
            loaders:[
                {
                    test:/.js$/,  //解析文件类型
                    exclude:/node_modules/,  //排除node_modules文件
                    loader:'babel-loader', //使用哪种loader解析
                    query:{
                        presets:['es2015','stage-0']//loader的配置项,解析es6
                    }
                },
                {
                    test:/.less$/,
                    exclude:/node_modules/,
                    loader:'style-loader!css-loader!less-loader'//顺序为从右向左
                }
            ]
        },
    }

    大功告成!

    如果你在全局安装有webpack的话,可以在终端敲入webpack并回车,几秒钟后,main.js文件已经在public打包出来了!

    之后我们在index.html中引入main.0.js文件,再打开index.html就可以看到效果了。

    以上步骤,我们已经实现了文件的打包调试,但是现在有个问题摆在我们面前:第三方库代码和业务代码打包到了同一个文件main.0.js内,每次更新代码都要更新整个文件。那么接下来我们对代码进行拆分。

    2.提取公共代码

    引入CommonsChunkPlugin插件,在webpack.config.js添加如下内容:

    module.exports = {
        devtool:'cheap-module-eval-source-map',
        entry:{
            main:__dirname + '/app/main.js',
            vendor:'moment'
        },
        output:{
            path:__dirname + '/public',
            filename:'[name].[id].js',
            publicPath:'/public/'
        },
        module:{
            loaders:[
                {
                    test:/.js$/,
                    exclude:/node_modules/,
                    loader:'babel-loader',
                    query:{
                        presets:['es2015','stage-0']
                    }
                },
                {
                    test:/.less$/,
                    exclude:/node_modules/,
                    loader:'style-loader!css-loader!less-loader'
                }
            ]
        },
        plugins:[
                new webpack.optimize.CommonsChunkPlugin({
                    names:['vendor','manifest']
             })
         ]
    }

    我们看到向插件的构造函数传入了两个参数vendormanifest,以及我们在entry也加入了新的入口momentmoment是常用的时间处理的第三方库,我们可以通过npm i moment --save-dev进行安装。而entry处的vendor将成为output字段filename[name]的值,也就是说将打包出main.x.jsvendor.x.js两个文件,main.x.js文件将保存我们的业务代码,vendor.x.js将保存moment的代码,这样我们将公共代码和业务代码进行了初步分离。

    在新添加的CommonmChunkPlugin插件中,我们添加了manifest值,这是为什么呢?如果你不添加这个值,你在打包时会发现,main.x.js有更新,vendor.x.js还是有更新,并未真正实现"分离"。官方文档对此的解释是:

    The issue here is that on every build, webpack generates some webpack runtime code, which helps webpack do it’s job. When there is a single bundle, the runtime code resides in it. But when multiple bundles are generated, the runtime code is extracted into the common module, here the vendor file.

    大致的意思就是说,webpack每次编译时运行的代码会影响到hash值的变化,当只有一个打包文件时这部分代码会塞进去,当有多个打包文件时,这部分代码会进入公共的vendor。所以解决办法是使用manifest字段把这部分代码从vendor中作为一个公共模块抽出来,从而不会影响vendor

    将以上的配置写入webpack.config.js,运行webpack命令,我们发现业务代码和公共库代码成功分离,改写main.1.js文件的内容,再次打包,发现vendor文件并没有变化,成功!

    当我们再进行打包时,发现又会多出了新的main.x.js等文件,打包三次就会出现三个main.x.js文件,此时该怎么办呢?我们可以使用clean-webpack-plugin插件:

    npm i clean-webpack-plugin --save-dev

    然后在webpack.config.js中引入:

        var CleanWebpackPlugin = require('clean-webpack-plugin');
        new CleanWebpackPlugin(
                ['public/main.*.js','public/manifest.*.js'],//要删除的文件目录匹配
                {
                    root:__dirname,
                    verbose:true,
                    dry:false
                }
            ),

    这样我们每次在打包新的代码时,旧文件就会删除,不会再出现同一份文件存在多份的情况。

    3.压缩

    在webpack中,图片,css,js等等其他资源皆可压缩,本文仅以压缩js为例。
    安装插件:
    npm i uglifyjs-webpack-plugin --save-dev

    webpack.config.js中引入:

    var UglifyJsPlugin = require('uglifyjs-webpack-plugin');
    new UglifyJsPlugin({
        beautify:true,
        exclude:['/node_modules/'],
        compress:{
            warnings:false
        },
        output:{
            comments:false
        }
    })

    我们指定了压缩的方法,排除了不需要压缩的node_modules部分,同时我们去除了comments部分(comments为@license等注释,是可观的压缩空间)。再次在终端输入打包命令,可见js打包后的体积有令人满意的减小。

    4.热替换

    webpack总是绕不开热替换的话题。热替换的功能配置和原理是一大话题,三天三夜也说不完,也并非本文重点,本文只提供简易高效的配置方法。

    热替换存在两种使用方式,clinodecli方式无需添加新的热替换插件,且无需在入口处添加webpack-dev-server等入口,故本文采用cli使用方式。

    webpack.config.js中添加devServer字段,加入如下代码:

    devServer:{
        inline:true,
        hot:true
    },

    保存后运行webpack-dev-server --inline --hot --progress,再修改下main.less文件的样式,会发现浏览器并没有刷新,但页面已经发生了变化,我们的热替换功能也成功加入了!

    tips:

    在实际项目打包时,可以将filename字段的值换为[name].[chunkhash].js,其中[chunkhash]为webpack每次打包后给每个模块的标识值,这个值每次打包后都会更换。为什么在此处我们使用[id]呢,因为chunkhash与热替换存在冲突,终端会有报错,那么使用id可以算作一个解决方案。这就引申出另一话题,我们可以使用两套webpack配置分别用于生产环境和开发环境,通过webpack指定config来进行打包。例如我们在开发环境使用id,在生产环境去掉热替换并使用hash的方式。而且,一些压缩插件也没必要在开发环境过度使用,两套配置能让webpack发挥最大的威力。

    另外,chunkhashhash有区别,chunkhash顾名思义是模块的标识,而hash是webpack每次编译的标识值,不同的资源如js和css存在chunkhash解耦的问题,此处不进行过多讨论。

    关于热替换的更多细节和原理,参考文章:http://www.cnblogs.com/wonyun/p/7077296.html

    5.运行

    我们知道,每次打包后,都会有新的main.x.js文件生成,其hash值每次打包后都会发生变化,难道我们的index.html文件需要每次打包后都手动修改main.x.js的路径吗?还好社区提供了html-webpack-plugin插件,可以在已有html模板的条件下自动为我们生成带有最新代码的html文件:

    npm i html-webpack-plugin --save-dev

    webpack.config.js中引入:

    var HtmlWebpackPlugin = require('html-webpack-plugin');
    new HtmlWebpackPlugin({
        title:'demo',
        template:'index.html'
    }),

    在终端运行打包命令,我们看到public文件夹下生成了新的index.html文件:

    以后我们再进行调试时,以本文为例,则需要打开localhost:8080/public/index.html,因为每次webpack的HtmlWebpackPlugin都会把新的js文件加入到这个html文件内。在开发全部完成后,我们可以将js路径写死,添加到原有的index.html文件中。

    以下是我们webpack.config.js全部的配置;

    var webpack = require('webpack');
    var CleanWebpackPlugin = require('clean-webpack-plugin');
    var HtmlWebpackPlugin = require('html-webpack-plugin');
    var UglifyJsPlugin = require('uglifyjs-webpack-plugin');
    
    module.exports = {
        devtool:'cheap-module-eval-source-map',
        entry:{
            main:__dirname + '/app/main.js',
            vendor:'moment'
        },
        output:{
            path:__dirname + '/public',
            filename:'[name].[id].js',
            publicPath:'/public/'
        },
        devServer:{
            inline:true,
            hot:true
        },
        module:{
            loaders:[
                {
                    test:/.js$/,
                    exclude:/node_modules/,
                    loader:'babel-loader',
                    query:{
                        presets:['es2015','stage-0']
                    }
                },
                {
                    test:/.less$/,
                    exclude:/node_modules/,
                    loader:'style-loader!css-loader!less-loader'
                }
            ]
        },
        plugins:[
            new CleanWebpackPlugin(
                ['public/main.*.js','public/manifest.*.js'],
                {
                    root:__dirname,
                    verbose:true,
                    dry:false
                }
            ),
            new webpack.optimize.CommonsChunkPlugin({
                names:['vendor','manifest']
            }),
            new HtmlWebpackPlugin({
                title:'demo',
                template:'index.html'
            }),
            new UglifyJsPlugin({
                beautify:true,
                exclude:['/node_modules/'],
                compress:{
                    warnings:false
                },
                output:{
                    comments:false
                }
            })
        ]
    }

    整个项目,我们在app文件下的main.js内写业务代码,main.less写样式,在public/index.html下使用热替换进行调试,打包后的压缩文件在public文件夹下,并且对业务代码,第三方代码进行了清晰地区分。

    使用这份webpack配置,我们实现了:

    • 工程的打包调试
    • 公共代码提取,提高开发效率
    • 资源压缩
    • 热替换
  • 相关阅读:
    MySQL设计之三范式的理解
    git基本操作命令和安装
    MySQL 中<=>用法(长知识)
    举个栗子看如何做MySQL 内核深度优化
    我们来说一说TCP神奇的40ms
    一览js模块化:从CommonJS到ES6
    Vtiger CRM 几处SQL注入漏洞分析,测试工程师可借鉴
    做优化的数据库工程师请参考!CynosDB的计算层设计优化揭秘
    1个开发如何撑起一个过亿用户的小程序
    教你一个vue小技巧,一般人我不说的
  • 原文地址:https://www.cnblogs.com/axl234/p/7120068.html
Copyright © 2020-2023  润新知