webpack介绍(翻译)

前端自动化

  • 您需要跟踪文件应该加载的正确顺序,包括哪些文件依赖于哪些其他文件,并确保不包含您不需要的任何文件。
  • 过多的 <script> 会增多网络需求
  • 这些都可以自动化

为什么要使用webpack

  • 新工具具有很多新特性,避免了一些前辈的问题
  • 使用简单,如果仅用来打包js文件不使其他花哨的东西,甚至不用过多的配置
  • 插件系统完善,你可以作为工具使用它

开始使用

  • npm init
  • npm install webpack -D / -D 意味这作为依赖安装,相当于 --save-dev
  • npm install lodash -S / -S 意味着--save
  • main.js
var map=require("lodash/map");
var square=function(n){
    return n*n
}
console.log(map([1,2,3,4,5,6], square));
  • node main.js

如何使用webpack来打包呢?下面循序渐进的为大家介绍

1. 使用webpack命令行

开始使用webpack而不浪费时间在配置文件上的最简单的方法就是从命令行运行它。 无需使用配置文件的webpack命令的最简单版本就是输入文件路径和输出文件路径。 Webpack将从该输入文件中读取,跟踪其依赖关系树,将所有文件合并到一个文件中,并将文件输出到您指定为输出路径的位置。 对于这个例子,我们的输入路径是main.js,我们要将捆绑的文件输出到bundle.js。 所以,让我们创建一个npm脚本来做到这一点(我们没有在全球安装webpack,所以我们不能直接从命令行运行它)。 在package.json中,编辑<script>部分,如下所示:

  "scripts": {
    "build": "webpack src/main.js dist/bundle.js",
  }

在探索webpack之前,我们再来一遍,通过在重建之前删除dist目录及其内容,并添加一些脚本来执行我们的bundle,让我们的构建脚本变得更加专业。 我们需要做的第一件事是安装del-cli,以便我们可以删除目录,而不会使不使用与我们相同的操作系统的人员(不要因为使用Windows而讨厌我); npm安装del-cli -D应该做的伎俩。 然后,我们将将npm脚本更新为以下内容:

scripts": {
    "prebuild": "del-cli dist -f",
    "build": "webpack src/main.js dist/bundle.js",
    "execute": "node dist/bundle.js",
    "start": "npm run build -s && npm run execute -s"
  }

我们保持build与以前一样,但现在我们有prebuild来做一些清理,这将在build之前运行,每次build被告知运行。 我们还有execute,它使用Node.js来执行捆绑的脚本,我们可以使用start使用一个命令来完成所有操作(-s位只是使npm脚本不输出为 无用的东西到控制台)。 继续运行npm开始。 您应该看到webpack的输出,快速跟随我们的平方阵列,显示在您的控制台。 恭喜! 刚刚完成了我之前提到的存储库的example1分支中的所有内容。

2. 使用配置的webpack

与使用webpack命令行一样有趣,一旦你开始使用更多的webpack的功能,你将要远离传递所有的选项通过命令行,而是使用一个配置文件 ,这将具有更多的能力,但由于它是用JavaScript编写的,它们也将更加易读。
所以,我们来创建一个配置文件。 在项目的根目录中创建名为webpack.config.js的新文件。 这是默认情况下webpack将要查找的文件名,但如果要将配置文件命名为其他目录或将其放在不同的目录中,则可以将--config [filename]选项传递给webpack。
对于本教程,我们将使用标准文件名,现在我们将尝试使其工作方式与使用命令行一样。 为此,我们需要将以下代码添加到配置文件中:

module.exports = {
    entry: './src/main.js',
    output: {
        path: './dist',
        filename: 'bundle.js'
    }
};

3. 学习使用loader

使用webpack处理文件有两种方式,loader或者插件,先讨论loader,loader被用来转换或者操作文件指定类型。我们可以对一个文件使用多个loader,例如我们可以先对一个文件进行Eslint操作之后用Babel把他转化为ES5,如果ESLint给出警告,竟会打印出警告信息,如果报错,就不会继续运行后面的loader。
下面用ES2015语法来下写main2.js

import { map } from 'lodash';

console.log(map([1,2,3,4,5,6], n => n*n));

上面代码运用ES2015写法,用了import 代替 require (import {map} from loadsh 这样写会把整个loadsh引入,当然也可以用 import map from 'lodash/map) ;用箭头函数代替了function。这些都是ES2015语法

我们需要编译使之在一些老旧浏览器中运行良好,为此我们需要使用Babel和webpack来运行编译。
需要的loader:

  1. babel-core(Babel 核心功能,完成大部分工作)
  2. babel-loader(webpack提供的和babel-core的接口)
  3. babel-preset-es2015(告诉babeles2015编译为ES5的规则)
  4. babel-plugin-transform-runtime , babel-polyfill(这两者都改变​​了Babel向您的代码库添加polyfills和helper函数的方式,尽管它们有所不同,因此它们适合于不同类型的项目。)
    安装这些包,然后更新webpack.config.js代码
module.exports = {
    entry: './src/main.js',
    output: {
        path: './dist',
        filename: 'bundle.js'
    },
    module: {
        rules: [
            …
        ]
    }
};

我们看到增加了module,module下两个有一个rules属性,这是一个数组,对于每组rule,我们设置两个选项testloader.

  1. test用来测试文件类型,通常是一个正则表达式,例如/\.js$/就是以js结尾的文件名,/\.jsx?$/匹配以js或jsx结尾的文件.
  2. loader用来指定运用哪些loader处理匹配到的文件。通过传入带有加载器名称的字符串来指定,用!分隔。例如babel-loader!eslint-loader,webpack从右向做开始编译,先经过eslint再经过babel-loader,如果loader有特殊选项你想指定,你可以使用babel-loader?fakeoption=true!eslint-loader这种形式,用option形式。
module:{
    rules:[
        {
            test:/\.jsx?$/,
            loader:'babel-core',
            exclude: /node_modules/,
            option:{
                plugins: ['transform-runtime'],
                presets: ['es2015']  
            }
        }
    ]
}

我们需要设置预设,使所有的ES2015功能都将转换为ES5,我们还将设置使用我们安装的转换运行时插件。如前所述,这个插件是没有必要的,但它在那里告诉你如何做到这一点。另一种方法是使用.babelrc文件来设置这些选项,但是我无法向您展示如何在webpack中执行此操作。一般来说,我建议使用.babelrc,但我们将在此项目中保留配置。exclude文件排除了node_modules文件夹.

4. 使用 Handlebars loader

使用handlebars模板的loader,仅仅举个例子

  1. 安装handlebars以及他的loadercnpm install handlebars handlebars-loader -D
  2. import template from 'handlebars-loader!./numberlist.hbs或者使用loader{ test: /\.hbs$/, loader: 'handlebars-loader' }.
  3. 使用npm start就会打印出li标签

5. 学习使用插件

除了loader之外,插件是将自定义功能安装到Webpack中。您可以自由地将它们添加到Webpack工作流程中,因为它们不仅限于在加载特定文件类型时被使用;它们几乎可以在任何地方注入,因此能够做得更多.下面举两个关于插件的例子.

  1. HTML Webpack Plugin
    1. npm i http-server html-webpack-plugin -D
    2. package.json
"scripts": {
    "prebuild": "del-cli dist -f",
    "build": "webpack",
    "server": "http-server ./dist",
    "start": "npm run build -s && npm run server -s"
},
3. webpack.config.js
const path = require('path');
var HtmlWebpackPlugin=require("html-webpack-plugin")
module.exports = {
    entry: [
    'babel-polyfill',
    './src/main.js'
    ],
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: 'bundle.js'
    },
    module:{
        rules:[
            {
                test:/\.jsx?$/,
                loader:'babel-loader',
                exclude: /node_modules/,
                options:{
                    plugins: ['transform-runtime'],
                    presets: ['es2015']  
                }
            },
            { 
                test: /\.hbs$/, 
                loader: 'handlebars-loader'
             }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin()
    ]
};

我们所做的两个更改是将新安装的插件导入文件的顶部,然后在配置对象的末尾添加一个plugins,我们在这个插件中传入新实例。
在这一点上,我们没有将任何选项传递给插件,所以它使用的标准模板不包括很多,但它包含了我们的捆绑脚本。如果您运行npm启动,然后访问浏览器中的URL,您将看到一个空白页面,但是如果您打开开发人员的工具,则应该会将HTML输出到控制台。

我们不应让其只从控制台输出,应该让他出现在HTML中,在src下新建index.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
    <h2>This is my Index.html Template</h2>
    <div id="app-container"></div>
</body>
</html>

注意我们通过向ejs文件传递插件中参数
没有指定应该添加脚本的位置。这是因为默认情况下,该插件会将脚本添加到body标签的末尾。

webpack.config.js中增加下面选项

 plugins: [
        new HtmlwebpackPlugin({
            title: 'Intro to webpack',
            template: 'src/index.html'
        })
    ]

我在尝试按照上面例子写demo的时候发现并不能将hbs模板插入到html中不知道为啥子.
我知道为啥子了,window.onload!!!

6. 使用懒加载

有一件事我非常喜欢与RequireJS,不能很好地使用Browserify(尽管可能)是懒惰加载模块。一个大规模的JavaScript文件将有助于限制所需的HTTP请求数量,但实际上保证下载的代码不一定在该会话中被访问者使用。
Webpack有一种方法可以将捆绑分割成可以进行延迟加载的大块,甚至不需要任何配置。所有你需要做的是以两种方式之一编写代码,webpack将处理其余的代码。 Webpack为您提供了两种方法:一种基于CommonJS,另一种基于AMD。要使用CommonJS来懒惰加载模块,你可以这样写:

require.ensure(["module-a", "module-b"], function(require) {
    var a = require("module-a");
    var b = require("module-b");
    // …
});

使用require.ensure,这将确保模块可用(但不执行),并传递一个模块名称数组,然后传回一个回调。要在该回调中实际使用该模块,您需要使用传递给回调的参数来明确地要求它。

AMD版本

require(["module-a", "module-b"], function(a, b) {
    // …
});
import { map } from 'lodash';

let numbers = map([1,2,3,4,5,6], n => n*n);

setTimeout( () => {
    require(['./numberlist.hbs'], template => {
        document.getElementById("app-container").innerHTML = template({numbers});
    })
}, 2000);

现在,如果您运行npm start,您将看到生成另一个文件,它应该命名为1.bundle.js。如果您在浏览器中打开页面并打开您的开发工具来观看网络流量,您会看到延迟2秒后,新文件将被加载并执行。这并不是很难实现,可以使用户的体验好多了。
请注意,这些子包或块包含其所有依赖关系,除了每个子包中包含的子包。 (您可以有多个条目,每个条目都延迟加载此块,因此,每个父项都加载不同的依赖项。)

7. Creating A Vendor Chunk

我们来谈一谈可以做的一个优化:wendor。你可以定义要构建的单独的包,该包将存储不太可能更改的“常用”或第三方代码。这允许访问者将库从应用程序代码缓存在一个单独的文件中,以便在更新应用程序时不需要再次下载这些库。
为此,我们将使用一个名为CommonsChunkPlugin的webpack附带的插件。它被包含,我们不需要安装任何东西;我们需要做的是对webpack.config.js进行一些编辑

var HtmlwebpackPlugin = require('html-webpack-plugin');
var UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');

module.exports = {
    entry: {
        vendor: ['babel-polyfill', 'lodash'],
        main: './src/main.js'
    },
    output: {
        path: './dist',
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/, loader: 'babel-loader', exclude: /node_modules/,
                options: { plugins: ['transform-runtime'], presets: ['es2015'] }
            },
            { test: /\.hbs$/, loader: 'handlebars-loader' }
        ]
    },
    plugins: [
        new HtmlwebpackPlugin({
            title: 'Intro to webpack',
            template: 'src/index.html'
        }),
        new UglifyJsPlugin({
            beautify: false,
            mangle: { screw_ie8 : true },
            compress: { screw_ie8: true, warnings: false },
            comments: false
        }),
        new CommonsChunkPlugin({
            name: "vendor",
            filename: "vendor.bundle.js"
        })
    ]
};

第3行是我们导入插件的地方。然后,在入口部分,我们使用不同的设置(对象字面值)来指定多个入口点。vendor中包括polyfill以及Lodash,我们将主条目文件放入主条目。然后,我们只需要将CommonsChunkPlugin添加到插件部分,将vendor指定为基础的块,并指定vendor将存储在名为vendor.bundle.js的文件中。
通过指定vendor,此插件会将其他条目文件中指定的所有依赖项提取到该供应商块中。如果这里没有指定块名,它将根据条目之间共享的依赖关系创建一个单独的文件。
运行webpack时,现在应该会看到三个JavaScript文件:bundle.js,1.bundle.js和vendor.bundle.js。您可以运行npm开始,并在浏览器中查看结果(如果需要)。看起来webpack甚至会把大部分自己的代码用于处理不同模块的加载到vendor中.

我表示并没有看到1.bundle.js这个文件

结语

当然webpack不仅仅能实现上述功能,他还能轻松实现CSS模块,高速缓存清除散列,图像优化,希望在以后的学习多多运用。( Webpack enables easy CSS modules, cache-busting hashes, image optimization and much much more — so much that even if I wrote a massive book on the subject, I couldn’t show you everything, and by the time I finished writing that book, most (if not all) of it would be outdated! So, give webpack a try today, and let me know if it improves your workflow. God bless and happy coding!)

原文链接

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

推荐阅读更多精彩内容

  • 作者:小 boy (沪江前端开发工程师)本文原创,转载请注明作者及出处。原文地址:https://www.smas...
    iKcamp阅读 2,758评论 0 18
  • 无意中看到zhangwnag大佬分享的webpack教程感觉受益匪浅,特此分享以备自己日后查看,也希望更多的人看到...
    小小字符阅读 8,164评论 7 35
  • 写在开头 先说说为什么要写这篇文章, 最初的原因是组里的小朋友们看了webpack文档后, 表情都是这样的: (摘...
    Lefter阅读 5,286评论 4 31
  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,693评论 7 110
  • 最近在学习 Webpack,网上大多数入门教程都是基于 Webpack 1.x 版本的,我学习 Webpack 的...
    My_Oh_My阅读 8,184评论 40 247