美文网首页
Webpack - 核心概念

Webpack - 核心概念

作者: 李岩liyan | 来源:发表于2018-11-27 23:31 被阅读0次

    如果你稍微了解过 HTTP,肯定知道一大堆文件请求对于浏览器是什么样的灾难。然而,数以百计的 JS 文件和 CSS 文件在现在的 Web Applications 中已经是常态了,这么多的文件如果一个个通过 HTML 标签引入,别说浏览器,自己都要疯掉。

    简单来说,Webpack 就是一个打包工具,它可以让你把众多文件,合并成一个。就像 Webpack 官网图里展示的那样。

    bundle everything

    对一个没有引入 Webpack 的项目来说,如果要实现这种效果,最先遇到的问题就是:

    • 要怎么打包?
    • 打包之后的文件会在哪?

    解决了这两个问题,我们就能在项目里开始使用 Webpack 了。

    所有问题的答案,都可以在 Webpack 的配置文件 webpack.config.js 中找到。

    基础概念

    对于第一个问题,要怎么打包?
    这是 Webpack 要考虑的问题,但同时我们也需要考虑 -- 怎么让 Webpack 知道把 哪些文件 打成一个 bundle?

    Entry

    以 JS 文件为例,通常来说,项目中的 JS 文件之间都是相互依赖的。你极有可能需要把 util.js 通过 import 引入另一个业务相关的文件 work.js 。那么 work.js 在被打包的时候, 它依赖的 util.js 也需要被打包在同一个 JS 文件中, 程序的逻辑才不会被破坏。
    如果通过引用一直向上溯源的话,通常会找到命名类似 src/index.js 的文件,它直接或间接的引用了几乎所有的 JS 文件(Webpack 可以将文件打包为多个,这里我们只考虑打包为一个的情况,认为 index.js 引用了所有文件)。那么我们如果从 index.js 出发,将它所有直接或间接通过 import 引用的文件全部都打包进一个 JS 文件 ,那 index.js 就是我们打包的开始、起点、入口,Webpack 中称为:entry。

    module.exports = {
      entry: './src/index.js'
    };
    

    entry 可以接收字符串、对象和数组。

    Webpack 认为,如果一个文件依赖于另一个文件(非代码资源,像是图片,Web 字体等),就存在 dependency。Webpack 从 entry 开始处理,递归地建立一个 dependency graph,包含工程所需的所有文件,最终将它们打包为一个文件供浏览器加载。

    那这个文件最终会在哪,文件名又是什么呢?知道这些信息我们就可以在 index.html 中直接引用它。

    Output

    这个问题的答案当然是自己定,我们可以通过 output 属性指定将来打包完毕的文件所在的路径,以及文件名。Webpack 4 中的默认值为 ./dist/main.js ( dist : distribution ),配置方式:

    const path = require('path');
    
    module.exports = {
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
      }
    };
    

    pathfilename 分别指定 bundle 文件所在文件夹的绝对路径的和文件名。

    似乎问题已经解决了?是的,目前为止我们已经可以打包 JS 了。
    只不过还有一些问题,比如我们需要打包的 JS 文件中不能使用 ES6 的特性,不能在 JS 中引入 CSS 文件(包括 SASS 文件),打包后文件数量数量少了但 bundle 文件所占空间还是比较大。

    前面两个问题是打包途中就需要考虑的,如果 Webpack 不能处理引入的文件(CSS 文件 和 浏览器不能辨识的 ES6 JS 文件),那打包的过程势必会收到影响。
    最后一个问题在 bundle 文件生成后处理就可以,比如压缩一下文件。

    这两类问题都需要额外的工具协助。

    对于第一类问题,我需要可以解析引入到 JS 的 CSS 文件的工具(css-loaderstyle-loader),以及将 ES6 标准下的 JS 转为浏览器能识别版本的工具( babel-loader )。 Webpack 将这些解析工具称为 loader。

    Loaders

    Webpack 只理解 javascript 和 json,Loaders 可以让 Webpack 将其他文件转化为 module,随后就可以加入 denpendency graph。

    Loaders 有两个属性可以在 config 文件中配置:

    • test : 指定要转化的文件
    • use :指定转化文件使用的 loader

    对于上面的问题:

    module.exports = {
      module: {
        rules: [
          { 
            test: /\.js$/, 
            use: 'babel-loader' 
          },
          { 
            test: /\.css$/, 
            use: ['style-loader', 'css-loader'] 
          }
        ]
      }
    };
    

    翻译一下:

    • 当 webpack 的编译器遇到某个文件中 require/importjs 结尾的文件时, 先使用 babel-loader 转化再打包。
    • 当 webpack 的编译器遇到某个文件中 require/importcss 结尾的文件时, 先使用 css-loaderstyle-loader 转化再打包。

    对于第二类问题,对打包好的 bundle 文件的处理,比如优化、压缩等等。通常通过一些插件进行操作。

    Plugins

    比如常用的压缩,Webpack 内置这个插件。
    这里我们更进一步,通过 Webpack 插件生成 HTML 文件,并且自动引入 bundle 之后的文件。显然,Webpack 需要知道生成的 HTML 文件是什么样子的,也就是它需要一个样板、模板( template ),我们假设程序的入口 HTML 文件是 src/index.html,通过插件 html-webpack-plugin 来进行这个操作。

    使用 plugin 需要先通过 require 引入,再加入到 plugins 数组中。

    const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
    const webpack = require('webpack'); //to access built-in plugins
    
    module.exports = {
      plugins: [
        new webpack.optimize.UglifyJsPlugin({minimize: true}),
        new HtmlWebpackPlugin({template: './src/index.html'})
      ]
    };
    

    现在我们直接使用 dist/index.html 就好了, Webpack 已经打包了 JS、CSS 文件并一并注入了这个 HTML 文件。

    Plugin 还可以执行更广泛的任务,如打包的优化,资源管理和环境变量注入。大多 plugin 都可以定制化。

    汇总

    一份包含上面所有概念的 webpack.config.js 看起来差不多是这样:

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin'); 
    const webpack = require('webpack'); 
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
      },
      module: {
        rules: [
          { 
            test: /\.js$/, 
            use: 'babel-loader' 
          },
          { 
            test: /\.css$/, 
            use: ['style-loader', 'css-loader'] 
          }
        ]
      },
      plugins: [
        new webpack.optimize.UglifyJsPlugin({minimize: true}),
        new HtmlWebpackPlugin({template: './src/index.html'})
      ]
    };
    

    打包入口 entry ,输出路径 output,解析文件的 loader ,打包文件处理的插件 plugin。

    今天就到这里了。

    相关文章

      网友评论

          本文标题:Webpack - 核心概念

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