webpack学习教程 loader与插件的使用

webpack以一个默认的入口文件作为打包的起点,将所有的资源依赖关系记录,形成一个依赖关系树状图,根据这个树状图引入这些相关的资源。引入的资源形成一个chunk(代码块),分别将这些chunk进行处理(例如将es6转化,将sass预处理为css等,这些操作统一称为打包),将打包好的文件输出为静态资源bundle

五个核心概念

  1. Entry

    指示webpack以哪个文件为打包的起点,并分析构建好内部资源依赖图。

  2. Output

    指示webpack将打包后的资源bundle输出到哪里,以及如何命名。

  3. Loader

    webpack能够去处理那些非js代码(webpack本身只理解js代码),如同翻译官的角色。loader模块下载后,课配置直接使用。

  4. Plugins

    可以用于执行范围更广泛的任务,包括从打包优化和压缩,到重新定义环境中的变量等。plugins插件下载后,还需引入才可配置使用。

  5. Mode

    development:能让代码本地调试运行的环境

    production:能让代码优化上线的运行环境

webpack能处理js/json资源,不能处理css/img等其他资源;打包的生产环境或开发环境代码,ES6模块化已经编译为浏览器能识别的模块化;打包的生产环境比开发环境多一个js压缩的过程。

webpack.config.js

指示webpack需要进行的工作,运行webpack指令时,会加载文件内的配置。所有构建工具都是基于nodejs平台运行的,默认采用commonjs标准模块化。

css文件编译处理

style-loader:创建style标签,将已转化为js的样式资源插入,然后添加到head中生效;css-loader:将css文件转化为commonjs模块加载到js中,模块内容为样式字符串;less-loader:将less文件编译成css文件,需要依赖less插件。

{
  test: /\.css$/, //匹配文件
  use: [ //use中loader执行顺序从后往前
    'style-loader', //创建style标签,将js中的样式资源插入,然后添加到head中生效
    'css-loader', //将css文件变成commonjs模块加载到js中,模块内容为样式字符串
  ]
},
{
  test: /\.less$/,
  use: [
    'style-loader',
    'css-loader',
    'less-loader', //将less文件编译成css文件,需要依赖less插件
    ]
},

html文件编译处理

html-webpack-plugin:不添加任何配置,默认会创建一个空的html,自动引入打包输出的所有资源(js/css);如果需要有结构的html文件,可以进行自定义配置。

new HtmlWebpackPlugin({
  template: './src/index', //复制./src/index.html文件,并自动引入打包输出的所有资源
  
})

图片资源编译处理

使用url-loader(依赖file-loader,默认处理不了html中的img图片,webpack5不再使用)处理图片资源,limit配置表示图片大小小于8kb的情况下,会通过base64处理转换成字符串方式。base64可以减少请求数量,减轻服务器压力,但同时图片体积会更大,文件请求速度会更慢。

使用html-loader处理html文件的img图片,该插件负责引入img图片,从而能被url-loader进行处理。由于url-loader是使用es6模块处理文件,而html-loader使用commonJs引入图片,解析会出问题:[object Module],此时url-loader应使用esModule配置。

{
  test: /\.(png|jpg|gif)$/,
  loader: 'url-loader',
  options: {
    limit: 8 * 1024,
    name: '[name]_[hash:10].[ext]', //name为图片文件名;hash:10取图片hash的前10位;ext取文件原来的扩展名
    esModule: false, //关闭url-loader的es6模块化,使用commonJs解析
  }
},
{
    test: /\.html$/,
  loader: 'html-loader'
}

webpack5中我们使用assets-moduleurl-loader在这个版本中已经被废弃。

{
    test: /\.(png|jpe?g|gif)/,
  type: 'assets',
  parser: {
    dataUrlCondition: {
      maxSize: 8 * 1024,
    }
  },
  generator: {
    filename: 'img/[name]_[hash:10].[ext]'
  }
}

其他资源编译处理

{
    exclude: /\.(css|jpg|png|gif|html|less|js)$/,
  loader: 'file-loader',
  options: {
    name: '[name]_[hash:10].[ext]'
  }
}

devServer

开发服务器,用来做自动化,能够自动编译,自动打开浏览器,自动刷新浏览器等。只会在内存中编译打包,不会有任何输出,output的配置将不再有用,终止服务器后,内存中存在的编译包将会自动删除。启动devServer指令为:webpack-dev-server(需下载该插件)

devServer: {
  contentBase: resolve(__dirname, 'build'), //需要运行的项目的文件目录(构建后的目录),webpack5不用配置该选项(该选项已被删除)
  compress: true, //启动gzip压缩,让项目体积更小,启动更快
  port: 9006, //开发服务器的端口号
  open: true, //自动打开浏览器
}

打包文件优化

mini-css-extract-plugin插件可以将样式文件从js代码中抽离出来,单独成一个文件目录,通过link标签引入。将css单独提取出来,可以减小js文件大小

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
{
  test: /\.css$/, //匹配文件
  use: [ //use中loader执行顺序从后往前
   // 'style-loader',
    MiniCssExtractPlugin.loader, //取代style-loader,提取出css代码
    'css-loader',
  ]
},
plugins: [
  new MiniCssExtractPlugin({
    filename: './css/built.css', //对输出的css文件进行重命名,注意该路径为相对路径
  })
]

css兼容性处理

使用postcss,依赖于插件postcss-loaderpostcss-preset-env(帮助postcss找到package.jsonbrowserslist里面的配置,通过配置加载指定的css兼容性样式,可以使兼容性精确到某一个浏览器版本。默认是找生产环境browserslist,若要找development环境,需要设置node环境变量:process.env.NODE_ENV = development

"browserslist": { //package.json
  "development": [
    "last 1 chrome version", //兼容至少最近的一个chrome浏览器版本
    "last 1 safari version"
  ],
  "production": [
    ">0.2%", //大于99.8%的浏览器
    "not dead", //不要已经废弃的浏览器版本
    "not op_mini all", //不要op_mini浏览器,webpack5已经删除
  ]
}

{ //webpack.config.js
  test: /\.css$/, //匹配文件
  use: [ //use中loader执行顺序从后往前
   // 'style-loader',
    MiniCssExtractPlugin.loader, 
    'css-loader',
    {
      loader: 'postcss-loader',
      options: {
        ident: 'postcss', //固定写法
        plugins: () => [
          require('postcss-preset-env')()
        ]
      }
    },
    { //webpack5用法
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          plugins: ['postcss-preset-env']
        }
      },
    }
  ]
},

css压缩

使用插件optimize-css-assets-webpack-pluginwebpack.config.js中直接调用插件,默认的配置已经足够。

js语法检查

语法检查只针对js文件,使用eslint-loader插件(依赖于eslint库),应该只检查自己的源代码,排除其他插件代码。需要在package.jsoneslintConfig设置具体的检查规则。推荐使用airbnb风格指南,指示如何规范的编写js代码。运用airbnb可以通过使用插件eslint-config-airbnb(包含react风格建议)或eslint-config-airbnb-base(不包含react风格建议)。

eslint-config-airbnb依赖于插件eslinteslint-plugin-importeslint-plugin-reacteslint-plugin-react-hookseslint-plugin-jsx-a11y

eslint-config-airbnb-base依赖于插件eslinteslint-plugin-import

{ 
    test: /\.js$/,
  exclude: /node_modules/,
  enforce: 'pre', //优先执行
  loader: 'eslint-loader',
  options: {
    fix: true, //自动修复代码格式问题
  }
}
 //eslint-disable-next-line 不检查下一行代码
{ //packag.json
  "eslintConfig": {
    "extends": "airbnb-base" //使用该包进行语法检查
  }
}

js兼容性处理

使用bable-loader插件,依赖于插件@babel/core@babel/preset-env,只能转换基本语法,如promise不能转换。

{
  test: /\.js/,
  loader: 'babel-loader',
  options: {
    presets: ['@babel/preset-env'], //指示babel做怎样的兼容性处理
  }
}

全部js兼容性处理还需插件@babel/polyfill,直接在js文件中引入import '@babel/polyfill'。该插件会将所有兼容性代码全部引入,导致文件体积太大。

按需引入需要做兼容性处理的代码,需要借助corejs,需要下载插件@babel/core。使用这种方法就不能同时使用第二种方法。

{ //有报错
  test: /\.js$/,
  exclude: /node_modules/,
  loader: 'babel-loader',
  options: {
    presets: [
      [
        '@babel/preset-env', 
        {
          useBuiltIns: 'usage', //按需下载
          corejs: {
            version: 3, //指定corejs版本
          },
          targets: { //指定兼容性做到哪个版本浏览器
            chrome: '60',
            firefox: '60',
            ie: '9',
            safari: '10',
            edge: '17',
          }
        }
      ]
    ]
  }
},

webpack性能优化

开发环境性能优化
  1. 优化打包构建速度

    HMRhot module replacement(热模块替换/模块热替换),一个模块发生变化,只会重新打包这一个模块(而不是打包整个模块),不会重新刷新浏览器,极大提升构建速度。devServer配置中添加hot: true就可以使用该功能。样式文件由于style-loader内部实现了HMR功能,可以实现热更新。因此在开发环境中应该使用style-loader,使样式文件打包更快;html文件默认不支持该功能,由于项目中只存在一个,html文件发生变化的时候也只需要更新这一个文件,因此不需要HMR功能;js文件默认也不支持该功能,若要实现该功能(只能处理非入口js文件),则需要添加代码:

    if(module.hot) { //为true则表示HMR功能为开启状态
      module.hot.accept('./print.js', () => {
        //module.hot.accept监听print.js文件,一旦该文件发生变化,其他模块不会重新打包构建,只会再次执行当前这个回调函数
        print();
      })
    }
    
  2. 优化代码调试

    source-map:一种提供源代码到构建后代码映射的技术,如果构建后代码出错了,通过映射,可以追踪到源代码错误位置。使用方式:在webpack.config.js中添加配置devtool: 'source-map'

    cheap-module-source-mapmodule表示会将loadersource-map也加入。开发环境推荐eval-source-map更快,生产环境推荐source-map

生产环境性能
  1. 优化打包构建速度

    one-of可以在webpack构建的时候,相应文件只用匹配一个规则,此是有一个问题,相同类型文件不能有两个规则来处理。解决方法是,将处理相同文件的多个规则移出one-of

    rules: [{}, {oneOf: []}]
    
    babel缓存:

    配置babel-loader规则选项cacheDirectorytrue,表示在第二次构建时, 会读取之前的缓存。使第二次构建速度更快。

  2. 优化代码运行的性能

    文件资源缓存:让代码上线运行缓存更好使用

    hash:每次webpack构建时,都会生成一个唯一的hash值,将jscss文件名加上hash值,可以使每次构建后都能拿到最新的代码。但由于webpack每次构建都会生成一个新的hash值,导致所有的缓存都会失效。

    chunkhash:根据chunk生成的hash值,如果打包来源于同一个chunkhash值就一样。chunk:由入口文件加上入口文件中引入的jscss文件形成一个chunk。由于css是在js中被引入的,因此同属于一个chunk,所以在其中部分模块发生变化时,也会使这一个chunk相关的所有缓存失效。

    cotenthash:根据文件的内容生成相应的hash值,不同文件的hash值一定不一样,从而实现,当前文件内容更新,只更新当前文件的hash值,获取最新文件代码,其他文件还是来自于缓存。

    tree shaking

    去除无用代码,减少代码体积。在使用ES6模块 化,webpackmodeproduction时,会自动开启该动能。如果配置sideEffects: false表示所有代码都没有副作用,都可以进行tree shaking,这样可能会导致直接引入的代码,例如css引入被去除。配置sideEffects: [*.css],改类型文件将不会执行tree shaking

    代码分割

    可以自动将node_modules中代码单独打包成一个chunk最终输出;自动分析多入口chunk中,有没有公共的文件,如果有,会打包成单独的一个chunkimport动态导入语法,能将某个文件单独打包,实现懒加载。

    {
    optimization: {
      splitChunks: {
        chunks: 'all',
      }
    }
    }
    

多进程打包

使用thread-loader模块,开启多进程打包。在thread-loader配置后的loader将会开启过进程打包。但进程启动大约需要600ms,进程通信也有一定的开销,因此只有工作消耗时间比较长(js代码比较多),才需要多进程打包。

{
  loader: 'thread-loader',
  options: {
    worker: 2
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容