Webpack系列笔记(二):webpack核心知识(上)

2.1 什么是 Loader?

如果想要打包一个 png 图片,webpack 是不会知道要怎么打包的,因为它默认只知道怎么打包 js 文件,因此就需要在配置文件中的 module 配置项告诉 webpack 怎么打包 png 模块

loader 的执行有顺序,是从后往前执行,所以对css打包时,需把 style-loader 写在 css-loader 前面,使 css-loader 先执行

const path = require('path')

module.exports = {
  mode: 'development', // 打包模式,默认是 production
  entry: {
    main: './src/index.js', // 打包的入口文件,即打包 index.js 文件
  },
  module: { // 打包的模块配置
    rules: [{ // 打包规则
      test: /\.png$/, // 如果遇到 .png 结尾的文件
      use: { // 使用
        loader: 'file-loader' // 使用 file-loader 来打包
      }
    }]
  },
  output: {
    filename: 'bundle.js', // 打包后的文件名
    path: path.resolve(__dirname, 'dist'), // 打包后的文件放在哪个文件夹内,这里必须是绝对路径
  }
}

通过以上例子,我们就知道了 loader 其实是一个 webpack 的打包方案,它知道对于某个特定的文件,webpack应该如何打包。

2.2 使用loader打包静态资源文件

2.2.1 打包图片资源

使用 file-loader 打包的 png 图片默认会重新起一个随机的文件名放到配置的出口文件夹下,我们想要不改变文件名打包就需要对 loader 进一步做配置:

module: {
    rules: [{
        test: /\.(png|jpg|gif)$/,
        use: {
            loader: 'file-loader',
            options: {
                // 这种配置语法叫做 placeholder, 占位符
                name: '[name].[ext]' // 打包后的文件名以及后缀不变
            }
        }
    }]
}

关于 file-loader 的更多信息,请参考官网

除了 file-loader 外,使用 url-loader 也能完成相同的功能,file-loader能做到的事,url-loader 都能做,对于图片文件来说,file-loader 是将图片打包到出口文件夹下指定文件夹内,通过外部引入的方式使用图片,而 url-loader 是通过将图片转成 base64 字符串,直接使用,不会单独生成一个图片文件。

怎么选择file-loader 和 url-loader 打包图片

  • file-loader 打包图片是引入外部文件,会形成一次 http 请求,当图片资源很大的时候,使用file-loader
  • url-loader 打包图片会把图片转成 base64 字符串,虽然不会去进行一次 http 请求,但如果图片很大,js 的加载就会占用很多时间,页面很久才会展示出来

所以:当图片资源很大的时候使用 file-loader,图片资源很小的时候使用 url-loader

我们一般选用url-loader,因为它能设置条件来动态选择是单独打包文件,还是转成base64到出口文件中,配置如下:

module: {
    rules: [{
        test: /\.(png|jpg|gif)$/,
        use: {
            loader: 'url-loader',
            options: {
                // 这种配置语法叫做 placeholder, 占位符
                name: '[name].[ext]', // 打包后的文件名以及后缀不变
                outputPath: 'images/', // 打包后的图片文件会放到出口文件夹中的 images 文件夹下
                limit: 2048 // 当图片大小大于 2048bit,即大于2Kb时,url-loader就不会将图片转成base64字符串,而是单独生成一个文件,打包到outputPath指定文件夹内
            }
        }
    }]
}
2.2.2 打包CSS

打包CSS,需要两个loader,一个是 style-loader,另一个是 css-loadercss-loader可以分析出css文件间的关系,例如使用 @import 时几个css间的引用关系,css-loader 会把他们打包成一个css文件;style-loader在得到 css-loader 生成的 css 文件后, 会把这个文件挂载到页面的 <head></head> 部分。

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

同理,如果使用 sasslessstylus 写样式时,也要引入相应的 loader

使用sass,需要安装 sass-loadernode-sass

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

使用less,需安装 less-loader

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

使用stylus,需安装stylusstylus-loader

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

当我们使用一些 CSS3 的样式时,一般会在样式前面加厂商前缀,这时我们可以使用 postcss-loader 来帮助我们,使webpack打包时自动加上厂商前缀,使用 postcss-loader 需在根目录下创建一个 postcss.config.js 的配置文件,打包时,postcss-loader 会自动的在这个配置文件中读取配置信息,具体配置如下:

我们先安装所需的依赖包:

# postcss-loader
npm i postcss-loader -D

# postcss-loader 所需的插件
npm i autoprefixer -D

postcss.config.js 配置文件:

module.exports = {
  plugins: [
    require('autoprefixer') // 使用 autoprefixer 插件
  ]
}

webpack.config.js 配置文件中 module 配置

// 没有在 css 中使用 @import 语法时
module: {
    rules: [{
        test: /\.css$/,
        use: ['style-loader', 'postcss-loader']
    }]
}

// 在 css 中使用了 @import 语法时
module: {
    rules: [{
        test: /\.css$/,
        use: [
            'style-loader',
            { 
                loader: 'css-loader', 
                options: { 
                    importLoaders: 1 // 下面有多少个loader,就写多少,这里下面只有一个postcss-loader,所以只写1
                } 
            },
            'postcss-loader'
        ]
    }]
}

使用postcss-loader 后,浏览器样式截图:
在这里插入图片描述

2.3 模块化CSS

当使用模块化创建项目的时候,我们会遇到这种情况:一个模块里的css会作用到另一个模块,相当于写了一个全局样式,但很多时候我们只想让每个模块里的css作用于本模块,于是有了CSS模块化的概念。

在webpack配置中,只需在css-loader 的 options 中配置 modules: true,在引入模块的 js 文件中,添加class的时候也做修改

webpack.config.js:

module: {
    rules: [{
      test: /\.css$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 1,
            module: true
          }
        },
        'postcss-loader'
      ]
    }]
  }

引入模块的js文件:

import bg from './bg.png';
import style from'./index.css';
import Header from './header.js';

Header();
var img = new Image();
img.src = bg;
img.classList.add(style.bg);

var root = document.getElementById('root');

root.append(img);

P.S.:如果需使用字体文件时,只需要使用 file-loader 即可,不用做太多配置

具体各种文件类型的打包可以查看官网

2.4 插件

plugin 可以在webpack运行到某个时刻,帮助webpack做一些特定的事情,类似vue、react的生命周期函数

2.4.1 html-webpack-plugin

之前我们打包的时候,调用出口文件(我这里是 bundle.js)的 index.html 文件总需要我们自己在出口文件夹(/dist)下创建,手动引入 bundle.js。webpack 的插件(html-webpack-plugin)可以很好的帮助我们免去这一步。

html-webpack-plugin 会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个HTML文件中,但在没做任何配置的时候,它并不会对这个 HTML 文件做任何的操作(不会创建dom元素,即不会创建js中元素需挂载的目标),我们可以对plugins做配置来让它创建这个dom元素,配置如下:

// webpack.config.js
// 首先引入 html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');

// 在配置项中增加
plugins: [new HtmlWebpackPlugin({
    template: 'src/index.html' // 以自建的src/index.html为模板创建 html 文件,只需在模板文件中创建dom元素
})]

注意:

一般来说,我们打包后的出口文件夹里的东西并不会被删除,我们做第二次打包时,只会覆盖出口文件夹的内容,如果你修改了配置文件中出口文件 名,那么就会出现两个出口文件(一个是修改前的,一个是修改后的),这时候我们可以借助 clean-webpack-plugin 将我们的出口文件夹清空,再打包

plugins: [
  new HtmlWebpackPlugin({
    template: 'src/index.html'
  }), 
  new CleanWebpackPlugin() // 在打包前清空出口文件夹
]

2.5 entry 和 output

entry入口文件我们可以将它写成一个字符串

entry: './src/index.js'

如果没有在output中指明出口文件filename,那么默认的出口文件名会是 main.js 。实际上,入口文件可以是一个对象,出口文件的默认文件名就是这个对象的键,即,上面的字符串方式我们可以写成:

entry: {
    main: './src/index.js'
}

如果我们想要将入口文件打包成两个不同文件名的文件,只需在entry中多加一个键值对,再再output中配置一下filename,即可:

entry: {
    main: './src/index.js',
    sub: './src/index.js'
},
output: {
    filename: '[name].js' // 通过占位符 name 打包生成不同的文件名的文件
}

就可以生成两个文件了。

当使用了 html-webpack-plugin 插件,打包生成的出口文件 index.html 中就会自动引入打包好的js文件,如果我们想在这前面加个前缀,可以通过配置 output 的 publicPath 来实现:

output: {
    publicPath: 'https://www.cdn.com.cn',
    filename: 'bundle.js', // 打包后的文件名
    path: path.resolve(__dirname, 'dist'), // 打包后的文件放在哪个文件夹内,这里必须是绝对路径
  }

2.6 SourceMap 配置

SourceMap 是一个映射关系,他知道出口文件中打包的代码对应的是源代码文件的哪一行

source-map: 会自动生成一个.map文件,inline: 就会把生成的 .map 文件合并到出口文件中,cheap: 只提示多少行出错,不提示多少列,module: 不知管业务代码,也管 loader 的报错

开发者模式mode: 'development' 下,是默认打开 SourceMap 的,我们可以加个配置项,关闭掉 SourceMap:

module.exports = {
  mode: 'development', // 打包模式,默认是 production
  devtool: 'none'
}

经实践,想要得到较好的报错提示信息,且打包速度也较快,可以将 SourceMap 设置成 cheap-module-eval-source-map

module.exports = {
  mode: 'development', // 打包模式,默认是 production
  devtool: 'cheap-module-eval-source-map'
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值