Webpack4学习笔记

    xiaoxiao2023-12-02  185

    其实很早之前就听说过webpack,但一直没有认真去看过官方文档,闲暇时舍近求远的去看一些教学视频,反而看的迷迷糊糊不知所云;今天终于抽出“大块儿”时间,细读了一下官方文档,才发现对于新事物,了解它最快的方法就是仔细阅读官方文档!下面是对今天学习内容的一些清单,以便回顾。

    Webpack是什么

    这张图是webpack官网对webpack是什么的诠释,webpack是一个静态模块打包的工具,他可以将工程中的静态资源根据我们声明的依赖关系,打包整理出一个或多个能正常运行的输出文件。在webpack中,所有的静态资源都可以被处理为一个模块,包括js、图片、css、字体。

    Webpack安装

    # 安装到项目目录 npm install --save-dev webpack # 全局安装 npm install -g webpack

    Webpack中的概念

    webpack中最重要的概念有以下几个:

    Entry, 工程的入口文件配置Output, 打包的输出的文件配置Chunk, webpack处理和输出的包Loaders, 加载器,用于处理各种不同类型的模块,可扩展Plugins, 插件,在webpack打包过程中不同时机执行一些任务,比如清除打包目录、复制静态文件、抽取css文件Mode, 区分开发环境和生成环境

    entry

    Entry,顾名思义就是工程的入口文件,Entry的配置写法有三种:

    对象,可配置多入口,可配置chunk名,灵活可扩展,最常用,一个属性就是一个entry chunk module.exports = { entry: { app: './src/app.js', vendors: './src/vendors.js' } }; 字符串, 最简单直接方式,单入口,chunk名默认为main module.exports = { entry: './path/to/my/entry/file.js' }; 数组, 多入口,将多个入口文件打包为一个chunk,chunk名默认为main module.exports = { entry: ['./path/to/my/entry/file.js', './path/to/my/entry/file1.js'] };

    output

    Output用于配置打包输出的文件,包括输出文件的文件名、输出路径、静态资源地址,这里列出最常用的4种:

    module.exports = { entry: { app: './src/app.js', search: './src/search.js' }, output: { filename: 'js/[name].js', chunkFilename: 'js/[name].js', path: __dirname + '/dist', publicPath: 'http://cdn.example.com/assets/[hash]/' } };

    配置项如下:

    filename: 配置输出文件名,可添加路径配置(例子中js/),可使用占位符,占位符有以下5种: name: chunk名,在该例子中就是app和searchhash: 模块标识符的hash值,跟工程内容相关chunkhash: chunk内容的hash值,只和当前chunk内容相关,可用于缓存设置id: 模块标识符query:模块查询参数,取文件名中?后面的内容 path: 文件的输出路径,必须是绝对地址publicPath: 用于设置打包过程中产生的静态文件的最终引用地址,静态文件的最终引用地址为output.publicPath + output.filename,很多时候,你的静态文件放置在CDN上,通过publicPath就可以很方便地设置。如果你的静态引用地址在运行时才能确定,可以在入口文件中设置__webpack_public_path__ 来决定publicPath的值: __webpack_public_path__ = myRuntimePublicPath; // rest of your application entry chunkFilename: 用于设置非entry入口的chunk的输出文件名,非entry入口的chunk一般在动态引入和CommonsChunkPlugin中产生,这是一个Plugin,用于抽取公共代码或者进行代码分割等操作,该plugin已经在webpack4中废除,由webpac4内置的optimization.splitChunks替代。

    loaders

    oaders可以理解为不同类型模块的处理器,将这些类型的模块处理为浏览器可运行和识别的代码。比如babel-loader将es6以上代码转换为es5代码;sass-loader将sass代码解析为css代码;url-loader和file-loader可以将图片、字体等静态文件解析为base64码或者静态文件地址。Loaders给我们提供了处理模块的入口,在里面可以使用全部的js功能,从而使webpack具有了强大而灵活的能力。webpack及webpack社区提供了功能强大的loader供开发者使用,你也可以自己编写loader。下面介绍一下在工程中常用的loader。

    js Loaders

    babel-loader

    使用babel将ES2015+的代码转码为ES5的代码,babel的具体配置可参考babel官网。

    modlue: { rules: [ { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: 'babel-loader } ] }

    exclude表示不处理的目录,一般node_modules中的第三方js文件不在我们的处理范围内。

    script-loader

    该loader使对应的js文件在全局环境中运行一次。比如我们在工程中使用了jquery的插件,需要全局暴露 , 我 们 就 需 要 让 j q u e r y 文 件 在 全 局 环 境 中 运 行 , 以 便 让 它 把 ,我们就需要让jquery文件在全局环境中运行,以便让它把 ,jquery便挂载到全局变量中,效果和在浏览器中加script标签一样。

    import 'jquery'; module: { rules: [ { test: /jquery$/, use: [ 'script-loader' ] } ] }

    css Loaders

    style-loader:将css模块以style标签的形式加入到html中css-loader:主要用来解析css中的静态资源,将@import和url()解析为import/require(),解析出的除css以外的静态资源,一般交给url-loader和file-loader去处理postcss-loader:可以对css进行各种处理,功能强大,比如自动添加css前缀,也可自定义插件sass-loader/less-loader:将sass/less代码转换为css

    解析一个sass文件,并不只需要一个loader,它需要多个loader串行处理,webpack可以配置多个loader链式处理:

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

    我们可以将use配置为一个数组,loader从右往左依次执行,且前一个loader的结果是下一个loader的输入。最后一个loader的输出就是我们最终要的结果。一个sass文件首先经过sass-loader处理,变成css文件,又经过postcss-loader处理,添加浏览器前缀等功能,接着交给css-loader去解析css文件引用的静态变量,最后由style-loader以script标签的形式加入到html中。

    Files Loaders

    url-loader和file-loader是一对用来处理图片、svg、视频、字体等静态资源文件的loader。一般体积比较小的资源交给url-loader处理,编码为base64字符串,直接嵌入js文件中。体积较大的文件由file-loader处理,直接释放为了一个输出文件。

    { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: 'img/[name].[hash:7].[ext]' } },

    一般只配置url-loader即可,在资源超过limit的时候,url-loader会将资源自动交给file-loader处理,并将options内容也传递给file-loader。

    Plugins

    loaders用来转换某种特定类型的module,plugins则用来在一些合适的时机执行一些特定的任务,比如代码分割、静态资源处理、环境变量的注入、将所有css的module抽取为单个文件等。webpack自身也是用插件系统构建起来的。插件的目的是做任何loaders做不了的事情。

    HtmlWebpackPlugin

    HtmlWebpackPlugin插件可以用来生成包含你所有打包文件(js和css)的html文件,特别是你在打包文件名配置了hash,就不得不用这个插件了。

    module.exports = { plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, 'src/index.html'), filename: 'static/index.[hash].html', inject: true, minify: false, chunks: ['app', 'vendor'] }) ] }; template: HtmlWebpackPlugin生成html文件的模板,如果简单的话可以直接通过其他配置项生成,不必单独提供一个html文件模板,详情可参考 filename: 输出的html文件名,规则和output的filename相同inject: 是否注入打包的文件,包括js和通过MiniCssExtractPlugin打包输出的css文件,默认为trueminify: 是否压缩chunks: 只注入某些特定chunk的输出文件,在多文件场景下比较有用

    MiniCssExtractPlugin

    MiniCssExtractPlugin将一个chunk中的css抽取为一个单独的css文件,如果chunk中不包含css,则不生成文件。且支持按需加载和sourceMap。webpack4新增插件,在webpack4之前是使用ExtractTextWebpackPlugin来做这件事。官方文档总结了MiniCssExtractPlugin相对ExtractTextWebpackPlugin的四个优势:

    按需异步加载没有重复编译(性能)使用更简单专门为css设计 const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const devMode = process.env.NODE_ENV !== 'production' module.exports = { plugins: [ new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output // both options are optional filename: "[name].css", chunkFilename: "[id].css" }) ], module: { rules: [ { test: /\.css$/, use: [ devMode ? 'style-loader' : { // MiniCssExtractPlugin目前还没有HMR功能,所以最好只在生成环境使用 loader: MiniCssExtractPlugin.loader, options: { publicPath: '../' // 可单独配置publicPath,默认采用output中的publicPath } }, "css-loader" ] } ] } }

    CopyWebpackPlugin

    CopyWebpackPlugin用来处理静态文件,可以将文件或者文件夹原封不动地移动到打包目录。

    const CopyWebpackPlugin = require('copy-webpack-plugin') const config = { plugins: [ new CopyWebpackPlugin([ { from: 'source', to: 'dest' }, { from: 'source', to: 'dest', toType: 'dir|file|template' }, // 手动设置to的类型,比如设置成dir,即使to设置为a.js,最后也会生成a.js文件夹 { from: 'source', to: 'dest', context: '/app' }, // 基准目录,from相对于context解析 { from: 'source', to: 'dest', ignore: ['*.js'] }, // ignore, 忽略匹配的文件 'source' // 只有from,to默认为output的path ], { context: '/app', // 同上 ignore: ['*.js'], // 同上 }) ] }

    CleanWebpackPlugin

    CleanWebpackPlugin用来清除打包目录,主要用于每次重新生成的时候,清除残留文件。在文件有hash值的情况下,是必要的。

    const CleanWebpackPlugin = require('clean-webpack-plugin'); const config = { plugins: [ new CleanWebpackPlugin(['dist', 'bulid/*.js'], { watch: false, // 是否在--watch模式下也清除files然后重新编译,默认为false exclude: [ 'files', 'svg', 'css' ] // 不删除的子目录和文件 }), ] }

    DefinePlugin

    DefinePlugin用来定义webpack编译期间的全局变量。我们可以根据这些变量,来做不同的动作。最典型的就是可以区分开发环境和生产环境,比如在开发环境打印各种警告、错误,在生产环境去掉这些跟业务无关的代码。

    DefinePlugin的参数是一个对象,键名是一个标识符,或者用.隔开的多级标识符,参数遵循以下规则:

    如果参数值是一个字符串,则被当做代码块如果参数值不是字符串,则会自动转换为字符串如果参数值是一个对象,则对象的每个值都按照上述规则被定义为全局变量如果键名前面有typeof,则只是定义typeof的调用 new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production'), PRODUCTION: JSON.stringify(true), VERSION: JSON.stringify('5fa3b9'), BROWSER_SUPPORTS_HTML5: true, TWO: '1+1', 'typeof window': JSON.stringify('object') });

    index.js

    console.log('PRODUCTION', PRODUCTION); console.log('VERSION', VERSION); console.log('BROWSER_SUPPORTS_HTML5', BROWSER_SUPPORTS_HTML5); console.log('TWO', TWO); console.log('Object', typeof window);

    被编译为

    console.log('PRODUCTION', true); console.log('VERSION', "5fa3b9"); console.log('BROWSER_SUPPORTS_HTML5', true); console.log('TWO', 1+1); console.log('Object', false ? undefined : _typeof(window));

    DefinePlugin的原理很简单,只是在编译过程中遇到这些定义好的键名,就用键值做简单的文本替换。所以,你如果想给全局变量赋一个字符串,需要这样写’“production”’,一般使用JSON.stringify来转一下。

    Mode

    webpack4新增了mode配置。webpack会根据mode值自动帮你做一个不同的优化:

    production(默认值)

    在DefinePlugin 中将process.env.NODE_ENV设置为production默认启用了如下插件:FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin and UglifyJsPlugin

    development:

    在DefinePlugin 中将process.env.NODE_ENV设置为development默认启用了如下插件:NamedChunksPlugin , NamedModulesPlugin

    none: 什么都不做

    mode的两种使用方式

    配置:

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

    命令行:

    webpack --mode=production

    代码分割

    代码分割可以把代码按照一定的逻辑分割,用来做按需加载或者并行加载,以减少加载时间。在webpack中,主要有以下3中方式,实现代码分割:

    Entry Points: 手动在entry入口配置处配置多个入口SplitChunks: webpack4默认带这个优化插件,用于抽取不同chunk的公共部分,或者直接代码分割Dynamic Imports: 动态加载,在函数中使用import()语法,webpack使用SplitChunks将import()加载的module分割为一个单独的chunk,并在函数执行时加载该chunk对应的js文件。

    refers: https://www.webpackjs.com/guides/ https://segmentfault.com/a/1190000015893796 https://www.cnblogs.com/284628487a/p/6272274.html

    最新回复(0)