深入学习webpack 4.x核心用法及其源码(二)

上一小节我简单介绍了 webpack 的一些用法,它的核心用法我还没有介绍,webpack 默认只会对 js 的一些代码进行打包,不可以对 css 样式进行打包,或把二进制图片打包成 data URL,热更新

Loader

介绍

loader 用于对模块的源代码进行转换。例如:typescript 转换成 js,less 转换为 css 等。

使用

webpack 4.x 有三种使用 loader 的方式:

  • 配置(推荐) :在 webpack.config.js 文件中指定 loader。
  • 内联 :在每个 import 语句中显式指定 loader。
  • CLI :在 shell 命令中指定它们。

注:下面我会以配置的方式为例子,如果想了解其他两种方式的用法可以看一下官方的文档:https://www.webpackjs.com/concepts/loaders/

const path = require('path');

module.exports = {
    mode: 'development',
    entry: './src/index.js',
    module: {
        rules: [{
            test: /\.jpg$/,
            use: {
                loader: 'file-loader'
            }
        }]
    },
    output: {
        filename: 'main.js',
        path: path.join(__dirname, 'dist'),
    }
}

和上一章的代码相比,我只添加了 module 这一项,那这个 module 是什么意思呢?

module 中可以配置一些 loaderplugins 中,可以理解成 当 webpack 4.x 不知道如何打包文件时,它会在 module 配置的 规则 和 插件中寻找解决方法

loader 写在 rules 中,rules 是一个数组,其中的每一个对象基本是需要一个 testusetest 是一个正则表达式,用来匹配文件后缀名。 use 中就填写你要使用到的 loader 名称。

file-loader 是一个处理二进制文件,默认情况下,生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名。如果你不满足于默认的文件名,你可以通过 options 中的 name 进行占位符配置文件名,这是链接:https://www.webpackjs.com/loaders/file-loader/。如果你对打包生成的文件路径不满,可以通过 outputpath 进行配置。

file-loader 类似的 loader 是 url-loader ,它可以将 二进制图片 直接转换为 base64 , 这个虽然可以带来请求的减少,但同时也会增加打包文件的体积。尤其是一个很大很大的图片的时候,这个问题尤其突出。所以最好是对文件的大小进行限制,通过 option 中的 limit (单位:byte) ,例如 limit: 2048 表示 小于 2kb 则按照 url-loader 打包,超出了就会按照 file-loader 来打包。可以参见:https://www.webpackjs.com/loaders/url-loader/

打包CSS样式表

打包 CSS 样式表需要安装 style-loadercss-loader

npm i style-loader css-loader -D

webpack.config.js 文件的代码如下:

    .
    .
    .

    module: {
        rules: [
            .
            .
            .

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

            .
            .
            .
        ]
    }

    .
    .
    .
}

注意:这两个的顺序必须是 style-loader 在前, css-loader 在后,不可颠倒

  • css-loader :用来解析样式表中用到的外部引用,例如:@importurl()
  • style-loader : 就是将 css-loader 分享出的样式挂载到头部(header区域)

css-loader 有很多其他的特性,例如二次加载,模块化css

    .
    .
    .

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

    .
    .
    .

其中 modules 表示启动 css 模块化,importLoaders 表示二次加载,那这个二次加载什么意思呢?可以理解成当确保无论这么加载都会将按照配置的loader顺序加载一遍,不会缺省loader,

less、scss 的使用

使用 less 和 sass 很简单,这里我以 less-loader 为例:

先安装:

npm i less-loader less -D

webpack.config.js

    .
    .
    .

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

    .
    .
    .

less-loader 的作用就是帮助我们把它翻译成我们看得懂的 css 样式表

学习 less-loader 配置,参见:https://www.webpackjs.com/loaders/less-loader/

学习 sass-loader 配置,参见:https://www.webpackjs.com/loaders/sass-loader/

给样式加上厂商前缀

给样式加上厂商前缀需要使用 postcss-loader

安装:

npm i -D postcss-loader

使用它需要创建一个 postcss.config.js 的配置文件,配置参见:https://www.webpackjs.com/loaders/postcss-loader/

我先安装一个 autoprefixer 的插件

npm i -D autoprefixer

postcss.config.js:

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

webpack.config.js:

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

打包字体图片

使用字体图片只需使用 file-loader 就行了

    {
        test: /\.(eot|ttf|svg)$/,
        use: ['file-loader'],
    },

插件

介绍

它很像 vue,react 的生命周期函数,可以在 webpack 运行到某个时刻的时候,帮你做一些事情

使用

下面我以 htmlWebapckPlugin 作为例子:

安装

npm i html-webpack-plugin -D

使用

module.exports = {
    mode: 'development',
    entry: './src/index.js',
    // 
    plugins: [new HtmlWebpackPlugin({
        template: 'src/template.html',
    })],
    // 可以使用模板进行打包
    output: {
        filename: 'main.js',
        path: path.join(__dirname, 'dist'),
    }
}

htmlWebpackPlugin 会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中,使用模板可以安装你的方式进行打包

devtool

介绍

主要是当我们源代码错误时,可以根据控制台输出的错误信息来定位我们到底是哪里出错了。这个功能很有用

可以参考:https://www.webpackjs.com/configuration/devtool/ 的表格,哪里有很多配置项。

默认是 devtool: 'none',当我们在生产时一般我们使用 cheap-module-eval-source-map,线上的时候一般使用 cheap-module-source-map

虽然有很多配置项,但我们还是可以总结出一些规律:

  • souce-map :生成一个 .map.js 的映射文件
  • inline :把 .map.js 的内容打包合并到我们输出文件中
  • cheap : 表示只提示哪一行出错,不精确到哪一个字符,只提示业务中出现错误的代码,不提示用到的第三方的错误的代码
  • module :会提示第三方的错误代码
  • eval :会用到 eval() 这种方式打包

自动监听并保存代码

两种方式都要使用 package.js 文件的 script:

第一种(webpack)

  "scripts": {
    "build": "webpack --watch"
  },

不能使用ajax

第二种(使用 webpack-dev-server 推荐)

不仅可以自动打包,还可以自动刷新浏览器

webpack.config.js :

module.exports = {
    mode: 'development',
    devtool: 'cheap-module-eval-source-map',
    entry: {
        main: './src/index.js',
    },
    devServer: {
        contentBase: './dist',
        open: true,
        proxy: {
            'api' :  'http://localhost:3000'
        }
    },

    .
    .
    .
}

其中:

  • contentBase :表示开启服务器的路径,默认自动打开 index.html
  • open :开启服务器时,自动打开浏览器
  • proxy :跨域代理

配置了这些还需要在 package.json 中使用 script 添加一项:

  "scripts": {
    "start": "webpack-dev-server"
  },

其实我们可以不配置上面的东西,仅仅借用 script 就可以实现,这种方式更简单:

  "scripts": {
    "dev": "webpack-dev-server --open --port 3000 --contentBase dist"
  },

为什么我们一定要使用服务器的方式打开文件呢?现在的项目中都会跨域使用ajax发起跨域请求。如果以 file: 的方式打开的文件是不可以发出ajax请求的,会报错。

开启热更新

webpack.config.js :

module.exports = {
    .
    .
    .

    devServer: {
        contentBase: './dist',
        open: true,
        hot: true,
        hotOnly: true,
    },

    .
    .
    .
}

使用 BABLE 写 ES6

介绍

babel 可以将 ES6 的语法转换成 ES5 的语法

安装

第一种:polyfill 打包业务中使用

会污染全局作用域

npm install --save-dev babel-loader @babel/core
npm install @babel/preset-env --save-dev
npm install --save @babel/polyfill

@babel/core 是一个 babel 的核心库,就是用于语法转换的

第二种:transform-runtime 打包库文件中使用

以闭包的形式保护了作用域

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
npm install --save @babel/runtime-corejs2

使用

webpack.config.js:

第一种:polyfill 打包业务中使用

const path = require('path');

module.exports = {
    //...
    module: {
        rules: [
            { 
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" ,
                options: {
                    "presets": [["@babel/preset-env",{
                        useBuiltIns: 'usage'
                    }]]
                },
            },
        ]
    },
    //...
}

配置完后,还要在输入的主文件中的第一行导入 import "@babel/polyfill",如果配置了 useBuiltIns: 'usage'@babel/polyfill 会自动导入,所以可以不用导入

第二种:transform-runtime 打包库文件中使用

const path = require('path');

module.exports = {
    //...
    module: {
        rules: [
            { 
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" ,
                options: {
                    "plugins": [
                        [
                          "@babel/plugin-transform-runtime",
                          {
                            "corejs": 2,
                            "helpers": true,
                            "regenerator": true,
                            "useESModules": false,
                          }
                        ]
                      ]
                },
            },
        ]
    },
    //...
}

如果你感觉 option 中的代码比较长,可以创建一个 .babelrc 的文件,将 option 中的代码复制到 .babelrc 中就行了,不能有注释

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值