1

webpack加载不同的资源

本文内容如下:

1 加载单一JS文件

2 加载2个或多个js

3 引入JSON文件

4 加载字体

5 加载数据CSV/TSV/XML

6 加载CSS文件介绍

7 实际操作:

8 单独打包CSS,ExtractTextWebpackPlugin插件

9 CSS modules

10 CSS预处理器

11 加载Sass

12 在 Webpack 中使用公用 CDN

13 当第三方库,不支持CommonJS或AMD时。或者需要前置库时。

13.1 使用webpack.ProvidePlugin

13.2 使用imports-loader

加载单一JS文件

以lodash.js为例子

安装lodash

npm i lodash --save-dev

//index.js

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

然后运行webpack。即可。

加载2个或多个js

如果是自己写的代码,通过require("./book.js");引入即可。

如果是第三方库,先安装,再通过require()或import引入即可。

引入JSON文件

zyx456:JSON文件可以直接用require(filename)引入使用。

var config = require('./test.json');

import Data from './data.json'

类似于 NodeJS,JSON 支持实际上是内置的,也就是说将正常运行。

项目目录:

JS/

  • config.json
  • entry.js

//test.json文件

{
  "greetText": "Hi there and greetings from JSON!"
}

entry.js

var config = require('./test.json');
module.exports = function() {
  var greet = document.createElement('div');
  greet.textContent = config.greetText;
  return greet;
};

加载字体

file-loader 和 url-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'         ]
       }
      ]
    }
  };

在项目中添加一些字体文件:

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

加载数据CSV/TSV/XML

可以加载的有用资源还有数据,如 CSV、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'
+         ]
+       }
      ]
    }
  };

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

【07】添加CSS文件

加载CSS文件介绍

【】如果直接在index.js文件里引入 CSS:

import styles from './assets/stylesheets/application.css';

会遇到以下的错误:You may need an appropriate loader to handle this file type。

在应用中添加 css 文件,就需要使用到 css-loader 和 style-loader。

css-loader 会遍历 CSS 文件,然后找到 url() 表达式然后处理他们。能够使用类似@import 和 url(...)的方法实现 require()的功能。

style-loader 会把原来的 CSS 代码插入页面中的一个 style 标签中。

【】在编译时,css-loader会读取CSS文件,并处理其中的import,返回CSS代码;

而style-loader会将返回的CSS代码作为DOM的style。

【】在生产构建下,CSS 是会被打包到 JavaScript 里的,style-loader 会把你的样式写在 Style 标签里。

css-loader用来返回有@import和url()的css文件style-loader用来将css文件插入页面。

【02】可以根据需求将一些图片自动转成base64编码的,减轻很多的网络请求。

实际操作:

【01】安装 css-loader 和 style-loader(全局安装需要参数 -g)。

cnpm install css-loader style-loader

安装url-loader

npm install url-loader --save-dev

【02】然后给 webpack.config.js 添加一条规则:

Loaders会根据数组的逆序运行,也就是说 css-loader会跑在 style-loader 前面。

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

webpack 根据正则表达式,来确定应该查找哪些文件,并将其提供给指定的 loader。在这种情况下,以 .css 结尾的全部文件,都将被提供给 style-loader 和 css-loader。

【03】添加css文件,注意文件的路径。

js/style.css

body {background: yellow; }

【04】在JS文件引入CSS文件。

import './style.css'

如何css文件根目录/css/a.css

那么

import '../css/a.css';

css会和js打包到同一个文件中。

实际网页中,含有 CSS 字符串的 <style> 标签,将被插入到 html 文件的 <head> 中。

单独打包CSS,ExtractTextWebpackPlugin插件

单独打包CSS,把 CSS 从 js 文件当中独立出来。

如果把CSS打包到JS中,有一个性能上的问题,就是无法使用浏览器去异步并并行地加载CSS。

反而,你的文件需要等待整个JavaScript文件加载完,才能进行渲染。

在我们的网页设计中,有一种平稳退化的概念。就是说,HTML是最重要的,其次是CSS,最后是JavaScript。

官方文档是以插件的形式做的:

webpack.github.io/docs/styles…

注意一下函数参数,第一第二个参数是有区别的,比如这样用:

第一个参数是编译好以后的代码用的,第二个参数是编译到源代码用的。

ExtractTextPlugin.extract('style-loader', 'css!less')

对插件进行开发依赖安装

$ npm install --save-dev extract-text-webpack-plugin

然后,我们需要修改我们的webpack.config.js配置文件:

//webpack.config.js
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
  entry: './app/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
        rules: [{
            test: /\.css$/,
            //use: [ 'style-loader', 'css-loader' ]
            use: ExtractTextPlugin.extract({
              use: 'css-loader'
            })
        }]
    },
    //ExtractTextPlugin
    plugins: [
      new ExtractTextPlugin('styles.css'),
    ],
  devServer: {
    contentBase: path.join(__dirname, "dist"),
    inline: true
    }
};

这样的设置下,webpack会在dist文件夹中生成一个汇总的styles.css文件。

你需要将它作为一个单独的样式加入到index.html中。在HTML文件中手动引入.css文件。

CSS modules

最近有一个叫做 CSS modules 的技术就意在把JS的模块化思想带入CSS中来,通过CSS模块,所有的类名,动画名默认都只作用于当前模块。

Webpack从一开始就对CSS模块化提供了支持,在CSS loader中进行配置后,你所需要做的一切就是把”modules“传递到所需要的地方,然后就可以直接把CSS的类名传递到组件的代码中,且这样做只对当前组件有效,不必担心在不同的模块中使用相同的类名造成冲突。

具体的代码如下

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }
                ]
            }
        ]
    }
};

在app文件夹下创建一个Greeter.css文件

.root {
  background-color: #eee;
  padding: 10px;
  border: 3px solid #ccc;
}

导入.root到Greeter.js中

import React, {Component} from 'react';
import config from './config.json';
import styles from './Greeter.css';//导入
class Greeter extends Component{
  render() {
    return (
      <div className={styles.root}>//添加类名
        {config.greetText}
      </div>
    );
  }
}
export default Greeter

放心使用把,相同的类名也不会造成不同组件之间的污染。

应用了css module后的样式

CSS modules 也是一个很大的主题,有兴趣的话可以去官方文档查看更多消息

CSS预处理器

Sass 和 Less 之类的预处理器是对原生CSS的拓展,它们允许你使用类似于variables, nesting, mixins, inheritance等不存在于CSS中的特性来写CSS,CSS预处理器可以这些特殊类型的语句转化为浏览器可识别的CSS语句。

你现在可能都已经熟悉了,在webpack里使用相关loaders进行配置就可以使用了,以下是常用的CSS 处理loaders:

  • Less Loader
  • Sass Loader
  • Stylus Loader

不过其实也存在一个CSS的处理平台-PostCSS,它可以帮助你的CSS实现更多的功能,在其官方文档可了解更多相关知识。

举例来说如何使用PostCSS,我们使用PostCSS来为CSS代码自动添加适应不同浏览器的CSS前缀。

首先安装postcss-loader 和 autoprefixer(自动添加前缀的插件)

npm install --save-dev postcss-loader autoprefixer

接下来,在webpack配置文件中添加postcss-loader,在根目录新建postcss.config.js,并添加如下代码之后,重新使用npm start打包时,你写的css会自动根据Can i use里的数据添加不同前缀了。

//webpack.config.js
module.exports = {
    ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader",
                        options: {
                            modules: true
                        }
                    }, {
                        loader: "postcss-loader"
                    }
                ]
            }
        ]
    }
}
// postcss.config.js
module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

加载Sass

zyx456:成功

运行如下命令来安装

npm install style-loader css-loader sass-loader node-sass extract-text-webpack-plugin -D

安装:

yarn add --dev sass-loader node-sass

然后加一条规则:

module.exports = {
  // …
  module: {
    rules: [
      {
        test: /\.(sass|scss)$/,
        use: [
          "style-loader",
          "css-loader",
          "sass-loader",
        ]
      }
      // …
    ],
  },
};

这时候 JavaScript 文件里就可以用 import 来引用 .scss 或者 .sass 文件。

使用:

import './scss/base.scss'

或者打包成单独的CSS文件。

webpack.config.js

output: {
  ...
},
module: {
  rules: [
    {
      test: /\.scss$/,
      use: ExtractTextPlugin.extract({
        fallback: 'style-loader',
        use: ['css-loader', 'sass-loader']
      })
    }
  ]
}

这将告诉webpack,我们希望将所有CSS打包成一个单独的文件,并将其称为style.css 。

plugins: [
  new ExtractTextPlugin('style.css')
]

在head标签中引入css文件:

<link rel='stylesheet' href='dist/style.css'>

插件会报错:

Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead

原因:

extract-text-webpack-plugin还不能支持webpack4.0.0以上的版本。

解决办法:

npm install extract-text-webpack-plugin@next --save-dev

会下载到+ extract-text-webpack-plugin@4.0.0-beta.0

然后在打包就正常了。

图片.png

【08】加载图片

CSS中的背景和图标,怎么办?

使用 file-loader,我们可以轻松地将这些内容混合到 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'
         ]
       }
      ]
    }
  };

用法:

import MyImage from './my-image.png'

该图像将被处理并添加到 output 目录,并且 MyImage 变量将包含该图像在处理后的最终 url。

在 Webpack 中使用公用 CDN

module.exports={ externals: {    moment: true
  }
}

当然了 HTML 代码里需要加上一行

<script referrerpolicy="no-referrer" src="//apps.bdimg.com/libs/moment/2.8.3/moment-with-locales.min.js"></script>

当第三方库,不支持CommonJS或AMD时。或者需要前置库时。

有时候会要加载各种各样的第三方库,一些老的库不支持AMD或者CommonJS等一些先进的格式,比如一些jQuery的插件,它们都依赖jQuery,如果直接引用就会报错 jQuery is not undefined这类的错误,有几种方法解决。

先创建一个jQuery plugin: plugin.js

(function ($) {
    const shade = "#556b2f";
    $.fn.greenify = function() {
        this.css( "color", shade );
        return this;
    };
}(jQuery));

第一种方法

使用webpack.ProvidePlugin

ProvidePlugin

webpack提供一个插件把一个全局变量插入到所有的代码中,在webapck.config.js里面配置

可以将模块作为一个变量,被 webpack 在其他每个模块中引用。

只有需要使用此变量的时候,这个模块才会被 require 进来。

多数之前遗留的模块,会依赖于已存在的某些特定全局变量,比如 jQuery 插件中的 $ 或者 jQuery。

在这种场景,你可以在每次遇到全局标识符 $ 的时候,在 webpack 中预先设置

var $ = require(“jquery”)。

...
  plugins: [
    new HtmlwebpackPlugin({
      title: 'Hello World app'
    }),
    //provide $, jQuery and window.jQuery to every script
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery"
    })
  ]
  ...

在js中引用

...
//这个也不需要了 因为$, jQuery, window.jQuery都可以直接使用了
//import $ from 'jquery';
import './plugin.js';
...
myPromise.then((number) => {
  $('body').append('<p>promise result is ' + number + ' now is ' + moment().format() + '</p>');
  //call our jquery plugin!
  $('p').greenify();
});
...

发现我们插入的p里面的颜色已经变成了绿色!

此插件还能够通过使用以下格式,通过配置一个路径数组,提供导出某个模块:[module, child, ...children?]。

第二种方法

使用imports-loader

先安装这个loader

imports-loader

npm install imports-loader --save-dev

然后在入口js中

//注意这种写法 我们把jQuery这个变量直接插入到plugin.js里面了
//相当于在这个文件的开始添加了 var jQuery = require('jquery');
import 'imports?jQuery=jquery!./plugin.js';
//后面的代码一样
myPromise.then((number) => {
  $('body').append('<p>promise result is ' + number + ' now is ' + moment().format() + '</p>');
  //call our jquery plugin!
  $('p').greenify();
});

吃码小妖
43 声望3 粉丝