资讯专栏INFORMATION COLUMN

应用层打包——Webpack

stormzhang / 2494人阅读

摘要:应用层打包工具一开始学其实有点逼不得已,作为一个奉行保守主义的人,对于新东西都会有一种观望的心态,这不是重点,我不会告诉你其实是因为我懒,真的是因为在简单的项目上已经足够好用。

应用层打包工具——webpack

一开始学webpack其实有点逼不得已,作为一个奉行保守主义的人,对于新东西都会有一种观望的心态,这不是重点,我不会告诉你其实是因为我懒,真的是因为Gulp在简单的项目上已经足够好用。

Gulp本身只是一个框架,通过安装各种插件,可以实现从监听-打包-合并-压缩-编译一系列流程,管道的概念在使用的过程中跟它的前身Grunt比起来简直舒服太多。(其实我也没怎么用过grunt……真的不是我懒,是因为出生太晚,我开始接触这类工具时Gulp已经流行起来了)

然而,在开始实践组件化开发之后,发现一个有点邪乎的事情:gulp很难处理较为复杂的依赖关系,各组件之间相互引入,写配置文件时会写得万念俱灰。经常哭得把我家狗狗吓出房间……

即便是一个最简单的项目,也需要做出如下的路径配置:

并且,React、Vue、Angular2,这三大MVVM框架都将webpack作为官方推荐的打包工具,虽然还是有点怀念Gulp,但不得不追随神的指引——去跳Webpack的坑。

webpack最早只是作为一个打包工具出现,也就是只操作js代码,但由于它智能寻找依赖的特点,很快插件数量就直追而上,就功能而言,现在基本能够完全取代Gulp,加上基于Express框架开发的webpack-dev-server,让它有了比Gulp家的browser-sync更赞的热模块替换功能,browser-sync在监听到代码修改后会重载代码并刷新页面,而Webpack的热模块替换可以做到在不刷新页面的情况下替换代码。

你没有听错,是在不刷新页面的情况下替换代码

上面说的Webpack可以智能查找依赖,是指:无论有多少个组件导入,它会自己寻找到对应的组件并打包在一起,不需要使用者操心。

如果是Gulp,则需要像上面那样配置一大串路径并且挨个注入监听才行。(怎么注入监听,下面会有例子)

Gulp最得意的莫过于管道式的工作方式,但webpack轻而易举地就做到了,并且书写起来更简洁明了,例如一个最普通的sass打包函数,gulp首先要导入sass编译模块,配置好输入路径和输出路径,还需要将这个函数注入到监听的服务里:

var sass = require("sass");

gulp.task("sass", function() {
    return gulp.src("./src/*.scss")
        .pipe(sass())
        .pipe(gulp.dest("dist/"));
});

其实这很清晰明了,但有个前提,就是你需要知道哪些CSS是你的应用真正用到的,如果项目庞大,那就不得不硬着头皮去维护一个无聊的依赖文件列表,或是干脆包含一整个目录的文件。

举个栗子说清楚一些:假设你在开发时需要用到一张图片,如果开发完成后你忘记把这张图片从开发目录中删除,那恭喜你,即便这张图片没有被任何代码引用,也照样会成功打包进入到生产环境中。

这样一来,很有可能引入一些冗余的代码或者一些静态文件,而且只能寄托命运让你在某一天醍醐灌顶突然发现这张图片并没有被引用。

造成这种隐患的原因是:Gulp是根据路径打包的,不管这个文件有没有用到,只要它的位置在Gulp的处理序列内,它就会处理!而Webpack的巧妙在于,被用到的它才打包,没用到的则是视而不见!这就是按需打包的概念。

此外,还有一处事关体验的地方,Gulp一旦检测到报错信息,就会退出,也就是你写css代码的时候多打了个分号,尽管眼睛看见了,然而身体的反射神经迟钝,手不听使唤按了保存,世界就毁灭了!你只能叹息一声,乖乖把分号删掉,然后回到终端(控制台)重启Gulp服务。

猜猜是谁已经做过无数次这种事……

而Webpack会显示报错信息,但是不会宕机,等你修正了错误之后,它会重新编译。有追求的工具就应该这样!!!

上面列出了Gulp处理sass的代码量,相对来说,webpack就简单多了:

{
  test: /.scss$/,
  use: "style!css!sass"
}

// 不过这么写的话,css最终会被打包到js文件里,如果想将css多带带打包出来,还需要安装插件,最终写成下面这样

const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports = {
    module: {
        ...
        rules: [
            {
                test: /.scss$/,
                use: ExtractTextPlugin.extract({
                    fallbackLoader: "style-loader",
                    loader: "css-loader!sass-loader"
                })
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin("./[name].css")
    ]
};

悲催,这好像比Gulp的代码量更多……

不!!以上看到的都是表面现象!!

不信来份真的比较一下!

Gulp先来!
var gulp        = require("gulp");
var browserSync = require("browser-sync").create();
var sass        = require("gulp-sass");
var prefix      = require("gulp-autoprefixer");
var cssmin      = require("gulp-clean-css");
var htmlmin     = require("gulp-htmlmin");
var imagemin    = require("gulp-imagemin");
var jsmin       = require("gulp-uglify");
var rename      = require("gulp-rename");
var reload      = browserSync.reload;

var Asset = {       // 配置监听路径
    html: "./src/html/*.html",
    js: "./src/js/*.js",
    sass: "./src/sass/*.scss",
    img: "./src/images/*"
}

// 启动静态服务器
gulp.task("server", function() {
    browserSync.init({
        server: "."
    });
});

gulp.task("html", function() {      // html代码的处理模块
  gulp.src(Asset.html)
    .pipe(htmlmin({collapseWhitespace: true}))
    .pipe(gulp.dest("dist/"));
});

gulp.task("img", function() {       // 图片的处理模块,负责压缩图片什么的
    return gulp.src(Asset.img)
        .pipe(imagemin({optimizationLevel: 7}))
        .pipe(gulp.dest("dist/images/"));
});

gulp.task("js", function() {        // js的处理模块
  return gulp.src(Asset.js)
    .pipe(jsmin())
    .pipe(rename({suffix: ".min"}))
    .pipe(gulp.dest("dist/"));
});

gulp.task("sass", function() {      // sass处理模块
    return gulp.src(Asset.sass)
        .pipe(sass())
        .pipe(prefix())
        .pipe(rename({suffix: ".min"}))
        .pipe(cssmin())
        .pipe(gulp.dest("dist/"))
        .pipe(reload({stream: true}));
});
gulp.task("watch", function() {     // 监听服务
    gulp.watch(Asset.sass, ["sass"], reload);
    gulp.watch(Asset.js, ["js"], reload);
    gulp.watch(Asset.html, ["html"], reload);
    gulp.watch(Asset.img, ["img"], reload);
    gulp.watch("*").on("change", reload);
    gulp.watch("./dist/**/*.*").on("change", reload);
});

// 启动
gulp.task("default", ["sass", "img", "html", "js", "server", "watch"]);

那些中括号里面的东东就是注入

这里说的注入跟Angular的依赖注入概念基本一样!注入这个概念理解起来可能比较困难,换一个词,应该叫反转,概念是这样的:一般的函数形参个数都……

呃……不跑题哈~

然后是Webpack选手
const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
    context: __dirname + "/src",
    entry: {
        index: "./js/index.js"
    },
    output: {
        filename: "[name].bundle.js",
        path: __dirname + "/dist"
    },
    module: {
        rules: [
            {
                test: /.scss$/,
                use: ExtractTextPlugin.extract({
                    fallbackLoader: "style-loader",
                    loader: "css-loader!sass-loader"
                })
            },

            {
              test: /.html$/,
              use: "html-withimg-loader"
            },
            {
              test: /.(png|jpg)$/,
              use: "url-loader?limit=8192&name=images/[name].[ext]"
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin("./[name].css"),
        new HtmlWebpackPlugin({
            template: "./html/index.html",
            filename: "./index.html",
            chunks: ["index"]
        })
    ]
};

以上两份配置文件完成的是差不多的工作,代码量……

呃……其实也就是半斤八两,别天真了,成熟一点:少写几行代码并不能体现出什么优越性……

那么从这里开始,态度要转弯了……

上面说了,文件较多的时候,配置Gulp的各种路径会万念俱灰,那么……配置Webpack的时候会比万念俱灰更加万念俱灰,跟webpack相比,Gulp倒是显得挺傻瓜。其实,单纯比较代码量的话,Webpack配置文件的代码量确实是少些,然而Webpack太过于博大精深,要理解它需要付出不少努力。

学了Webpack是不是就能召唤神龙?

No!!经由Webpack打包出来的代码可读性很差,尽管很少人会闲着没事去读打包后的代码,但前端近几年迭代太快,有人诟病就会有人创新,号称下一代打包工具的Rollup已经在崛起,它进一步升级了“按需打包”的概念,只是各类插件尚不成熟,因此就目前来看,将Webpack用作应用层的打包还是最合适的。

等我跳了Rollup的坑再来跟各位介绍~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82055.html

相关文章

  • webpack多页应用架构系列(三):怎么打包公共代码才能避免重复?

    摘要:在上一篇文章多页应用架构系列二配置常用部分有哪些中,我介绍了如何配置多页应用的入口,然而,如果仅仅如此操作,带来的后果就是,打包生成出来的每一个入口文件都会完整包含所有代码。的初始化常用参数有哪些,给这个包含公共代码的命个名唯一标识。 本文首发于Array_Huang的技术博客——实用至上,非经作者同意,请勿转载。原文地址:https://segmentfault.com/a/1190...

    oliverhuang 评论0 收藏0
  • webpack多页应用架构系列(十一):预打包Dll,实现webpack音速编译

    摘要:本文首发于的技术博客实用至上,非经作者同意,请勿转载。原文地址如果您对本系列文章感兴趣,欢迎关注订阅这里前言书承上文多页应用架构系列十如何打造一个自定义的。终于,发现了这一大杀器,打包时间过长的问题得到完美解决。 本文首发于Array_Huang的技术博客——实用至上,非经作者同意,请勿转载。原文地址:https://segmentfault.com/a/119000000710437...

    sixleaves 评论0 收藏0
  • webpack多页应用

    本文主要讲了webpack怎么搭建多页应用,熟悉下webpack的基本用法。 新建文件夹,目录结构如下: showImg(https://segmentfault.com/img/bV6NnK?w=169&h=145); 然后 cd webpack-test npm init(根目录下创建了一个pakage.json) npm install webpack@1.15.0 --save-dev(...

    Pocher 评论0 收藏0
  • 什么是 Webpack?【Webpack Book 翻译】

    摘要:资源哈希编码使用可以为每个包的名称注入一个哈希值例如,,以便在版本更新后使客户端上旧版本的包无效重新下载。如此受人喜爱的原因之一是热模块更换。可以为文件名生成哈希值,在内容更改时,可以作废浏览器缓存中上个版本的包。 原文链接:https://survivejs.com/webpack...翻译计划:https://segmentfault.com/a/11... 涉及到的未翻译单词 ...

    tainzhi 评论0 收藏0
  • 前端构建_webpack

    摘要:一个文件,一张图片一个文件都是一个模块,都能用导入模块的语法的,的导入进来。自身只能读懂类型的文件,其它的都不认识。 webpack 是什么? webpack是一个前端模块化打包工具指(由于模块化开发,所以需要打包,这里所说的模块化开发主要指JS) 由于现代前端应用程序越来越复杂,需要采用模块化进行开发,但浏览器还未支持模块化开发,所以webpack才诞生 webpack默认只支持js...

    ethernet 评论0 收藏0

发表评论

0条评论

stormzhang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<