webpack 4 入门指南 系列三(资源管理篇)

  • 在开始接下来的教程之前,你应该已经有一个展示“Hello webpack”的小工程了。现在我们来尝试合并一些其他资源,例如图片,看看该如何处理它们。

  • 在webpack之前,前端开发人员会使用类似grunt和gulp之类的工具处理这些资源,并把它们从src目录移到distbuild目录中。但类似webpack这样的工具会动态捆绑所有的依赖关系(创建依赖图),相同的想法也用在了Javascript模块上。这样做非常好,因为每个模块都明确指明它的依赖状态,而且我们还可以避免加载不需要的模块。

  • webpack最酷的一个特性就是除了Javascript之外, 你可以通过一个加载器包含任何类型的文件。这意味着上述列举的有关JavaScript的好处(例如显示依赖关系),都可以应用于构建网站或Web应用程序时使用的所有内容。通过前面的教程你应该已经熟悉了该设置,让我们先从CSS开始吧。

设置

  • 在开始之前,我们做一点点改变先:

dist/index.html

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

加载 CSS

  • 为了在JavaScript模块中import一个CSS文件,你需要安装并添加style-loadercss-loader到你配置文件module中:
npm install style-loader css-loader --save-dev

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

webpack 使用正则表达式来确定它应该查找哪些文件并对其使用特定加载器。在这个例子中,任何以.css结尾的文件都将使用style-loadercss-loader加载器。

  • 这样就允许通过imort "./style.css"导入文件并使用其中的样式。现在当模块运行的时候,一个字符串化的<style>标签就会添加到你的html文件的<head>中。

  • 现在在我们的项目中添加一个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
  • 在浏览器中打开index.html就可以看到红色的Hello webpack了。可以通过检查页面查看 head 标签。里面有我们导入到index.js中的样式块。

  • 注意,你可以(在大多数情况下)压缩css代码,以便在生产环境中节省更多的加载时间。最重要的是,加载器几乎存在于你能想到的任何CSS风格中--postcss,sass,以及less等等。

加载图片

  • 我们已经可以把CSS加入到我们的项目中了,那我们背景图和图标呢?使用file-loader可以很轻易的就整合进我们的系统:
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'
+         ]
+       }
      ]
    }
  };

现在当你使用import MyImage from './my-image.png'的时候, 该图片将被处理并添加到输出目录中,而且变量MyImage将包含处理后该图片的最终url。当使用css-loader时, 如上所示,CSS中的url('./my-image.png')也会出现类似的过程。加载器会识别出这是本地文件,并将路径'./my-image.png'替换为输出目录中图片的最终路径。html-loader也用相同的方式处理**<img src="./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
  • 如果一切正常,你会看到你的图片成为了重复的背景,以及Hello webpack文字旁边的img元素。如果你检查元素,你会看到实际的文件名是类似于82b9c7a5a3f405032b1db71a25f67021.png的。这意味着webpack找到了我们在src目录下的图片并进行了处理。

这里合乎逻辑的下一步是缩小和优化您的图像。查看image-webpack-loaderurl-loader,了解有关如何增强图像加载过程的更多信息。

加载字体

  • 那么像字体这样的资源的?文件和url加载器会获取你通过它们加载的任何文件,并将其输出到构建目录。这意味着我们可以使用它们处理任何类型的文件,包括字体文件。
  • 现在更新一下webpack.confog.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
  • 配置和添加好字体后,你可以使用@font-face申明来合并它们。webpack将会使用过本地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');
  }
  • 现在重新构建并打开index.html文件:
npm run build
  • 你会看到Hello webpack换了一种字体。

加载数据

  • 另一种可以被加载的有用资源是数据,像JSON,CSV,TSV和XML文件。对JSON文件的支持是内置的,和NodeJs一样,意味着可以直接使用import Data from './data.json。为了importCSV,TSV和XML,你需要使用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'
+         ]
+       }
      ]
    }
  };
  • 添加一个xml文件

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)的任何一种并且变量Data将会被解析成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的时候, 查看控制台,你就会看到你导入的数据。

当使用d3等工具实现某种数据可视化时,这尤其有用。你可以在构建过程中将其加载到模块中。 而不是在运行时发出ajax请求并解析数据,这样一旦模块访问浏览器,解析后的数据就可以运行了。

全局资源

  • 上面提到的最酷的事情就是用这种方式加载资源允许你以一种更直观的方式将模块和资源文件组合在一起。你可以根据使用它们的代码对资源进行分组,而不是依赖包含所有内容的全局assets目录。例如像这样的机构非常哟用
- |- /assets
+ |– /components
+ |  |– /my-component
+ |  |  |– index.jsx
+ |  |  |– index.css
+ |  |  |– icon.svg
+ |  |  |– img.png
  • 这样的设置适应的代码更便于移植,因为现在紧密耦合的东西都在一起了。假设如果你想在其他项目中使用/my-component,只要简单的复制或者移动到/components目录即可。只要你安装了任何外部依赖项并且配置文件定义了相同的加载器,那就没问题了。

  • 但是,假设你已经锁定了老的方式或者有一些资源在多个组件中共享(views,templates,modules等等)。仍然可以将这些资源放在基目录中,甚至可以使用别名使它们更容易import

总结

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

推荐阅读更多精彩内容