webpack 常用配置

环境搭建

既然是前端项目,那么就npm就必不可少 运行 npm install webpack-cli -g 来全局安装脚手架 随后使用 npm install webpack-cli -D 安装到工程下

在工程目录下创建 webpack.config.js (文件名固定) 来作为webpack的配置文件,所有有关webpack的配置都写在此文件中,其中的内容通过es5语法暴露出去

五个核心配置

webpack 五个核心配置是

  1. entry 入口文件

  2. output 输出

  3. module loader配置

  4. plugins 插件

  5. mode 打包模式 其结构如下

 module.exports = {
     //入口起点
     entry:
 ​
     //输出
     output:{
         
     },
     module:{
 ​
     },
     plugins:[
 ​
     ],//插件配置
     mode:'development',
     //mode:'production'
 }

下面详细聊聊这五个配置

entry 入口文件,指示webpack 从哪个文件开始打包,这个入口文件所引用导入的文件都会参与打包

webpack 常用配置_第1张图片

output 输出文件,指示webpack将打包好的文件输出到哪里 其中需要在顶部导入js的内置模块path

webpack 常用配置_第2张图片

webpack 默认只能打包js/json资源,所以当我们想要打包其他资源是,则需要借助loader

module module主要作用是配置loader,而每一个loader都作为一个对象,存在rules数组中。 loader是webpack最重要的一环,只有配置了各种loader webpack才能打包各种各样的资源,其中各种loader通过npm 下载即可

  1. 打包资源

    1. 打包css资源(需要下载css-loader,style-loader)

       {
       //正则表达式 表示匹配哪些文件
       test:/\.css$/,
       ​
           use:[//use为一个数组,将loader按从下至上顺序执行
       ​
               //创建一个style标签 将js中的样式添加到页面中生效
               'style-loader',
       ​
               //将css文件 以字符串的形式变成一个commjs模块加载到js
               'css-loader',
           ]
       }

    2. 打包less资源(需要下载style-loader,css-loader,less-loader)

       {
           test:/\.less$/,//每一种匹配规则 只适用与一种文件
       ​
           use:[
               //创建style标签 将js中的样式添加到页面中
               'style-loader',
       ​
               //将css文件 编译成commjs模块加载到js
               'css-loader',
       ​
               //将less文件编译成css文件
               'less-loader'
           ]
       },

    3. 将css单独打包成一个文件(单独下载mini-css-extract-plugin)

      首先new一个对象  

      const MiniCssExtracetPlugin = requir('mini-css-extract-plugin')

    4. 调用插件对象

      new MiniCssExtracetPlugin({
           filename:'css/built.css'//对输出文件进行重命名
       })

      修改loader信息

       {
           test:/\.css/,
           use:[
               //'style-loader',//创建style标签,将样式放上去
               MiniCssExtracetPlugin.loader,//取代style-loader 提取js中的css为单独文件
               'css-loader'//将css文件整合到js中
           ]
       }

  2. 打包img资源(1)(需要下载url-loader,file-loader) 由于图片数量在实际开发中会很多,在打包过程中就会拖慢打包速度,所以我们需要使用 options来修改loader的一些参数 

     //当只使用了一个loader时,则可以不使用use数组
         loader:'url-loader',
         options:{
             limit:8 * 1024,
             //图片大小小于8kb(项目中较小的图片) 就会被base64编码方式处理
             //优点:减少请求数量 (减轻服务器压力)
             //缺点:图片体积会更大(请求速度更慢)
     ​
         name: '[hash:10].[ext]'
             //文件名取哈希值前十位加上文件原拓展名
         }
     },
     
  3. 打包img资源(2)(需要下载html-loader) 上面那种处理方式只能处理 html引用的css文件中引入的图片,不能处理html页面中引入的图片。解决方法是使用html-loader 但是 url-loader是使用es6model去解析,而html-loader是使用commjs去解析, 为了避免冲突我们需要关闭url-loader的es6Module 改用commjs解析(在option中加入esModule:false)

    {
        //使用html-loader
        test:/\.html$/,
        loader:'html-loader'
    }
        options:{
                limit:8 * 1024,
                name: '[hash:10].[ext]'
    
            //在url-loader中关闭es6Module
                esModule:false
        }

  4. 打包html资源(需要下载适用于html的plugin插件,html-webpack-plugin -D

    在顶部引入 const HtmlWbpackPlugin = requi('html-webpack-plugin');

    随后在plugins列表中new一个对象,其中的template属性,将作为结构模板。

       
      plugins:[
             new HtmlWbpackPlugin({
                 template:'./src/index.html'
             })
             
         ],

  5. 兼容性处理

    1. 兼容css(需要下载postcss-loader,postcss-preset-env) 随着css版本的更新迭代,相对于应的兼容性问题也层出不穷,webpack也提供了css兼容性的解决方案

     修改loader
 {
     test:/\.css/,
     use:[
         MiniCssExtracetPlugin.loader,
         'css-loader',
 ​
         //第一种 使用loader的默认配置 修改loader配置
         //帮postcss找到package.json中browserslist的配置,通过指定配置加载兼容性样式
         {
             loader:'postcss-loader',
             options:{
                 ident:'postcss',
                 plugins:()=>{
                     require('postcss-preset-env')
                 }
             }
         }
     ]
 }

在package.json 中添加支持的browserlist

 "browserslist": {
     "development": [
         "last 1 chrome version",
         "last 1 firefox version",
         "last 1 safari version"
         //兼容最近一个版本的谷歌火狐索菲亚浏览器
     ],
     "production": [
         ">0.2%",//兼容99.8%的浏览器
         "not dead",//不兼容已经死掉的浏览器
         "not op_mini all"//不兼容op_mini
     ]
 },

postcss 默认使用生产环境 如需使用开发环境则需要手动配置nodejs 中的临时环境变量,在webpack.config.js 顶部添加 process.env.NODE_ENV = 'development'

如抛错 ValidationError: Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema. 则说明 此插件版本不支持在webpack.config.js中进行配合 需要在项目根目录下 创建 postcss.config.js 添加如下代码

module.exports = { plugins:[ require('postcss-preset-env')() ] }

然后在webpack.config.js 中删除post-loader的额外配置

{
  loader:'postcss-loader',
  //options:{
  //    ident:'postcss',
  //    plugins:()=>{
  //        require//('postcss-preset-env')
  //    }
  //} 
}

  1. 兼容js(1)(需要下载babel-loader,@babel/core,@babel/preset-env)

 {
     test: /\.js$/,
     exclude: /node_modules/,
     loader: 'babel-loader',
     options: {
         // 预设:指示babel 做怎样的兼容处理
         presets: [
             [
                 '@babel/preset-env',
                 {
                     //指定兼容性做到哪个版本的浏览器
                     targets: {
                         chrome: '60',
                         firefox: '50',
                         ie: '9',
                         safari: '10',
                         edge: '17'
                     }
                 }
             ]
         ]
     }
 }

这种方法只能转换基本语法,promise等不能转换

如需要兼容所有js(需要下载@babel/polyfill),在入口文件中引入 import '@babel/polyfill',这种方法会将所有js兼容性都包括,所以打包后会非常大

  1. 压缩处理

  2. 压缩js html 在修改mode属性为 production生成模式

    删除html中无用的内容

      new HtmlWbpackPlugin({
           template:'./index.html',
           minify:{
               //移除空格
               collapseWhitespace:true,
     ​
               //移除注释
               removeComments:true
           }
       })

  3. 压缩css(需要下载optimize-css-assets-webpack-plugin插件),并在插件列表中使用

     plugins:[
         new OptimizeCssAssetsWebpackPlugin()
     ],

性能调优

HMR

HMR:hot module replacement 热模块替换 当某一个模块发生变化时 只会重新加载变化的模块 其他模块不会被加载

在webpack.config.js 结尾处添加

 devServer:{
     contentBase:resolve(__dirname,'build'),
     compress:true,
     port:3000,
     open:true,
     hot: true
 }

js默认不能使用hmr,如需要,在入口文件添加监听即可

 if(module.hot){
     module.hot.accept('./print.js',()=>{
         dosomething()
         //监听print.js 文件,如果发生变化,会执行回调函数
     })
 }

html默认不能使用hmr 而且会导致html文件不能热更新 在入口文件 加上html文件即可(通常不需要hmr功能)

source-map映射

在源代码和构建后代码之间形成映射,当构建后代码出错时,可以映射到源代码 在webpack.config.js 末端添加devtool属性即可属性值及功能如下

 开发环境下使用:eval-source-map(调试好) || eval-cheap-module-source-map(速度快)
 生成环境下使用:source-map(调试好) || cheap-module-source-map(速度好) || 
 nosources-source-map(隐藏全部代码)||hidden-source-map(隐藏源代码)

oneOfLoader

当使用oneOf后 当文件命中loader就会停止 不会接着继续判断 提高效率 将所有loader对象放入oneOf数组即可

 module: {
         rules: [
             {
                 oneOf: [
                     {},
                     {},
                     {}
                 ]
             }
         ]
     },

treeShaking

去除无用代码 减少打包体积 前提:es6module productionEnv 问题:会把一些文件干掉 如css babel(直接引用,没有使用)

在packge.json 中 添加配置sideEffects 以排除相应文件

 "sideEffects": [
     "*.css",
     "*.less"
 ]

codeSplit

将打包后的文件拆分成多个文件 可以实现并行加载/按需加载

  1. 多个入口 多个出口 每一个出口文件都对应一个入口文件

 entry:{
     main:'./js/index.js',
     test:'./js/test.js'
 },
 ​
 output:{
     //    生成的构建后文件将根据入口文件进行命名
     filename:'js/[name].js',
     path:resolve(__dirname,'build')
 },
  1. 添加 属性 将node_modules 中的文件 单独打包成一个chunk,如果是多入口 会将里面公用的modules 单独打包,在配置文件中添加配置

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

lazyLoading

只有当需要模块的时候 才去加载,加载完成之后 再次调用会使用缓存

pwa

渐进式网络开发应用程序(离线访问) (需要下载 workbox-webpack-plugin 并导入其GenerateSW方法)

在配置文件plugins中使用插件

 new GenerateSW({
     clientsClaim:true,
     skipWaiting:true
 })

随后在入口文件中 注册service-worker

 //注册serciceworker
 if('serviceWorker' in navigator){
     window.addEventListener('load',()=>{
         navigator.serviceWorker.register('/service-worker.js')
         .then(()=>{
             console.log('serviceworkder 注册成功');
         })
         .catch(()=>{
             console.log('serviceworkder 注册成功');
         })
     })
 }

externals

忽略打包 如果有包通过标签引入了 可以设置不被打包 在配置文件中添加

 //忽略包名 不被打包
     externals:{
         jquery:'jQuery'
     }

完整通用版本

生产版

const { resolve } = require('path');
 const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
 const HtmlWebpackPlugin = require('html-webpack-plugin');
 ​
 // 定义nodejs环境变量:决定使用browserslist的哪个环境
 process.env.NODE_ENV = 'production';
 ​
 // 复用loader
 const commonCssLoader = [
   MiniCssExtractPlugin.loader,
   'css-loader',
   {
     // 还需要在package.json中定义browserslist
     loader: 'postcss-loader',
     options: {
       ident: 'postcss',
       plugins: () => [require('postcss-preset-env')()]
     }
   }
 ];
 ​
 module.exports = {
   entry: './src/js/index.js',
   output: {
     filename: 'js/built.js',
     path: resolve(__dirname, 'build')
   },
   module: {
     rules: [
       {
         test: /\.css$/,
         use: [...commonCssLoader]
       },
       {
         test: /\.less$/,
         use: [...commonCssLoader, 'less-loader']
       },
       /*
         正常来讲,一个文件只能被一个loader处理。
         当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
           先执行eslint 在执行babel
       */
       {
         // 在package.json中eslintConfig --> airbnb
         test: /\.js$/,
         exclude: /node_modules/,
         // 优先执行
         enforce: 'pre',
         loader: 'eslint-loader',
         options: {
           fix: true
         }
       },
       {
         test: /\.js$/,
         exclude: /node_modules/,
         loader: 'babel-loader',
         options: {
           presets: [
             [
               '@babel/preset-env',
               {
                 useBuiltIns: 'usage',
                 corejs: {version: 3},
                 targets: {
                   chrome: '60',
                   firefox: '50'
                 }
               }
             ]
           ]
         }
       },
       {
         test: /\.(jpg|png|gif)/,
         loader: 'url-loader',
         options: {
           limit: 8 * 1024,
           name: '[hash:10].[ext]',
           outputPath: 'imgs',
           esModule: false
         }
       },
       {
         test: /\.html$/,
         loader: 'html-loader'
       },
       {
         exclude: /\.(js|css|less|html|jpg|png|gif)/,
         loader: 'file-loader',
         options: {
           outputPath: 'media'
         }
       }
     ]
   },
   plugins: [
     new MiniCssExtractPlugin({
       filename: 'css/built.css'
     }),
     new OptimizeCssAssetsWebpackPlugin(),
     new HtmlWebpackPlugin({
       template: './src/index.html',
       minify: {
         collapseWhitespace: true,
         removeComments: true
       }
     })
   ],
   mode: 'production'
 };

开发版

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        // 处理less资源
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        // 处理css资源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        // 处理图片资源
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          // 关闭es6模块化
          esModule: false,
          outputPath: 'imgs'
        }
      },
      {
        // 处理html中img资源
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        // 处理其他资源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true
  }
};

你可能感兴趣的:(前端项目环境,webpack)