webpack的基础学习

目录

1、Webpack五个核心概念

Entry

Output

Loader

Plugins

Mode

2、使用source map

3、处理图片资源

4、加载css并抽离和压缩css

5、使用babel-loader

1、安装

2、regeneratorRuntime插件

6、代码分离

入口起点-防止重复

动态导入

7、缓存

        7.1、输出文件的文件名

        7.2、缓存第三方库

8、拆分开发环境和生产环境配置

8.1公共路径

8.2环境变量

8.3拆分配置文件


1、Webpack五个核心概念

  • Entry

入口(Entry)指示Webpack以哪个文件为入口起点开始打包,分析构建内部依赖图。

  • Output

输出(Output)指示Webpack打包后的资源bundles输出到哪里去,以及如何名。

  • Loader

Loader让WebPack能够去处理那些非JavaScript文件(webpack 自身只理解JavaScript)

  • Plugins

插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。

  • Mode

2、使用source map

作用:精准定位代码行数

devtool: 'inline-source-map',

3、处理图片资源

module:{
    rules:[
        {
        // 问题:默认处理不了html中img图片
        // 处理图片资源
        test: /\.(png|jpg|gif|svg)$/i,
        type: 'asset',
        //指定图片的打包位置
        generator: {
          filename: 'images/[contenthash][ext]'
        },
        parser: {
          // 如果一个模块源码大小小于 maxSize,那么模块会被作为一个 Base64 编码的字符串注入到包中, 否则模块文件会被生成到输出的目标目录中。其中这里是4M
          dataUrlCondition: {
            maxSize: 4 * 1024
          }
        }
      },
    ]
}

4、加载css并抽离和压缩css

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 给每个css文件单独抽调出来放进html的link上引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
//这个插件使用 cssnano 优化和压缩 CSS。
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");


module.exports = {
  mode: 'production',
  entry: {
    index: './src/index.js'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
  devtool: 'inline-source-map',
  // loader的配置
  module: {
    rules: [
      {
        test: /\.(css|less)$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'styles/[contenthash].css'
    }),
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
      // `...`,
      new CssMinimizerPlugin(),
    ],
  }
};

5、使用babel-loader

目的:为了使浏览器兼容es6以上等的写法转化为熟悉浏览器认识的es5写法。

1、安装

npm install -D babel-loader @babel/core @babel/preset-env
  • babel-loader:在webpack里应用babel解析ES6的桥梁
  • @babel/core:babel核心模块
  • @babel/preset-env:babel预设,一组babel插件的集合

配置如下:

module:{
    rules:[
        {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
}

2、regeneratorRuntime插件

此时执行编译,在浏览器里打开项目发现报了一个致命错误:

 regeneratorRuntime是webpack打包生成的全局辅助函数,由babel生成,用于兼容async/await的语法。

regeneratorRuntime is not defined这个错误显然是未能正确配置babel。

正确的做法需要添加一下的插件和配置:

npm install @babel/runtime

npm install -D @babel/plugin-transform-runtime

//配置
{
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: ['@babel/plugin-transform-runtime']
          }
        }
      }


6、代码分离

  • 入口起点-防止重复

根据不同的入口打包,将公用的代码分离出来

第一种

webpack.config.js

entry:{
    index: {
      import: './src/index.js',
      dependOn: 'shared'
    },
    another: {
      import: './src/another-module.js',
      dependOn: 'shared'
    },
    shared: 'lodash'
}

第二种

使用SplitChunksPlugin插件

modules.exports={
    entry: {
    index: './src/index.js',
    another: './src/another-module.js',
    },
    optimization: {
    splitChunks: {
      // 包含所有类型的块
      chunks: 'all',
    },
  }

}
  • 动态导入

使用符合ECMAScript提案的import()语法实现动态导入

新建async-module.js

function getComponent () {
  return import('lodash')
    .then(({ default: _ }) => {
      const element = document.createElement('div')
      element.innerHTML = _.join(['Hello', 'webpack'], '')
      return element
    })
}

getComponent().then((ele) => {
  // 为了单独处理lodash这个文件
  document.body.appendChild(ele)
})

在所需的模块中引入

import './async-module'
  • 懒加载

好处:减少网络流量请求

//math.js webpackChunkName为设置打包的后的名字
const button = document.createElement('button')
button.textContent = '点击执行加法运算'
button.addEventListener('click', () => {
  import(/* webpackChunkName:'print'*/'./print.js').then(({ add }) => {
    console.log(add(4, 5))
  })
})
document.body.appendChild(button)
  • 预加载

preFetch(预获取):将来某些导航下可能需要的资源,比懒加载更优的选择。

preload(预加载):当前导航下可能需要资源,和懒加载类似

const button = document.createElement('button')
button.textContent = '点击执行加法运算'
button.addEventListener('click', () => {
  import(/* webpackChunkName:'print',webpackPrefetch:true*/'./print.js').then(({ add }) => {
    console.log(add(4, 5))
  })
})
document.body.appendChild(button)

7、缓存

        当项目部署到服务器时,浏览器加载完服务器上的文件,会缓存我们打包好的模块,如果我们修改了自己的业务代码,而文件名没有变,浏览器就会获取本地缓存的内容,从而获取不到新内容,所以通过下面的方式解决。

        7.1、输出文件的文件名

        我们可以通过替换output.filename中的substitutions设置,来定义输出文件的名称。webpack提供了一种使用称为substitution(可替换模板字符串)的方式,通过带括号字符串来模板化文件名。其中,[contenthas] substitution将根据资源内容创建出唯一的hash。当资源内容发生变化时,[contenthash]也会发生变化。

修改配置文件

module.exports = {
    output: {
    filename: '[name].[contenthash].js',
    },
}

        7.2、缓存第三方库

        将第三方库(library)(例如 lodash )提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,他们很少像本地的源代码那样频繁修改,因此通过实现以上步骤,利用client的长效缓存机制,命中缓存来消除请求,并减少向server获取资源,同时还能保证client代码和server代码版本一致。我们在 optimization.splitChunks 添加如下 cacheGroups 参数并构建:

//webpack.config.js
optimization:{
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    },
}

8、拆分开发环境和生产环境配置

使用不同的命令做开发环境或生产环境的打包

module.exports = (env) => {
    return{
        mode: env.production ? 'production' : 'development',
    }
}
  • 开发环境打包命令
npx webpack --env development
  • 生产环境打包命令
npx webpack --env production
  • terser-webpack-plugin

// 该插件使用 terser 来压缩 JavaScript。
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  optimization: {
    minimizer: [new TerserPlugin()],
  },
};

8.1公共路径

publicPath 配置可以用来指定应用程序中所有资源的基础路径

output:{
    publicPath: 'http://localhost:8080/'
}

8.2环境变量

可使用--env 的方式配置打包成开发环境或是生产环境

//package.json
"scripts":{
     "start": "webpack --config webpack.config.js --env development",
     "build": "webpack --config webpack.config.js --env production",
}

8.3拆分配置文件

webpack.config.js  (使用webpack-merage对文件进行合并)

const { merge } = require('webpack-merge');

const commonConfig = require('./webpack.common')
const productionConfig = require('./webpack.prod')
const developmentConfig = require('./webpack.dev')

module.exports = (env) => {
  switch (true) {
    case env.development:
      return merge(commonConfig, developmentConfig)
    case env.production:
      return merge(commonConfig, productionConfig)
    default:
      return Error('No matching configuration was found')
  }
}

webpack.common.js  (提取公共的部分)

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 给每个css文件单独抽调出来放进html的link上引入
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: {
    index: './src/index.js',
    another: './src/another-module.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
  // loader的配置
  module: {
    rules: [
      {
        test: /\.(css|less)$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
      },
      {
        // 问题:默认处理不了html中img图片
        // 处理图片资源
        test: /\.(png|jpg|gif|svg)$/i,
        type: 'asset',
        generator: {
          filename: 'images/[contenthash][ext]'
        },
        parser: {// 如果一个模块源码大小小于 maxSize,那么模块会被作为一个 Base64 编码的字符串注入到包中, 否则模块文件会被生成到输出的目标目录中。
          // 这里是4M
          dataUrlCondition: {
            maxSize: 4 * 1024 * 1024
          }
        }
      },
      {
        test: /\.html$/,
        // 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
        use: 'html-loader'
      },
      {
        test: /\.ttf$/,
        type: 'asset/resource',
        generator: {
          filename: 'fonts/[contenthash][ext]'
        }
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: ['@babel/plugin-transform-runtime']
          }
        }
      }

    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'styles/[contenthash].css'
    }),
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })

  ],
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    },
  }

};

webpack.dev.js  (开发环境配置,不需要缓存和压缩)


module.exports = {
  mode: 'development',
  output: {
    filename: 'scripts/[name].[contenthash].js'
  },
  devtool: 'inline-source-map',
  devServer: {
    static: './dist'
  }
};

webpack.prod.js (生产环境配置,加入缓存和压缩)

//这个插件使用 cssnano 优化和压缩 CSS。
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 该插件使用 terser 来压缩 JavaScript。
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  mode: 'production',
  output: {
    filename: 'scripts/[name].[contenthash].js',
    publicPath: 'http://localhost:8080/'
  },
  devtool: 'inline-source-map',
  optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`),将下一行取消注释
      // `...`,
      new CssMinimizerPlugin(),
      new TerserPlugin()
    ]
  },
  performance: {
    hints: false
  }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值