webpack基础篇(一)

112 阅读7分钟

本文是webpack的基础篇,将介绍:

  • webpack基本语法
  • loader && plugins
  • 资源解析
  • 热更新
  • 文件指纹
  • html,css,js代码压缩

webpack基本语法

npm run build运行构建

{
  ...,
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  ...
}

原理:模块局部安装会在node_modules/.bin目录创建软链接

entry

入口起点(entry point)  指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。

image.png

默认值是 ./src/index.js,可以通过在 webpack configuration 中配置 entry 属性,来指定一个(或多个)不同的入口起点。例如:

module.exports = {
  entry: './path/to/my/entry/file.js',
};

output

output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。

你可以通过在配置中指定一个 output 字段,来配置这些处理过程:

webpack.config.js

const path = require('path');

module.exports = {
  entry: {
    index: './src/index.js',
    search: './src/search.js'
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
};

loaders

webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。

loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。

其本身是一个函数,接受源文件作为参数,返回转换的结果。

常见的loaders

名称描述
babel-loader转换es6、es7等新特性语法
css-loader支持.css文件的加载和解析
less-loader将less文件转换成css
ts-loader将TS转换成JS
file-loader进行图片、字体等的打包
raw-loader将文字以字符串的形式导入
thread-loader多进程打包JS和CSS

webpack 的其中一个强大的特性就是能通过 import 导入任何类型的模块(例如 .css 文件),其他打包程序或任务执行器的可能并不支持。

在更高层面,在 webpack 的配置中,loader 有两个属性:

  1. test 属性,识别出哪些文件会被转换。
  2. use 属性,定义出在进行转换时,应该使用哪个 loader。

webpack.config.js

const path = require('path');

module.exports = {
  output: {
    filename: 'my-first-webpack.bundle.js',
  },
  module: {
    rules: [{ test: /.txt$/, use: 'raw-loader' }],
  },
};

test: 指定匹配规则
use: 指定使用的loader名称

语义化解释:

“嘿,webpack 编译器,当你碰到「在 require()/import 语句中被解析为 '.txt' 的路径」时,在你对它打包之前,先 use(使用)  raw-loader 转换一下。”

loader是链式调用的,执行顺序是从右到左的

pulgins

loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。作用于整个构建过程。

plugins

名称描述
CommonsChunkPlugin将chunks相同的模块代码提取成公共js
CleanWebpackPlugin清理构建目录
ExtractTextWebpackplugin将CSS从bunlde文件里提取成一个独立的css文件
CopyWebpackPkugin将文件或者文件夹拷贝到构建的输出目录
HtmlWebpackPlugin创建html文件去承载输出的bundle
UglifyjsWebpackPlugin压缩js
ZipWebpackplugin将打包出的资源生成一个zip包

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件

module.exports = {
  module: {
    rules: [{ test: /.txt$/, use: 'raw-loader' }],
  },
  plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};

在上面的示例中,html-webpack-plugin 为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中。

mode

通过选择 developmentproduction 或 none 之中的一个,来设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production

module.exports = {
  mode: 'production',
};

想要了解更多,请查阅 mode 配置,这里有具体每个值相应的优化行为。

浏览器兼容性(browser compatibility)

Webpack 支持所有符合 ES5 标准 的浏览器(不支持 IE8 及以下版本)。webpack 的 import() 和 require.ensure() 需要 Promise。如果你想要支持旧版本浏览器,在使用这些表达式之前,还需要 提前加载 polyfill

为什么需要构建工具

  1. 转换es6语法
  2. 转换JSX
  3. CSS前缀补全/预处理器
  4. 压缩混淆
  5. 图片压缩

资源解析

解析es6

使用babel-loader,配置文件是.babelrc

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ],
    "plugins": [
        "@babel/proposal-class-properties"
    ]
}

presets:一系列plugin的集合
plugins:一个plugin对应一个功能

解析CSS

style-loader将样式通过标签插入到head中。 css-loader用于加载.css文件,并且转换成common.js对象。
less-loader将less文件解析为css文件

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

解析文件资源

file-loader用于处理文件

解析图片

{
    test: /.(png|jpg|gif|jpeg)$/,
    use: 'file-loader'
}

url-loader也可以处理图片和字体,可以设置较小资源自动base64

webpack中的文件监听

文件监听是在发现源码发生变化时,自动重新构建出新的输出文件。

webpack开启监听模式,有两种方式:

  • 启动webpack命令时,带上--watch参数
  • 在配置webpack.config.js中设置watch: true

原理分析
轮询判断文件的最后编辑时间是否变化
某个文件发生了变化,并不会立即告诉监听者,而是先缓存起来,等aggregateTimeout

module.export = {
    // 默认false,不开启
    watch: true,
    // 只有开启监听模式时,watchoptions才有意义
    watchOptions: {
        // 默认为空,不监听的文件或者文件夹,支持正则匹配
        ignored: /node_modules/,
        // 监听到变化发生后等300ms再去执行,默认300ms
        aggregateTimeout:300,
        // 判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的,默认每秒文件1000次
        poll:1000
    }
}

webpack热更新(webpack-dev-server)

模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除 模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:

  • 保留在完全重新加载页面期间丢失的应用程序状态。
  • 只更新变更内容,以节省宝贵的开发时间。
  • 在源代码中对 CSS / JS 进行修改,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。

webpack-dev-server热更新具有以下特性:

  • 不刷新浏览器
  • 不输出文件,而是放在内存中
  • 使用HotModuleReplacementPlugin插件(webpack内置插件,不需要额外导入)

安装

npm i webpack-dev-server

代码配置

const webpack = require('webpack');

module.exports = {
    ...,
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        static: './dist',
        hot: true
    }
};

原理分析

  • webpack compile:将js编译成bundle
  • HRM Server: 将热更新的文件输出给HRM Runtime
  • Bundle server:提供文件在浏览器的访问
  • HRM Runtime:会被注入到浏览器,更新文件的变化
  • bundle.js:构建输出的文件

原理可以用这个图概括,这里直接引用大佬的文章:juejin.cn/post/684490… image.png

文件指纹

文件指纹是指:打包后输出的文件名的后缀,可以用于版本管理。

image.png

文件指纹如何生成,主要有以下三种形式:

  • Hash:和整个项目的构建相关,只要项目文件有修改,整个项目构建的hash值就会更改
  • Chunkhash:和webpack打包的chunk(模块)有关,不同的entry会生成不同的chunkhash值
  • Contenthash:根据文件内容来定义hash,文件内容不变,则contenthash不变(CSS文件指纹,一般用这种形式)

JS的文件指纹设置

设置output的filename,使用[chunkhash]

module.exports = {
    entry: {
        app: './src/index.js'
    },
    output: {
        filename: '[name][chunkhash:8].js',
        path: __dirname+ '/dist/'
    }
};

CSS的文件指纹设置

设置MiniCssExtractPlugin的filename,使用[contenthash]

module.exports = {
    entry: {
        app: './src/index.js'
    },
    output: {
        filename: '[name][chunkhash:8].js',
        path: __dirname+ '/dist/'
    },
    plugins:[
        new MiniCssExtractPlugin({
            filename: '[name][contenthash:8].css'
        })
    ]
};

style-loader将样式通过标签插入到head中,这个时候并没有一个独立的css文件,MiniCssExtractPlugin这个插件把这style-loader生成的css提取出来成一个独立的文件

可知MiniCssExtractPlugin与style-loader功能互斥的,一般前者用于生成环境,后者用于开发环境。

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

图片的文件指纹设置

设置file-loader的name,使用[hash]

占位符名称含义
[ext]资源后缀名
[name]文件名称
[path]文件的相对路径
[folder]文件所在的文件夹
[contenthash]文件的内容hash,默认是md5生成
[hash]文件的内容hash,默认是md5生成(32位)
[emoji]一个随机的指代文件内容的emoji
module.exports = {
    entry: {
        app: './src/index.js'
    },
    output: {
        filename: '[name][chunkhash:8].js',
        path: __dirname+ '/dist/'
    },
    modules: {
        rules: [
            {
                test:/\.(png|svg|jpg|gif)$/,
                use:[{
                    loader: 'file-loader',
                    options: {
                        name: 'img/[name][hash:8].[ext]'
                    }
                }]
            }
        ]
    }
};

打包示例:

image.png

代码压缩

压缩属于性能的常用方式之一,代码压缩包括「HTML压缩」、「CSS压缩」、「JS压缩」。

JS文件的压缩

webpack内置了uglifyjs-webpack-plugin

CSS文件的压缩

使用optimize-css-assets-webpack-plugin,同时使用cssnano. 可以将其添加到webpackOptimization(优化)配置项.##

optimization.minimizer: 允许你通过提供一个或多个定制过的 TerserPlugin 实例,覆盖默认压缩工具(minimizer

代码示例:

modules.exports = {
  entry: {
    app: './scr/index.js'
  },
  output: {
    filename: '[name][chunkhash:8].js',
    path:__dirname + '/dist'
  },
  optimization: {
    minimizer: [
        
    ]
  }
};

For webpack v5 or above please use css-minimizer-webpack-plugin instead.

踩坑:css-minimizer-webpack-plugin这个版本的依赖运行会报错,建议使用安装量最多的3.4.1版本

压缩后: image.png

html文件的压缩

修改html-webpack-plugin,设置压缩参数

modules.exports = {
  entry: {
    app: './scr/index.js'
  },
  output: {
    filename: '[name][chunkhash:8].js',
    path:__dirname + '/dist'
  },
  plugins: [
    new HtmlWebpackPlugin({
        template: path.join(__dirname, 'src/search.html'), // html 模版所在位置
        filename: 'search.html', // 打包出来html文件名称
        chunks: ['search'], // html使用哪些chunk
        inject: true, // js自动注入html
        minify: {
            html5: true,
            collapseWhitespace: true,
            preserveLineBreaks: false,
            minifyCSS: true,
            minifyJS: true,
            removeComments: false
        }
    })
  ]
};

参考文档

webpack官方文档:webpack.docschina.org/ webpack热更新显示cannot get:www.cnblogs.com/ofnoname/p/… webpack热更新原理:juejin.cn/post/684490…