1

Asset Management

If you've been following the guides from the start, you will now have a small project that shows "Hello webpack". Now let's try to incorporate some other assets, like images, to see how they can be handled.

       如果你一直跟着我们的Guide来操作,你现在应该有一个叫"Hello webpack"的项目了。现在,让我们试着把它和其他资源合并在一起,就比如图片一类的东西。

Prior to webpack, front-end developers would use tools like grunt and gulp to process these assets and move them from their /src folder into their /dist or /build directory. The same idea was used for JavaScript modules, but tools like webpack will dynamically bundle all dependencies (creating what's known as a dependency graph). This is great because every module now explicitly states its dependencies and we'll avoid bundling modules that aren't in use.

       在webpack问世之前,前端的开发者们都是用grunt 啊,gulp 这样的工具来处理和移动资源,他们将资源从他们的/src目录移动到/dist或者/build目录。JavaScript模块使用了相同的想法,但是像webpack这样的工具会动态地捆绑所有的依赖关系(创建所谓的依赖关系图)这很好,因为现在每个模块都明确地声明了它的依赖关系,我们将避免捆绑未使用的模块。

One of the coolest webpack features is that you can also include any other type of file, besides JavaScript, for which there is a loader. This means that the same benefits listed above for JavaScript (e.g. explicit dependencies) can be applied to everything used in building a website or web app. Let's start with CSS, as you may already be familiar with that setup.

       你知道webpack最酷的事情之一是什么吗?他不仅能打包JS,还可以打包任何其它类型的文件,只要你设定好了加载器。这意味着,上面列出的对于打包JavaScript的好处(例如明确的依赖关系)也可以应用于构建网站或Web应用程序的所有内容。让我们从CSS开始,因为您可能已经熟悉了这个设置。

Setup (起步)

Let's make a minor change to our project before we get started:

       在我们开始之前,让我们给我们的项目做一个微小的改变吧!(* ̄︶ ̄)

dist/index.html

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

P.S.:这里再解释一次,代码行左边的+和-表示相比于原来的文件,增加了哪一行,减少了哪一行。

Loading CSS (加载CSS)

In order to import a CSS file from within a JavaScript module, you need to install and add the style-loader and css-loader to your module configuration:

       为了让JavaScript模块可以获取CSS文件,需要安装style-loadercss-loader,并添加它们到您的module配置中:

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

webpack.config.js

  const 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'
+         ]
+       }
+     ]
+   }
  };

P.S.:这里我想为基础薄弱的朋友们解释一下test: /\.css$/,这个是在写正则表达式呢,它的意思是“以.css结尾”如果你想大致了解一下这个东西而不是很深入地去研究,我推荐菜鸟教程-正则表达式

webpack uses a regular expression to determine which files it should look for and serve to a specific loader. In this case any file that ends with .css will be served to the style-loader and the css-loader.

       webpack使用正则表达式来确定应该查找哪些文件并将其提供给特定的加载程序。在这种情况下,任何以文件结尾的文件.css将被提供给style-loadercss-loader

This enables you to import './style.css' into the file that depends on that styling. Now, when that module is run, a <style> tag with the stringified css will be inserted into the <head> of your html file.

       这使您能够import './style.css'进入依赖于该样式的文件。现在,当这个模块运行时,<style>带有字符串化CSS的标签将被插入到<head>你的html文件中。

Let's try it out by adding a new style.css file to our project and import it in our index.js:

       让我们通过添加一个新的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());

Now run your build command:

       来吧,执行编译命令:

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]

Open up index.html in your browser again and you should see that Hello webpack is now styled in red. To see what webpack did, inspect the page (don't view the page source, as it won't show you the result) and look at the page's head tags. It should contain our style block that we imported in index.js.

       在你的浏览器中再一次打开index.html吧,然后你应该能看见"Hello webpack"现在已经变成红色的了。如果你想知道webpack都干了些啥,实现了这种效果,请监听这个页面的加载吧,看一看页面的头部标签都写了些啥。肯定包含了我们的样式块在我们导入进index.js的时候。

Note that you can also split your CSS for better load times in production. On top of that, loaders exist for pretty much any flavor of CSS you can think of -- postcss, sass, and less to name a few.

       注意,你还可以拆分您的CSS文件以获得更好的加载时间。最重要的是,无论你对于CSS的口味有多刁,都存在相应的加载器——就像postcsssass,还有其它几种,都能加载的。

Loading Images (加载图片)

So now we're pulling in our CSS, but what about our images like backgrounds and icons? Using the file-loader we can easily incorporate those in our system as well:

       那么好,现在我们正在搞CSS,但是,对于咱们的图片,就像那种,背景图片啊,图标啊,这个咋整呢?使用文件加载器,我们可以很轻松地将它们也加入我们的系统之中:

npm install --save-dev file-loader

webpack.config.js

  const 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'
+         ]
+       }
      ]
    }
  };

Now, when you import MyImage from './my-image.png', that image will be processed and added to your output directory and the MyImage variable will contain the final url of that image after processing. When using the css-loader, as shown above, a similar process will occur for url('./my-image.png') within your CSS. The loader will recognize this is a local file, and replace the './my-image.png' path with the final path to the image in your output directory. The html-loader handles <img src="./my-image.png" /> in the same manner.

       现在,当你需要从./my-image.png导入MyImage ,那张图片将会被处理然后添加到你的输出目录中,并且MyImage 变量将会包含一个该图片处理后的url常量。当我们使用CSS加载器的时候,比如把./my-image.png打包到你的CSS文件里,就像上面展现出来的那样,是一个跟上面图片加载差不多的过程。加载器会发现这是一个本地文件,然后把./my-image.png路径替换为output目录中映像的最终路径。HTML加载器也会相同的方式来处理<img src="./my-image.png" />

P.S.:这里说一个小知识点,URL不是URI,这是两个抽象概念,很多人混为一谈。URL指的是统一资源定位符,而URI指的是统一资源标识符。URL是URI的子集。

Let's add an image to our project and see how this works, you can use any image you like:

       让我们给我们的项目添加一张图片,然后看看这是怎么工作的吧,你可以使用任意一张你喜欢的图片哦。

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');
  }

Let's create a new build and open up the index.html file again:

       让我们再一次编译项目,然后打开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]

If all went well, you should now see your icon as a repeating background, as well as an img element beside our Hello webpack text. If you inspect this element, you'll see that the actual filename has changed to something like 5c999da72346a995e7e2718865d019c8.png. This means webpack found our file in the src folder and processed it!

       如果一切顺利,你现在应该看到你的图标铺满了背景,而且一个图片元素就在你的文本“Hello webpack”的一边。如果你监听了这个元素,你将会看到真实的图片名称已经被更换了,更换成类似于5c999da72346a995e7e2718865d019c8.png的名字。这就意味着,webpack已经在src目录下找到了我们的文件而且处理了它。

Loading Fonts (加载字体)

So what about other assets like fonts? The file and url loaders will take any file you load through them and output it to your build directory. This means we can use them for any kind of file, including fonts. Let's update our webpack.config.js to handle font files:

       那么,其它的资源呢?就比如说字体?文件加载器和url加载器将会处理任何你想处理的文件并输出它们到你的编译路径。这就意味着我们可以使用它们来处理各种各样的文件,当然包含字体文件。让我们升级一下我们的webpack.config.js让它能够处理字体文件吧:

webpack.config.js

  const 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

With the loader configured and fonts in place, you can use incorporate them via an @font-face declaration. The local url(...) directive will be picked up by webpack just as it was with the image:

       就在加载器配置和字体的地方,你合并他们通过使用@font-face注解。本地url(...)指令将被webpack拾取,就像它与图像一样:

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');
  }

Now run a new build and let's see if webpack handled our fonts:

       现在,让我们运行一个新的编译,来看看我们的webpack是如何处理我们的字体的:

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]

Open up index.html again and see if our Hello webpack text has changed to the new font. If all is well, you should see the changes.

       再一次打开我们的index.html,我们将看到我们的文本换成了新的字体,如果一切进展顺利,你就应当能够看到这改变。

Loading Data (加载数据)

Another useful asset that can be loaded is data, like JSON files, CSVs, TSVs, and XML. Support for JSON is actually built-in, similar to NodeJS, meaning import Data from './data.json' will work by default. To import CSVs, TSVs, and XML you could use the csv-loader and xml-loader. Let's handle loading all three:

       另外,有用的资源还可能是需要加载的数据,就比方说JSON文件、CSV文件、TSV文件、XML文件……对JSON的支持实际上是内置的,类似于NodeJS,就是说从./data.json导入数据是会被默认执行的。要导入CSVTSVXML,您可以使用csv-loaderxml-loader。让我们来处理加载所有三个:

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

webpack.config.js

  const 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'
+         ]
+       }
      ]
    }
  };

Add some data files to your project:

       还有一些属于这个项目的数据文件:

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>

Now you can import any one of those four types of data (JSON, CSV, TSV, XML) and the Data variable you import it to will contain parsed JSON for easy consumption:

       现在,你可以导入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());

When you open index.html and look at your console in your developer tools, you should be able to see your imported data being logged to the console!

       当你打开index.html的时候,请观察你的开发工具的控制台输出,你应该能够看到导入的数据已经被打印到控制台上了。

This can be especially helpful when implementing some sort of data visualization using a tool like d3. Instead of making an ajax request and parsing the data at runtime you can load it into your module during the build process so that the parsed data is ready to go as soon as the module hits the browser.

       这在使用像D3这样的工具来进行数据可视化的时候是非常有用的。你可以在编译进行的期间将数据加载到你的模块里,而不是使用一个ajax请求然后解析数据,这样,只要模块一运行在浏览器中,解析后的数据就已经准备好了。

Global Assets (全局资源)

The coolest part of everything mentioned above, is that loading assets this way allows you to group modules and assets together in a more intuitive way. Instead of relying on a global /assets directory that contains everything, you can group assets with the code that uses them. For example, a structure like this can be very useful:

       上面提到的所有的事情中最酷的部分是,通过这种方式加载资源可以让您以更直观的方式将模块和资源组织在一起。根据资源和代码之间的使用关系来对资源进行分组,而不是将它们包含在一个全局的资源文件夹下。例如,像这样的结构可能非常有用:

- |- /assets
+ |– /components
+ |  |– /my-component
+ |  |  |– index.jsx
+ |  |  |– index.css
+ |  |  |– icon.svg
+ |  |  |– img.png

This setup makes your code a lot more portable as everything that is closely coupled now lives together. Let's say you want to use /my-component in another project, simply copy or move it into the /components directory over there. As long as you've installed any external dependencies and your configuration has the same loaders defined, you should be good to go.

       这个设置使得你的代码更加轻便,因为现在所有紧密耦合的东西都在一起了。假设您想让/my-component在另一个项目中使用,只需将其复制或移动到/components那里的目录即可。只要你已经安装了任何外部的依赖关系,并且你的配置已经定义了相同的loader

However, let's say you're locked into your old ways or you have some assets that are shared between multiple components (views, templates, modules, etc.). It's still possible to store these assets in a base directory and even use aliasing to make them easier to import.

       然而,假设您已经被旧的方式束缚,或者您拥有一些在多个组件(视图,模板,模块等)之间共享的资源。仍然可以将这些资源存储在基本目录中,甚至可以使用别名来使它们更容易导入。

Wrapping up (收尾)

For the next guides we won't be using all the different assets we've used in this guide, so let's do some cleanup so we're prepared for the next piece of the guides Output Management:

       对于下一个指南,我们将不会使用我们在本指南中使用过的所有不同资源,所以我们来做一些清理工作,以便为下一部分指南做好准备。输出管理:

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

webpack.config.js

  const 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'
-         ]
-       }
-     ]
-   }
  };

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());

hengbao
22 声望2 粉丝

消极的心态限制潜能发挥