如何使用webpack优化开发/生产环境

HMR 热模块替换/模块热替换

作用:一个模块发生变化,只会更新这个模块(而不是打包所有)提高速度
样式文件:可以使用HRM功能,因为style-loader内部实现了
js文件:默认没有HRM
html文件:默认没有HRM,同时html文件不能热更新(本地代码不能重新编译)了<就一个文件,不需要做HMR功能>

  • 解决 :修改entry入口,讲html文件引入
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
module.export={
   entry:['./src/index.js','./src/index.html'],
   output:{
   filename:'built.js',
   path:resolve(_dirname,'build')
   },
   module:{
     rules:[
        module:{
     rules:[
       //详细loader配置 
       { 
         //处理css资源
         test:/\.css$/,
         use:[
           'style-loader',//(是一个包)
           'css-loader',//(是一个包)
         ]
       },
       { 
         //处理less资源
         test:/\.less$/,
         use:[
           'style-loader',//(是一个包)
           'css-loader',//(是一个包)
           'less-loader'
         ]
       },
       {
         //处理图片资源
         test:/\.(jpg|png|gif)$/,
         loader:'url-loader'
         options:[
           limit:8*1024
           name:'[hash:10].[ext]',
           //关闭es6模块化
           esModule:false,
           outputPath:'imgs'//改变输出路径
         ]
       },
        {
         test:/\.html$/,
         //处理html文件的img图片
         loader:'html-loader'
         name:'[hash:10].[ext]'
       },
       {
       //打包其他资源
         exclude:/\.(css|js|html|less|jpg|png|gif)$/,
         loader:'file-loader',
         //修改名字
         options:{
         name:'[hash:10],[ext]'
       },
     ]
   }//plugin的配置
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html'
     })
   ],
   //模式
   mode:'development'
     devServer:{
     //项目构建后的路径
      contentBase:resolve(_dirname,'build'),
      //启动gzip压缩
      compress:true,
      //端口号
      port:3000,
      //自动打开浏览器
      open:true//开启HMR功能
      //当修改了webpack配置,一定要重启webpack服务
      hot:true
  }
}

js的热模块
在index.js文件中写

针对非入口文件的js
import print from './print';
if(module.hot){
  //一旦module.hot为true,说明开启了HMR功能 -->让HMR功能代码生效
  module.hot.accept('./print.js',function(){
  //方法监听print.js文件变化,一旦发生变化,其他模块不会重新打包构建,会执行后面的回调函数
  print();
}

开发环境下调试代码(source-map)

一种提供源代码到构建后代码到映射技术(如果构建后代码出错了,通过映射可以追踪到源代码的目录)
[inline-|hidden-|eval-][nosources-][cheap-[module]]source-map

  • source-map:外联
    提示错误代码的准确信息和源代码错误位置
  • inline-source-map:内联:只生成一个source-map
    提示错误代码的准确信息和源代码错误位置
  • hidden-source-map:外联
    提示错误代码错误原因但是没有错误位置,不能追踪到源代码错误
  • eval-source-map:内联:每个文件都生成对应source-map,在eval函数中
    提示错误代码的准确信息和源代码错误位置
  • mosources-source-map:外联
    提示错误代码的准确信息,没有源代码错误位置
  • cheap-source-map:外联
    提示错误代码的准确信息和源代码错误位置,只能精确到行
  • cheap-module-source-map:外联
    提示错误代码的准确信息和源代码错误位置

1.生产环境:速度快,调试友好 (内联会让代码体积大,所以排除)source-map
2.开发环境:源代码隐藏?调式友好? eval-source-map

内联外联区别 1.外部生成了文件,内联没有2.内联构建速度更快

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
module.export={
   entry:['./src/index.js','./src/index.html'],
   output:{
   filename:'built.js',
   path:resolve(_dirname,'build')
   },
   module:{
     rules:[
        module:{
     rules:[
       //详细loader配置 
       { 
         //处理css资源
         test:/\.css$/,
         use:[
           'style-loader',//(是一个包)
           'css-loader',//(是一个包)
         ]
       },
       { 
         //处理less资源
         test:/\.less$/,
         use:[
           'style-loader',//(是一个包)
           'css-loader',//(是一个包)
           'less-loader'
         ]
       },
       {
         //处理图片资源
         test:/\.(jpg|png|gif)$/,
         loader:'url-loader'
         options:[
           limit:8*1024
           name:'[hash:10].[ext]',
           //关闭es6模块化
           esModule:false,
           outputPath:'imgs'//改变输出路径
         ]
       },
        {
         test:/\.html$/,
         //处理html文件的img图片
         loader:'html-loader'
         name:'[hash:10].[ext]'
       },
       {
       //打包其他资源
         exclude:/\.(css|js|html|less|jpg|png|gif)$/,
         loader:'file-loader',
         //修改名字
         options:{
         name:'[hash:10],[ext]'
       },
     ]
   }//plugin的配置
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html'
     })
   ],
   //模式
   mode:'development'
     devServer:{
     //项目构建后的路径
      contentBase:resolve(_dirname,'build'),
      //启动gzip压缩
      compress:true,
      //端口号
      port:3000,
      //自动打开浏览器
      open:true//开启HMR功能
      //当修改了webpack配置,一定要重启webpack服务
      hot:true
  },
  //加东西
  devtool:'eval-source-map'
}

oneOf

提升构建速度

//当一个文件被多个loader处理,一定要指定loader的先后执行顺序js中(先执行eslint 再执行babel)
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const 	MiniCssExtractPlugin=require('mini-css-extract-plugin');
const 	OptimizeCssAssetsWebpackPlugin=require('optimize-css-assets-webpack-plugin');
//复用loader
const commonCssLoader=[
  MiniCssExtractPlugin.loader,
  'css-loader',
  {//兼容性,在package.json中定义browserslist
    loader:'postcss-loader',
    //修改配置
    potions:{
    ident:'postcss',
    plugins:()=>[
      //postcss插件
      require('postcss-preset-env')()
    ] 
    }
  }
];
module.export={
   entry:'./src/index.js',
   output:{
   filename:'built.js',
   path:resolve(_dirname,'build')
   },
   module:{
     rules:[
     {
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            //优先执行的意思
            enforce:'pre'
            options:{
              //自动修复eslint错误
            fix:true 
         },
     oneOf:[//以下loader只会匹配一个,不能两个配置处理同一种类型文件
       {
         test:/\.css$/,
         use:[commonCssLoader]
        },
        {
          test:/\.less$/,
          use:[...commonCssLoader, 'less-loader']
         },
         {//在package.json中eslintConfig  ---> airbnb
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            options:{
              presets:[
                [
                  '@babel/preset-env',
                  {
                      useBuiltIns:'usage',
                     //指定corejs版本
                      corejs:{
                        version:3            
                      },
                     //兼容性做到哪个版本浏览器
                      targets:{
                        chrome:'60',
                        firefox:'60',
                        ie:'9',
                        safari:'10',
                        edge:'17'
                     }
                  }
                  ]
                ]
              ]
            }
           },
           {
             test:/\.(jpg|png|gif)$/,
             loader:'url-loader',
             options:{
               limit:8*1024,
               name:'[hash:10].[text]',
               outputath:'imgs',
               esModule:false
             }
           },//html里面的img
           {
             test:/\.html$/,
             loader:'html-loader'
           },
           {
              //打包其他资源
             exclude:/\.(css|js|html|less|jpg|png|gif)/,
             loader:'file-loader',
             options:{
               outputPath:'media',
               name:'[hash:10],[ext]'
             }
            },
           
   }//plugin的配置
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html'//压缩html代码,里面压缩配置
       minify:{
         //折叠空格
         collapseWhitespace:true,
         //移除注释
         removeComments:true
       }
     }),
     new MiniCssExtractPlugin({
       //若想输入到css目录下/重命名
       filename:'css/built.css'
     }),
     //压缩css:会运行更快
     new OptimizeCssAssetsWebpackPlugin(),
   ],
   //模式   生产环境下自动压缩js代码
   mode:'production'
}

缓存

  • babel:CacheDirectory:true–>让第二次打包构建速度更快
  • 文件资源 修改文件名 hash:每次webpack构建打包时生成唯一hash值
    问题:因为js和css使用同一hash值,如果重新打包会导致所有缓存失效
    chunkhash:根据chunk生成的hash值,如果打包来自于同一个trunk,hash值一样
    问题:js和css的hash值还是一样的,因为css是在js中被引入的,所以属于同一个trunk
    什么是trunk,所有根据入口文件引入的js、css,都会用一个trunk,是一个代码块
    contenthash:根据文件的内容生成的hash,不同文件hash值一定不一样–>让代码上线运行缓存速度更快
//当一个文件被多个loader处理,一定要指定loader的先后执行顺序js中(先执行eslint 再执行babel)
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const 	MiniCssExtractPlugin=require('mini-css-extract-plugin');
const 	OptimizeCssAssetsWebpackPlugin=require('optimize-css-assets-webpack-plugin');
//复用loader
const commonCssLoader=[
  MiniCssExtractPlugin.loader,
  'css-loader',
  {//兼容性,在package.json中定义browserslist
    loader:'postcss-loader',
    //修改配置
    potions:{
    ident:'postcss',
    plugins:()=>[
      //postcss插件
      require('postcss-preset-env')()
    ] 
    }
  }
];
module.export={
   entry:'./src/index.js',
   output:{
   filename:'built.[hash:10].js', //生成的资源带hash值
   path:resolve(_dirname,'build')
   },
   module:{
     rules:[
     {
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            //优先执行的意思
            enforce:'pre'
            options:{
              //自动修复eslint错误
            fix:true 
         },
     oneOf:[//以下loader只会匹配一个,不能两个配置处理同一种类型文件
       {
         test:/\.css$/,
         use:[commonCssLoader]
        },
        {
          test:/\.less$/,
          use:[...commonCssLoader, 'less-loader']
         },
         {//在package.json中eslintConfig  ---> airbnb
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            options:{
              presets:[
                [
                  '@babel/preset-env',
                  {
                      useBuiltIns:'usage',
                     //指定corejs版本
                      corejs:{
                        version:3            
                      },
                     //兼容性做到哪个版本浏览器
                      targets:{
                        chrome:'60',
                        firefox:'60',
                        ie:'9',
                        safari:'10',
                        edge:'17'
                     }
                  }
                  ]
                ],
                //开启babel缓存
                //第二次构建时,会读取之前的缓存
                CacheDirectory:true
              ]
            }
           },
           {
             test:/\.(jpg|png|gif)$/,
             loader:'url-loader',
             options:{
               limit:8*1024,
               name:'[hash:10].[text]',
               outputath:'imgs',
               esModule:false
             }
           },//html里面的img
           {
             test:/\.html$/,
             loader:'html-loader'
           },
           {
              //打包其他资源
             exclude:/\.(css|js|html|less|jpg|png|gif)/,
             loader:'file-loader',
             options:{
               outputPath:'media',
               name:'[hash:10],[ext]'
             }
            },
           
   }//plugin的配置
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html'//压缩html代码,里面压缩配置
       minify:{
         //折叠空格
         collapseWhitespace:true,
         //移除注释
         removeComments:true
       }
     }),
     new MiniCssExtractPlugin({
       //若想输入到css目录下/重命名
       filename:'css/built.css'
     }),
     //压缩css:会运行更快
     new OptimizeCssAssetsWebpackPlugin(),
   ],
   //模式   生产环境下自动压缩js代码
   mode:'production'
}

tree shaking

去除在应用程序中没有使用的代码
前提:1.必须使用es6模块化 2.开启production环境
作用:减少代码体积
在package.json中配置

"sideEffects":false;//所有代码都没有副作用(都可以进行 tree shaking)
//问题:可以能会把css/ @babel/polyfill(副作用)文件干掉
"sideEffects":["*.css","*.less"];//解决

code split

module.export={
//单入口
  // entry:'./src/index.js',
  entry:{
    //多入口:有一个入口,最终输出就有一个bundle
    main:'./src/index.js',
    test:'./src/test.js',
  }
   output:{
   //[name]取文件名
   filename:'built.[name].[hash:10].js', //生成的资源带hash值
   path:resolve(_dirname,'build')
   }//plugin的配置
   plugins:[
   ],
   //可以将node_modules中代码单独打包成一个chunk最终输出
   //自动分析多入口文件中有没有公共的文件,如果有会打包成单独的一个trunk
   optimzation:{
     splitChunks:{
     chunks:'all'
     }
   }
   //模式   生产环境下自动压缩js代码
   mode:'production'
}

第3种方式:通过js代码,让某个文件被单独打包成一个trunk
在index.js页面
import动态导入语法:能将某个文件单独打包

import('./test')
  .then(()=>{
    //文件加载成功
  })
  .catch(()=>{
    //文件加载失败
  })

懒加载和预加载

js文件的懒加载(触发了某些条件的时候才会加载)

//懒加载 --放在函数中,函数调用的时候加载:需要加载的时候才加载
//预加载 prefetch:会提前加载js文件
//正常加载可以认为是并行加载(用一时间加载多个文件) 预加载:等其他资源加载完毕,浏览器空闲了,再偷偷下载
//'/*webpackChunkName:'test',webpackPrefetch:true*/'分割成两个文件
import('/*webpackChunkName:'test'*/'./test').then(()=>{
 console.log('过一段时间再加载成功')
}

PWA(渐进式网络开发应用程序)

离线也可以访问
workbox 下载包workbox-webpack-plugin

//当一个文件被多个loader处理,一定要指定loader的先后执行顺序js中(先执行eslint 再执行babel)
const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const 	MiniCssExtractPlugin=require('mini-css-extract-plugin');
const 	OptimizeCssAssetsWebpackPlugin=require('optimize-css-assets-webpack-plugin');
const 	WorkboxWebpackPlugin=require('workbox-webpack-plugin');
//复用loader
const commonCssLoader=[
  MiniCssExtractPlugin.loader,
  'css-loader',
  {//兼容性,在package.json中定义browserslist
    loader:'postcss-loader',
    //修改配置
    potions:{
    ident:'postcss',
    plugins:()=>[
      //postcss插件
      require('postcss-preset-env')()
    ] 
    }
  }
];
module.export={
   entry:'./src/index.js',
   output:{
   filename:'built.[hash:10].js', //生成的资源带hash值
   path:resolve(_dirname,'build')
   },
   module:{
     rules:[
     {
            test:/.js$/,
            exclude:/node_modules/,
            loader:'eslint-loader',
            //优先执行的意思
            enforce:'pre'
            options:{
              //自动修复eslint错误
            fix:true 
         },
     oneOf:[//以下loader只会匹配一个,不能两个配置处理同一种类型文件
       {
         test:/\.css$/,
         use:[commonCssLoader]
        },
        {
          test:/\.less$/,
          use:[...commonCssLoader, 'less-loader']
         },
         {//在package.json中eslintConfig  ---> airbnb
            test:/.js$/,
            exclude:/node_modules/,
            loader:'babel-loader',
            options:{
              presets:[
                [
                  '@babel/preset-env',
                  {
                      useBuiltIns:'usage',
                     //指定corejs版本
                      corejs:{
                        version:3            
                      },
                     //兼容性做到哪个版本浏览器
                      targets:{
                        chrome:'60',
                        firefox:'60',
                        ie:'9',
                        safari:'10',
                        edge:'17'
                     }
                  }
                  ]
                ],
                //开启babel缓存
                //第二次构建时,会读取之前的缓存
                CacheDirectory:true
              ]
            }
           },
           {
             test:/\.(jpg|png|gif)$/,
             loader:'url-loader',
             options:{
               limit:8*1024,
               name:'[hash:10].[text]',
               outputath:'imgs',
               esModule:false
             }
           },//html里面的img
           {
             test:/\.html$/,
             loader:'html-loader'
           },
           {
              //打包其他资源
             exclude:/\.(css|js|html|less|jpg|png|gif)/,
             loader:'file-loader',
             options:{
               outputPath:'media',
               name:'[hash:10],[ext]'
             }
            },
           
   }//plugin的配置
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html'//压缩html代码,里面压缩配置
       minify:{
         //折叠空格
         collapseWhitespace:true,
         //移除注释
         removeComments:true
       }
     }),
     new MiniCssExtractPlugin({
       //若想输入到css目录下/重命名
       filename:'css/built.css'
     }),
     //压缩css:会运行更快
     new OptimizeCssAssetsWebpackPlugin(),
     new WorkboxWebpackPlugin.GenerateSW({
     //帮助serviceworker快速启动
     //删除旧的serviceworker
     //生成一个serviceworker配置文件
       clientsClaim:true,
       skipWaitting:true
     })
   ],
   //模式   生产环境下自动压缩js代码
   mode:'production'
}

注册serviceworker
在入口文件

//注意:1.eslint不认识window。navigator全局变量
解决:需要修复package.json中eslintConfig配置
2.sw代买必须运行在服务器上-->nodejs  -->npm i serve -g    serve -s build 
启动服务器,将build目录下的所有资源作为静态资源暴露出去

"env":{
  "browser":true//支持浏览器端全局变量
}//
//注册serviceworker
//处理兼容性问题
if('serviceworker' in navigator){
  window.addEventListener('load',()=>{
    navigator.serviceworker.register('/service-worker.js')
    .then(()=>{
      console.log('注册成功了')
     })
    .catch(()=>{
      console.log('注册失败了')
    })
}

多进程打包

下载thread-loader ,一般给babel-loader用

         {//在package.json中eslintConfig  ---> airbnb
            test:/.js$/,
            exclude:/node_modules/,
            use:[
            //开启多进程打包,进程开启有时间的,大概600ms,进程通信也有开销
            //只有在工作消耗时间比较长的时候,才需要多进程打包
              'thread-loader',
              //修改配置
              options:{
                workers:2//进程2个
              }
              {
                loader:'babel-loader',
            options:{
              presets:[
                [
                  '@babel/preset-env',
                  {
                      useBuiltIns:'usage',
                     //指定corejs版本
                      corejs:{
                        version:3            
                      },
                     //兼容性做到哪个版本浏览器
                      targets:{
                        chrome:'60',
                        firefox:'60',
                        ie:'9',
                        safari:'10',
                        edge:'17'
                     }
                  }
                  ]
                ],
                //开启babel缓存
                //第二次构建时,会读取之前的缓存
                CacheDirectory:true
              ]
            }
              }
            ],
            
           },

externals和dill(动态连接库)

不同的是:dill单独的对库进行打包,有的不打包,有的拆分开打包成多个

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const webpack=require('webpack');
const AddAssetHtmlWebpackPlugin=require('add-asset-html-webpack-plugin');
module.export={
   entry:'./src/index.js',
   output:{
   filename:'built.[hash:10].js', //生成的资源带hash值
   path:resolve(_dirname,'build')
   },
   module:{
     rules:[]
   }//plugin的配置
   plugins:[
     new HtmlWebpackPlugin({
       template:'./src/index.html'}),
     //告诉webpack那些库不参与打包,同时使用时名称也得改
      new webpack.DillPlugin({
      mainfes:resolve(_dirname,'dill/mainfest.json'),
      //将某个文件打包输出出去,并在html中引入该资源
      new AddAssetHtmlWebpackPlugin({
        filepath:resolve(_dirname,'dill/jquery.json'),
      })
   ],
   //模式   生产环境下自动压缩js代码
   mode:'production',
   externals:{//快
     //拒绝包打包进来 --npm包
     jquery:'jQuery'
   }
}
在index.js页面引入

dill打包,创建webpack.dill.js
使用dill技术,对某些库进行单独打包(jQuery、react、vue。。。)
运行–> webpack --config webpack.dill.js

const {resolve}=require('path');
const webpack=require('webpack');
module.export={
   entry:{//最终打包生成[name]-->jquery
     //['jquery']-->要打包的库是jQuery
     jquery:['jquery']
   },
   output:{
     filename:'[name].js', 
     path:resolve(_dirname,'dill'),
     libiary:'[name]_[hash]',//打包的库里面向外面暴露出去的内容的名字
   },
   plugins:[
     new webpack.DillPlugin({
       name:'name_[hash]',//映射库的暴露的内容名称
       path:resolve(_dirname,'dill/mainfest.json'),//输出文件路径
   ],
   mode:'production'
  }

总结

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值