webpack

一张图,看懂webpack

webpack 是一个现代的 JavaScript 应用程序的模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图表(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成少量的 bundle - 通常只有一个,由浏览器加载。

它是高度可配置的,但是,在开始前你需要先理解四个核心概念:入口(entry)、输出(output)、loader、插件(plugins)。

概览

app.js

import bar from './bar'
bar()

bar.js

export default function () {
    // ...
}

webpack.config.js

module.exports = {
    entry: './app.js',
    output: {
        filename: 'bundle.js'
    }
}

index.html

<html>
    <head>
        ...
    </head>
    <body>
        ...
        <script src="bundle.js"></script>
    </body>
</html>

起步

参考地址: https://doc.webpack-china.org/guides/get-started/

webpack is a tool to build JavaScript modules in your application.

webpack 是一个用来构建我们应用程序中的 JavaScript 模块的工具

创建一个bundle文件

  1. 在项目中创建package.json文件

    $ npm init -y
    
  2. 安装webpack到项目中

    $ npm install --save webpack
    
  3. app目录下创建index.js文件
    app/index.js

    function component () {
        var element = document.createElement('div');
    
        // 需要引入 lodash,下一行才能正常工作
        element.innerHTML = _.join(['Hello','webpack'], ' ');
    
        return element;
    }
    
    document.body.appendChild(component());
    

    要运行这段代码,在项目根目录下创建 index.html 文件。

    index.html

    <html>
        <head>
            <title>webpack 2 demo</title>
            <script src="https://unpkg.com/lodash@4.16.6"></script>
        </head>
        <body>
    
        </body>
        <script src="app/index.js"></script>
    </html>
    

    在此示例中,<script> 标签之间存在隐式依赖关系。

    运行 index.js 会依赖于页面中提前引入的 lodash。之所以说是隐式的是因为 index.js 并未显式声明需要引入 lodash,只是假定推测已经存在一个全局变量 _

    使用这种方式去管理 JavaScript 项目会有一些问题:

    • 如果依赖不存在,或者引入顺序错误,应用程序将无法正常运行。
    • 如果依赖被引入但是并没有使用,那样就会存在许多浏览器不得不下载的无用代码。
  4. 要在 index.js 中打包 lodash 依赖,首先我们需要安装 lodash

    $ npm install --save lodash
    

    app/index.js最上面添加此行代码,在文件内显示引入

    import _ from 'lodash'
    

    修改index.html文件,删除两行script标签的引入,改为引入dist/bundle.js

    <html>
        <head>
            <title>webpack 2 demo</title>
        </head>
        <body>
    
        </body>
        <script src="dist/bundle.js"></script>
    </html>
    
  5. 使用webpack,对app/index.js进行处理

    $ webpack app/index.js dist/bundle.js
    

    之后会生成一个dist文件夹,内部存在bundle.js文件
    刷新网页,效果是一样的!

    通过声明模块所需的依赖,webpack 能够利用这些信息去构建依赖图表,然后使用图表生成一个优化过的,会以正确代码顺序被运行的 bundle。并且没有用到的依赖将不会被 bundle 引入。

    现在在此文件夹下带上以下参数运行 webpack,其中 index.js 是入口文件,bundle.js 是已打包所需的所有代码的输出文件。

    说明: 尽管 import/export 语句在浏览器中还未被支持,你也可以正常的使用,因为 webpack 会将其替换为 ES5 兼容的代码。你可以检查 dist/bundle.js 的代码来说服自己放心使用

使用配置好的文件

对于更复杂的配置,我们可以使用一个配置文件,webpack 会按照它来打包代码。创建一个 webpack.config.js 文件后,你可以使用如下的配置设置来表示上述 CLI 命令。

webpack.config.js

var path = require('path');

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

执行命令,进行压缩打包

$ webpack --config webpack.config.js

同样可以生成bundle.js文件

通过配置文件可以最灵活地使用 webpack。我们可以通过向配置文件添加 loader 规则(loader rules)、插件(plugins)、解析选项(resolve options)以及许多其他增强功能,来进行打包。

配合npm使用

考虑到用 CLI 这种方式来运行 webpack 不是特别方便,我们可以设置一个快捷方式。像这样调整 package.json

package.json添加如下代码:

"scripts": {
    "build": "webpack"
},

通过执行命令,即可使用webpack进行打包压缩等操作

$ npm run build

概念解释

入口(entry)

webpack 将创建所有应用程序的依赖关系图表(dependency graph)。图表的起点被称之为入口起点(entry point)入口起点告诉 webpack 从哪里开始,并遵循着依赖关系图表知道要打包什么。可以将您应用程序的入口起点认为是根上下文(contextual root)app 第一个启动文件

module.exports = {
    entry: './path/to/my/entry/file.js'
};

entry属性告诉我们主文件在哪里

出口(output)

将所有的资源(assets)归拢在一起后,还需要告诉 webpack 在哪里打包应用程序。webpack 的 output 属性描述了如何处理归拢在一起的代码(bundled code)。

const path = require('path');

module.exports = {
    entry: './path/to/my/entry/file.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'my-first-webpack.bundle.js'
    }
};

通过 output.filenameoutput.path 属性,来告诉 webpack bundle 的名称,以及我们想要生成(emit)到哪里

loader

webpack 的目标是,让 webpack 聚焦于项目中的所有资源(asset),而浏览器不需要关注考虑这些(这并不意味着资源(asset)都必须打包在一起)。webpack 把每个文件(.css, .html, .scss, .jpg, etc.) 都作为模块处理。然而 webpack 只理解 JavaScript

webpack loader 会将这些文件转换为模块,而转换后的文件会被添加到依赖图表中。

在更高层面,webpack 的配置有两个目标。

  1. 识别出(identify)应该被对应的 loader 进行转换(transform)的那些文件
  2. 由于进行过文件转换,所以能够将被转换的文件添加到依赖图表(并且最终添加到 bundle 中)(use 属性)
const path = require('path');
const config = {
    entry: './path/to/my/entry/file.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
    },
    module: {
        rules: [
            {test: /\.(js|jsx)$/, use: 'babel-loader'}
        ]
    }
};
module.exports = config;

以上配置中,对一个单独的 module 对象定义了 rules 属性,里面包含两个必须属性:testuse。这可以告诉 webpack compiler 如下:

“嘿,webpack compiler,当你碰到「在 require()/import 语句中被解析为 '.js' 或 '.jsx' 的路径」时,在你把它们添加并打包之前,要先使用 babel-loader 去转换”。

插件

由于 loader 仅在每个文件的基础上执行转换,而 插件(plugins) 最常用于(但不限于)在打包模块的“compilation”和“chunk”生命周期执行操作和自定义功能(查看更多)。webpack 的插件系统极其强大和可定制化

想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,你需要使用 new 创建实例来调用它。

// 引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');

const config = {
    entry: './path/to/my/entry/file.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
    },
    module: {
        rules: [
            {test: /\.(js|jsx)$/, use: 'babel-loader'}
        ]
    },
    plugins: [ // 创建插件对象,添加到此数组中
        new webpack.optimize.UglifyJsPlugin(),
        new HtmlWebpackPlugin({template: './src/index.html'})
    ]
};

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

推荐阅读更多精彩内容