webpack使用笔记(二)loader的使用

module 配置项

在 module 中主要配置 loader,loader 是模块转换器,比如把 sass 转成 css。配置了相关资源的 loader,我们就可以直接在程序中用 import 的方式引入非 js 资源。loader 能够加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一起打包到指定的文件中。

需要下载的 loader 以及作用:

  • babel-loader:解析 JavaScript,包括 js 的新特性、新语法;
  • css-loader:处理 css 语法,比如 @importurl() 等;
  • style-loader:将 css 引入到 head 标签中的 style 标签里;
  • sass-loader:处理 sass 文件,将 sass 语法编译成 css;
  • less-loader:处理 less 文件,将 less 语法编译成 css;
  • ts-loader:处理 typescript 文件,将 ts 语法编译成 js;
  • postcss-loader:接收样式原码并交由编译插件处理,比如层架浏览器前缀,使用 css 新语法;
  • eslint-loader:规范 js 代码;
  • html-loader:将一个 html 文件通过 JS 加载进来;
  • file-loader:加载图片、字体等资源;
  • url-loader:与 file-loader 功能相同;
  • html-withimg-loader:转化 HTML 中的 img 图片路径;
  • expose-loader:用于暴露全局变量;
  • vue-loader:处理 vue 文件;
  • raw-loader:将文件作为字符串导入;

需要注意的是,使用 sass 时,除了要下载 sass-loader,还要下载 node-sass;使用 less 时,除了要下载 less-loader,还要下载 less;

在 module.rules 这个配置项中配置 loader,下面详细介绍各个 loader 的配置。

style-loadercss-loader

两者有很大不同,css-loader 的作用仅仅是处理 CSS 的各种加载语法,例如 @importurl() 等。而 style-loader 才是真正让样式起作用的 loader(会将 CSS 引入到 head 标签里的 style 标签中)。因此这两个一般配合使用:

{
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            }
        ]
    }
}

还需要注意的是:webpack打包时是按数组从后往前的顺序将资源交给loader处理的(先处理数组的最后一项),因此要把最后生效的放在前面。

loader options

有时候使用一个 loader 时,可能要对它进行一些配置,例如 babel-loader,babel 的一些配置就可以写在 options 里,当然也可以建一个 .babelrc 文件进行配置。当一个 loader 需要配置时,它就不能在 use 属性里是个单纯的字符串了,而应是一个对象。

{
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [{
                    loader: 'style-loader',
                    options: {
                        // 将样式放到顶部
                        // 当 HTML 模板中也有 CSS 样式(通过 style 标签写的),你又不想被覆盖掉,可以将 引入的 CSS 放到最顶部防止原来的样式被覆盖。
                        insertAt: 'top',
                    }
                },{
                    // 对 css-loader 配置时,是个对象
                    loader: 'css-loader',
                    options: {
                        // css-loader 的配置项
                    }
                }]
            }
        ]
    }
}

需要注意的是,css 中还不能书写背景图片路径(例如:background: url())。不然会报错。因为加载的不是样式,而是图片,在 webpack 中,想要加载图片,还需要使用 file-loader,之后会介绍。

CSS Module

在书写 css 规则时,可能有些元素的类名会重复,导致样式被覆盖,为了解决全局污染的问题,可以把 class 命名写长一点、加一层父级选择器、降低冲突的几率。

在 css-loader 中就可以配置 css module,达到降低类名冲突的目的。

{
	loader: 'css-loader',
	options: {
		modules: true,
	}
}

css-loader 默认的哈希算法是 [hash:base64],会将类名编译成 base64 的字符串。除此之外,还可以定制。

{
	loader: 'css-loader',
	options: {
		mudules: true,
		localIdentName: '[name]__[local]--[hash:base64:5]'
	}
}

// 或者使用这种的方式:
{
	loader: 'css-loader?modules&localIdentName=[name]__[local]--[hash:base64:5]'
}

配置项含义:

  • [name] css 的模块名;
  • [local] 指原本的编译器标识符,比如 css 类名;
  • [hash:base64:5] 表示是一个 5 位的 hash 值,这个值是根据模块名和标识符计算的,因此不同模块中相同的标识符也不会造成样式冲突;

如果在某些样式中不想使用 css module,可以使用:global(.className)的语法,声明一个全局规则。凡是这样声明的 class,都不会被编译成哈希字符串。

参考:CSS Modules 用法教程

sass-loaderless-loader

sassless 是 CSS 的预处理器,需要安装。而且最终会编译成 CSS,因此我们还需要 style-loadercss-loader。。

module: {
    rules: [
        {
            test: /\.(sa|sc)ss$/,
            use: ["style-loader", "css-loader","sass-loader"]
        },
        {
            test: /\.less$/,
            use: ["style-loader", "css-loader", "less-loader"]
        }
    ]
}

postcss-loader

下载:npm install postcss-loader
配置:

// 不需要再次创建新的 loader 对象,应该在之前的 style-loader css-loader 之后直接添加 postcss-loader 即可
{
    test: /\.(c|sa|sc)ss)$/,
    // 顺序很重要
    use: ['style-loader','css-loader','postcss-loader', 'sass-loader'],
},{
	test: /\.(c|le)ss)$/,
	use: ['style-loader','css-loader','postcss-loader', 'less-loader'],
}

需要注意的是:使用多个 loader 时,loader 的加载是有顺序的,loader 的加载是从右到左。因此,less-loader 或者 sass-loader 先执行,让代码先转成原生的CSS,然后使用 postcss-loader 优化CSS属性(比如添加属性后缀),然后是 css-loader 将CSS文件中 @import 导入的文件添加进来,最后使用 style-loader 将 CSS 样式添加到 html 的 style 标签中。

配置 PostCSS

这里需要创建一个文件 —— postcss.config.js 在项目根目录下。

自动添加后缀 —— autoprefixer

使用之前需要先下载。

const autoprefixer = require('autoprefixer');

module.exports = {
    plugins: [
        autoprefixer({
            // 需要支持的特性(这里添加了 grid 布局)
            grid: true,
            // 浏览器兼容
            overrideBrowserList: [
                '>1%',  // 浏览器份额 大于 1% 的。
                'last 3 versions',  // 兼容最后三个版本
                'android 4.2',
                'ie 8'
            ],
        })
    ]
};
postcss-preset-env 插件

这个插件可以让我们在应用中使用最新的 CSS 语法特性。同样需要下载:

yarn add postcss-preset-env -D

使用:

// postcss.config.js

const autoprefixer = require('autoprefixer');
const postcssPresetEnv = require('postcss-preset-env');

module.exports = {
    plugins: [
        autoprefixer({
            grid: true,
            overrideBrowserList: [
                '>1%',
                'last 3 versions',
                'android 4.2',
                'ie 8'
            ],
        }),

        postcssPresetEnv({
            state: 3,
            features: {
                'color-mod-function': {
                    unresolved: 'warn'
                },
                browsers: 'last 2 versions'
            }
        })
    ]
};

babel-loader

babel-loader 很重要,使用 babel-loader可以让我们写的 JS 代码更加兼容浏览器环境。配置 babel-loader 时需要下载好几个其他的包 。这三个是最核心的模块。

yarn add babel-loader @babel/core @babel/preset-env -D

主要作用如下:

  • babel-loader 它是 babel 与webpack协同工作的模块;
  • @babel/core babel 编译器的核心模块;
  • @babel/preset-env 它是官方推荐的预置器,可根据用户设置的目标环境自动添加所需的插件和补丁来编译 ES6+ 代码。
    具体配置如下:
rules: [
    {
        test: /\.js$/,
        // 不要编译 node_modules 下面的代码
        exclude: path.join(__dirname,'../node_modules'),
        use: {
            loader: "babel-loader",
            options: {
                // 当为 true 时,会启动缓存机制,
                // 在重复打包未改变过的模块时防止二次编译
                // 这样做可以加快打包速度
                "cacheDirectory": true,
            }
        }
    }
]

对于 options 其它部分,可以在项目根目录下新建一个 .babelrc 文件。.babelrc 文件相当于一个 json 文件。它的配置项大概是这样的:

{
    "presets": [],
    "plugins": [],
}

比如要配置的一个内容:

{   
    "presets": [
        ["@babel/env",      // 每一个 preset 就是数组的每一项
            // 当有的 preset 需要配置时,这一项将也是一个数组
            // 数组的第一项是 preset 名称,第二项是该 preset 的配置内容,是一个对象
            {   // @babel/preset-env 会将 ES6 module 转成 CommonJS 的形式
                // 将 mudules 设置成 false,可以禁止模块语句的转化
                // 而将 ES6 module 的语法交给 webpack 本身处理
                "mudules": false,
                // targets 可以指定兼容的各个环境的最低版本
                "targets": {
                    "edge": "17",
                    "firefox": "60",
                    "chrome": "67",
                    "safari": "11.1"
                }
            }
        ]
    ],
    "plugins": [
        // 语法转换(ES6转ES5)将常用到这个包
        // 在开发环境下载
        // 下载这个插件后还需要下载另一个包:@babel/runtime
        // @babel/runtime 需要下载到生产环境中(--save)。不需要配置
        "@babel/plugin-transform-runtime",
    ]
}

env 的 targets 属性,可以配置的环境名称有:chromeoperaedgefirefoxsafariieiosandroidnodeelectron。当然 targets 的值也可以是一个字符串,例如:"targets": "> 0.25%, not dead" 表示仅包含浏览器具有> 0.25%市场份额的用户所需的polyfill和代码转换。

除了使用 @babel/preset-env 解决语法兼容性问题之外,也可以使用 @babel/plugin-transform-runtime + @babel/runtime 的方式来解决。使用前需要先下载。

关于 babel-runtime 的作用可以参考:@babel/preset-env 与@babel/plugin-transform-runtime 使用及场景区别

ts-loader

使用 ts-loader 可以让我们使用 typescript 来编写 js 代码。安装该 loader 后,还要安装 typescript。

yarn add ts-loader typescript -D
rules: [
    {
        test: /\.ts$/,
        use: "ts-loader",
    }
]

可以使用 tsc --init 命令生成 ts 配置文件,进一步地配置 ts 语言环境。

eslint-loader

eslint 是 JS 语法的校验器,它提供了一个 loader:eslint-loader。使用之前需要先下载:

yarn add eslint eslint-loader

配置如下:

{
    rules: [
        {
            test: /\.js$/,
            use: {
                laoder: 'eslint-loader',
            }
        }
    ]
}

设置好 loader 后,还要在项目根目录下建一个 .eslintrc.json 文件再进行其他配置。

当然,也可以来到这个网址 https://eslint.org/demo/,下载默认的配置文件。下载好后把文件修改成 .eslintrc.json 名称(名称前有一个点),然后把该文件剪切到项目根目录下。

需要注意的是,loader 的执行顺序是从右到左(对于一个规则,多个loader的情况,配置 .css laoder时,use 项中有多个 loader),从下到上(对于一个多个规则,比如同是处理 .js 文件的配置,写了好几个规则(test)),因此,eslint-loader 应该放在所有 .js 规则中的最后一个(先检验,再做别的事情)。

{
    rules: [
        {
            test: /\.js$/,
            use: [
                loader: "babel-loader",
            ]
        },{
            test: /\.js$/,
            use: [
                loader: "eslint-loader",
            ]
        }
    ]
}

也可以使用 options 中的 enforce 配置项:

{
    rules: [
        {
            test: /\.js$/,
            use: [
                loader: "eslint-loader",
                options: {
                    // 强制让这个 loader 最先执行
                    enforce: "pre"
                }
            ]
        },{
            test: /\.js$/,
            use: [
                loader: "babel-loader",
            ]
        }
    ]
}

enforce 默认值是 normal,除了 prenormal 之外,还有 post,表示强制最后执行在 normal 之后执行这个loader。

处理 react jsx 语法:@babel/preset-react

下载: yarn add @babel/preset-react -D。当然,如果想使用 react,也要下载。在 .babelrc 的presets项中添加一个preset:

{
    "presets": [
        ["@babel/env",
            {
                "modules": false,
                "targets": {
                    "ie": 9
                }
            }
        ],
        "@babel/react"
    ]
}

这个时候就可以愉快的使用 react 了!

处理 .jsx 的文件

用 react 写的文件不光可以使用 .js后缀,也可以使用 .jsx 文件后缀。但想要使用,这需要配置,不然会报错。来到 webpack 配置文件,添加一个 loader 项:

{
    test: /\.jsx?$/,
    use: "babel-loader",
},{
	test: /\.tsx?$/,
	use: "ts-loader"
}

暴露全局变量

在 webapck 中使用 jquery 时,可以这么引入:

import $ from 'jquery';

但是这个 $ 变量并不在全局下(window)。如果我们想要将改变量暴露到全局中,需要使用 expose-loader

下载:yarn add expose-loader。将 jquery 模块暴露出来:

import $ from "expose-loader?$!jquery";

?$! 中的 $ 就是指被暴露的变量名(expose-loader ? ! 是固定格式)。

当然,如果不想这么写,也可以在 rules 中进行配置:

{
    rules: [
        test: require('jquery'),
        use: 'expose-loader?$'
    ]
}

配置好后,使用jQuery时,还需要进行引入:import $ from 'jquery'。如果不想每次都引入(或说不用引入),可以使用一个插件:provide-plugin。使用时不需要下载,webpack 自带,然后在 plugins 配置项中配置:

{
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery'
        })
    ]
}

如果你在 HTML 中引入了第三方模块使用 script 标签,但在开发中如果再使用 import $ from 'jquery',webpack 就会多打包一次。为了不让 webpack 这样做,可以添加一个配置:

module.exports = {
    plugins: [],
    // ...
    externals: {
        jquery: 'jQuery'
    }
}

html-loader

有了这个 loader,我们可以将一个 html 文件通过 JS 加载进来。比如这样:

rules: [
    {
        test: /\.html$/,
        use: 'html-loader'
    }
]

// loader.html
<h1>Hello World!</h1>

// index.js
import html from './loader.html';
document.write(html);

file-loaderurl-loader

file-loader 用于打包文件类型的资源。比如 CSS 的背景图片和字体、HTML 的 img 标签中的 src 路径等。

rules: [
    {
        test: /\.(png|jpg|gif)$/,
        use: "file-loader",
    }
]

这样就可以对 png、jpg、gif类型的图片文件进行打包,而且可以在 JS 中加载图片。

file-loader 中的 options

主要有两个配置项:

  1. name,指定打包后文件的名字,默认是 hash 值加上文件后缀。也可以制定成:[name].[ext] 表示原来的名字和文件后缀。
  2. publicPath 这里的 publicPath 与 output 中的 publicPath 一样,在这里指定后,会覆盖原有的 output.publicPath。 比如:
rules: [
    {
        test: /\.(png|jpg|gif)/,
        use: {
            loader: "file-loader",
            options: {
                name: '[name].[ext]',
                publicPath: "",
            }
        }
    }
]
url-loader

file-loader 作用类似,唯一的不同是:url-loader 可以设置一个文件大小的阈(yù)值。当大于该阈值时与 file-loader 一样返回 publicPath,而小于阈值时则返回文件的 base64 形式编码。比如:

{
    test: /\.(png|jpg|gif)$/,
    use: {
        loader: "url-loader",
        options: {
            // 当文件小于这个值时,使用 base64 编码形式
            // 大于该值时,使用 publicPath 
            // 这个属性在 file-loader 中是没有的。
            limit: 10240,	// 10KB
            name: '[name].[ext]',
            // 将所有的图片打包到 img 目录下
            outputPath: 'img/',
        }
    }
}
html-withimg-loader

当我们在 HTML 模板中有 img 标签时,img 标签的 src 的路径并不会被 webpack 转化(因为没有被依赖,图片将不会被打包),可以使用 html-withimg-loader 打包 src 对应的资源,使用之前同样需要先下载。然后配置:

{
    rules: [
        test: /\.html/,
        use: 'html-withimg-loader'
    ]
}

vue-loader

它可以将 .vue 文件转换成 JavaScript 模块。配置如下:

{
	test: /\.vue$/,
	use: 'use-loader',
}

在 vue 中,可以使用 vue-style-loader 代替 style-loader。配置如下:

const VueLoaderPlugin = require('vue-loader/lib/plugin');
// ...
{
	rules: {
	    test: /\.vue$/,
	    loader: 'vue-loader',
	}
}
// ...
plugins: {
	new VueLoaderPlugin()
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值