您的当前位置:首页正文

webpack指南 - 资源管理

来源:华拓网
  • 翻译作者: 饭团爸爸

资源管理

在有 webpack 之前,前端开发工程师使用 grunt 或者 gulp 等工具去处理资源文件,然后将它们从src文件夹移动到/dist或者/build文件夹中。类似的方法在 JavaScript Module,但是类似 webpack 的工具会动态绑定所有的依赖(通过创建依赖图的方式)。这样的好处在于所有的模块都显示声明它们的依赖,避免绑定我们不需要的模块。

webpack 中一个非常酷的功能是可以包含除了 JavaScript 文件之外的任何文件,只需要配置好相应的加载器 loader。这意味着以上那些关于 JavaScript(例如:显示声明)的优点可以用在构建 website 或者 webapp 的各处。现在我们从 CSS 这个可能是你最熟悉的部分开始。

译者注释 : webpack 将各种资源文件统称为 asset,这个词一般指资产,不过资产这个词
过于正式,所以在这里我将统一将 asset 翻译为资源

步骤

在此之前,我们先对我们的项目做一点微调。

dist/index.html

  <html>
    <head>
-    <title>Getting Started</title>
+    <title>Asset Management</title>
    </head>
    <body>
      <script src="./bundle.js"></script>
    </body>
  </html

加载 CSS

为了import一个 CSS 文件从 JavaScript 模块,你需要安装然后添加style-loadercss-loader到你的module配置:

npm install --save-dev style-loader css-loader

webpack.config.js

  var path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
+   module: {
+     rules: [
+       {
+         test: /\.css$/,
+         use: [
+           'style-loader',
+           'css-loader'
+         ]
+       }
+     ]
+   }
  };

webpack 使用正则表达式去指明需要搜索什么文件,以及如何去加载这些文件。在这里
例子中,所有文件后缀名称为.css的文件将会被stlye-loadercss-loader加载。

上述配置将使你可以用import的方式将'./style.css'引入你的文件中。现在我们让这个模块运行起来。一个<script>标签将会被被一段在 html 文件头部的字符串所替代。

现在让我们添加一个新的style.css文件到我们的项目中,并且将其添加到index.js文件中:

project

  webpack-demo
  |- package.json
  |- webpack.config.js
  |- /dist
    |- bundle.js
    |- index.html
  |- /src
+   |- style.css
    |- index.js
  |- /node_modules

src/style.css

.hello {
  color: red;
}

src/index.js

  import _ from 'lodash';
+ import './style.css';

  function component() {
    var element = document.createElement('div');

    // Lodash, now imported by this script
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+   element.classList.add('hello');

    return element;
  }

  document.body.appendChild(component());

现在开始运行构建命令

npm run build

Hash: 9a3abfc96300ef87880f
Version: webpack 2.6.1
Time: 834ms
    Asset    Size  Chunks                    Chunk Names
bundle.js  560 kB       0  [emitted]  [big]  main
   [0] ./~/lodash/lodash.js 540 kB {0} [built]
   [1] ./src/style.css 1 kB {0} [built]
   [2] ./~/css-loader!./src/style.css 191 bytes {0} [built]
   [3] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
   [4] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built]
   [5] ./~/style-loader/lib/urls.js 3.01 kB {0} [built]
   [6] (webpack)/buildin/global.js 509 bytes {0} [built]
   [7] (webpack)/buildin/module.js 517 bytes {0} [built]
   [8] ./src/index.js 351 bytes {0} [built]

打开index.html文件在你的浏览器,你会看到Hello webpack现在变成红色了。为了看 webpack 做了什么,我们可以检视页面(不要查看页面代码,它不会给你展示结果),然后看页面的 <head> tag,你会看见我们的样式已经被包含在内了。

你甚至可以拆分你的 CSS 文件,以便能在生产环节中更好的决定加载实际。除此之外你
还可以加载 CSS 的变体包括 postcss,sass 或者 less.

加载图片

npm install --save-dev file-loader

webpack.config.js

  var path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
+       {
+         test: /\.(png|svg|jpg|gif)$/,
+         use: [
+           'file-loader'
+         ]
+       }
      ]
    }
  };

现在,当你从./my-image.png中引入MyImage,这个图片将被处理,然后添加到output目录,并且这个MyImage变量将包含这个图片被处理后的最终 url。当使用css-loader,正如所展示的那样,一个类似的处理url('./my-image.png')的方法会被调用在你的 CSS 中。这个加载器将会识别出这个本地文件,然后替换'./my-image.png'路径为最终output文件夹中的目录。html-loader 处理![](./my-image.png)使用同样的方法。

现在我们添加图片到我们的项目中,看看它是如何工作的,你可以使用任意一张你自己的图片。

project

  webpack-demo
  |- package.json
  |- webpack.config.js
  |- /dist
    |- bundle.js
    |- index.html
  |- /src
+   |- icon.png
    |- style.css
    |- index.js
  |- /node_modules

src/index.js

  import _ from 'lodash';
  import './style.css';
+ import Icon from './icon.png';

  function component() {
    var element = document.createElement('div');

    // Lodash, now imported by this script
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    element.classList.add('hello');

+   // Add the image to our existing div.
+   var myIcon = new Image();
+   myIcon.src = Icon;
+
+   element.appendChild(myIcon);

    return element;
  }

  document.body.appendChild(component());

src/style.css

  .hello {
    color: red;
+   background: url('./icon.png');
  }

让我们重新构建项目,然后打开 index.html 文件。

npm run build

Hash: 854865050ea3c1c7f237
Version: webpack 2.6.1
Time: 895ms
                               Asset     Size  Chunks                    Chunk Names
5c999da72346a995e7e2718865d019c8.png  11.3 kB          [emitted]
                           bundle.js   561 kB       0  [emitted]  [big]  main
   [0] ./src/icon.png 82 bytes {0} [built]
   [1] ./~/lodash/lodash.js 540 kB {0} [built]
   [2] ./src/style.css 1 kB {0} [built]
   [3] ./~/css-loader!./src/style.css 242 bytes {0} [built]
   [4] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
   [5] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built]
   [6] ./~/style-loader/lib/urls.js 3.01 kB {0} [built]
   [7] (webpack)/buildin/global.js 509 bytes {0} [built]
   [8] (webpack)/buildin/module.js 517 bytes {0} [built]
   [9] ./src/index.js 503 bytes {0} [built]

如果一切正常的话,你可以看到你的 icon 会作为背景反复出现,与此同时一个img元素将会出现在Hello webpack文本后面。如果你审查这些元素,你会看到实际的文件名称已经被该为类似5c999da72346a995e7e2718865d019c8.png的结构,这意味着 webpack 在src中找到了我们的文件,并且处理过他们。

加载字体

好!现在我们来看看如何加载字体资源。文件和 url 加载器可以加载任何文件,并且输出到你的构建目录中,任何文件意味着包括字体文件。现在我们更新配置文件去处理字体文件。

webpack.config.js

  var path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
        {
          test: /\.(png|svg|jpg|gif)$/,
          use: [
            'file-loader'
          ]
        },
+       {
+         test: /\.(woff|woff2|eot|ttf|otf)$/,
+         use: [
+           'file-loader'
+         ]
+       }
      ]
    }
  };

添加一些字体文件到你的项目中

project

  webpack-demo
  |- package.json
  |- webpack.config.js
  |- /dist
    |- bundle.js
    |- index.html
  |- /src
+   |- my-font.woff
+   |- my-font.woff2
    |- icon.png
    |- style.css
    |- index.js
  |- /node_modules

使用以上的加载器配置和字体文件,你可以将字体纳入你的项目,使用引用本地文件的url()命令,你同样可以加载字体文件,就像加载图片一样。

src/style.css

+ @font-face {
+   font-family: 'MyFont';
+   src:  url('./my-font.woff2') format('woff2'),
+         url('./my-font.woff') format('woff');
+   font-weight: 600;
+   font-style: normal;
  }

  .hello {
    color: red;
+   font-family: 'MyFont';
    background: url('./icon.png');
  }

现在我们再次构建

npm run build

Hash: b4aef94169088c79ed1c
Version: webpack 2.6.1
Time: 775ms
                                Asset     Size  Chunks                    Chunk Names
 5c999da72346a995e7e2718865d019c8.png  11.3 kB          [emitted]
11aebbbd407bcc3ab1e914ca0238d24d.woff   221 kB          [emitted]
                            bundle.js   561 kB       0  [emitted]  [big]  main
   [0] ./src/icon.png 82 bytes {0} [built]
   [1] ./~/lodash/lodash.js 540 kB {0} [built]
   [2] ./src/style.css 1 kB {0} [built]
   [3] ./~/css-loader!./src/style.css 420 bytes {0} [built]
   [4] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built]
   [5] ./src/MyFont.woff 83 bytes {0} [built]
   [6] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built]
   [7] ./~/style-loader/lib/urls.js 3.01 kB {0} [built]
   [8] (webpack)/buildin/global.js 509 bytes {0} [built]
   [9] (webpack)/buildin/module.js 517 bytes {0} [built]
  [10] ./src/index.js 503 bytes {0} [built]

打开index.html文件,我们可以看到Hello webpack的字体已经改变为新的字体,如果一切正常,你会看到这些变化的。

加载数据

另一种常用的被加载的是数据,类似 JSON 文件,CSVs,TSVs 和 XML。NodeJS 原生支持对 JSON 文件的支持,这意味着你只需要使用 import Data from './data.json'命令就可以直接使用了。但是引入 CSVs,TSVs 和 XML 你需要使用csv-loaderxml-loader,现在让我们同时加载它们。

npm install --save-dev csv-loader xml-loader

webpack.config.js

  var path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
        {
          test: /\.(png|svg|jpg|gif)$/,
          use: [
            'file-loader'
          ]
        },
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/,
          use: [
            'file-loader'
          ]
        },
+       {
+         test: /\.(csv|tsv)$/,
+         use: [
+           'csv-loader'
+         ]
+       },
+       {
+         test: /\.xml$/,
+         use: [
+           'xml-loader'
+         ]
+       }
      ]
    }
  };

添加数据文件到项目中

project

  webpack-demo
  |- package.json
  |- webpack.config.js
  |- /dist
    |- bundle.js
    |- index.html
  |- /src
+   |- data.xml 
    |- my-font.woff
    |- my-font.woff2
    |- icon.png
    |- style.css
    |- index.js
  |- /node_modules

src/data.xml

<?xml version="1.0" encoding="UTF-8"?>
<note>
  <to>Mary</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Call Cindy on Tuesday</body>
</note>

现在我们可以通过import使用者四种数据(JSON,CSV,TSV,XML)并且数据将被直接解析为 JSON 结构易于我们使用。

src/index.js

  import _ from 'lodash';
  import './style.css';
  import Icon from './icon.png';
+ import Data from './data.xml';

  function component() {
    var element = document.createElement('div');

    // Lodash, now imported by this script
    element.innerHTML = _.join(['Hello', 'webpack'], ' ');
    element.classList.add('hello');

    // Add the image to our existing div.
    var myIcon = new Image();
    myIcon.src = Icon;

    element.appendChild(myIcon);

+   console.log(Data);

    return element;
  }

  document.body.appendChild(component());

当你打开index.html文件,你可以在浏览器的开发工具控制台中看到被引入的文件的日志。

(译者注:使用这个加载数据文件的特性,非常有利于测试,可以用这个特性模拟 ajax 请求的数据,有助于前后端同时开始。而不相互等待)