美文网首页
webpack5 基本配置

webpack5 基本配置

作者: miao8862 | 来源:发表于2021-06-24 09:03 被阅读0次

    这篇文件主要介绍以下基本配置:

    1. 拆分不同环境的配置文件:webpack-merge
    2. 自动生成模板文件: html-webpack-plugin
    3. 自动删除以前的打包文件:clean-webpack-plugin
    4. 定义全局变量:
      • 使用cross-env设置命令行参数,并在配置文件中获取process.env.xxx,这个只能在脚本配置文件中获取
      • 使用webpack.DefinePlugin设置模块中可以使用的全局变量,注意要使用JSON.stringify封装变量
    5. 开发环境跨域设置:devServer.proxy中设置代理
    6. 样式资源导入处理
      • css:css-loader, style-loader
      • less:less-loader
      • 增加浏览器兼容前缀:postcss-loaderautoprefixer插件结合使用
      • 抽离css文件:mini-css-extract-pluginloader和插件
    7. 图片资源导入处理
      • file-loader:将资源文件抽离出来,打包到指定位置
      • url-loader:同file-loader,但url-loader增加文件大小阈值,小于阈值使用base64导入
    8. 将es6转换成es5:babel-loader

    创建demo

    1. 创建项目
    mkdir webpack-demo
    cd webpack-demo
    npm init -y
    npm i webpack webpack-cli -D
    

    可以看到package.json中webpack 和 webpack-cli的版本,现在最新的已经是webpack5

    {
      "name": "webpack-demo",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "webpack": "^5.40.0",
        "webpack-cli": "^4.7.2"
      }
    }
    
    1. 创建基本目录
    • src:资源目录,随便创建一个文件index.js,作为文件入口
    // index.js
    function hello() {
      console.log('hello')
    }
    hello()  // 注意要调用这个函数,不然会被默认tree-shaking掉
    
    • dist:创建打包输出目录
    • webpack.config.js:webpack默认的基本配置文件
    const path = require('path')
    
    module.exports = {
      entry: path.join(__dirname, 'src', 'index.js'), // 单文件入口
      output: {
        filename: 'bundle.js',  // 输出文件名
        path: path.join(__dirname, 'dist')  // 输出目录
      }
    }
    
    • 改下package.json脚本命令
    "scripts": {
        "build": "webpack"
      },
    
    1. 启动打包:npm run build
      会在dist/bundle.js打包出以下结果,可以看出来webpack5的tree-shaking已经非常强大,无用的代码不再被保留
    console.log("hello");
    

    区分 开发环境dev 和 生产环境prod

    在大项目中,我们往往需要根据不同的环境来进行不同的配置,所以需要拆分webpack配置文件

    1. 创建一个config目录,用来区分不同环境的配置文件:
      • webpack.common.js:用来配置公共的webpack配置
      • webpack.dev.js:用来配置开发环境专有的webpack配置
      • webpack.prod.js:用来配置生产环境专有的webpack配置
    2. 在不同环境的配置文件中,使用webpack-merge中的merge来合并公共的webpack配置文件(webpack4中是通过smart来合并的)
      npm i webpack-merge -D
    // webpack.common.js 公共的配置
    const path = require('path')
    const srcPath = path.join(__dirname, '..', 'src')
    
    module.exports = {
      entry: path.join(srcPath, 'index')
    }
    
    
    // webpack.dev.js
    const path = require('path')
    const commonConfig = require('./webpack.common')
    const {merge} = require('webpack-merge')
    const devConfig = {
      mode: 'development', // 开发环境
      output: {
        filename: 'bundle.js',  // 输出文件名
        path: path.join(__dirname, '..', 'dist')  // 输出目录
      }
    }
    module.exports = merge(commonConfig, devConfig)
    
    
    // webpack.prod.js
    
    const path = require('path')
    const commonConfig = require('./webpack.common.js')
    const {merge} = require('webpack-merge')
    
    const prodConfig = {
      mode: 'production', // 生产环境
      output: {
        filename: 'bundle.[chunkhash].js',  // 输出文件名,一般要加上hash
        path: path.join(__dirname, '..', 'dist')  // 输出目录
      }
    }
    
    module.exports = merge(commonConfig, prodConfig)
    
    1. package.json脚本中区分不同环境的启动命令
      先要安装:npm install webpack-dev-server -D
      PS:在webpack4中开发环境使用的命令是webpack-dev-server --config config/webpack.dev.js,在webpack5后,改成了webpack server
    "scripts": {
        "build": "webpack --config config/webpack.prod.js",
        "dev": "webpack server --config config/webpack.dev.js"
      },
    
    1. 运行npm run build,打包
    // dist/bundle.004799ddc36231aeaad8.js
    console.log("hello");
    

    html-webpack-plugin 自动创建index.html文件

    打包的js文件,需要我们有一个载体来查看结果,也就是我们一般说的模板文件index.html

    • 手动创建一个index.html(根目录)文件
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    <body>
      <script src="./dist/bundle.004799ddc36231aeaad8.js"></script>
    </body>
    </html>
    

    使用浏览器打开,可以看到正常输出的结果


    dev

    这个载体文件,不单单是开发环境需要,生产环境也是需要的,但是生产环境我们往往会生成不同的hash值来防止资源缓存,所以每次生成的文件名都是不同的,手动引入入口文件往往不太现实,所以需要借助html-webpack-plugin插件来自动生成项目中的html页面,并实现自动导入对应脚本

    • html-webpack-plugin 自动创建index.html文件
    1. 安装: npm i html-webpack-plugin -D
    2. plugins中使用,因为是公用的,所以写在webpack.common.js配置文件中:
    // webpack.common.js 公共的配置
    const path = require('path')
    const srcPath = path.join(__dirname, '..', 'src')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    
    module.exports = {
      entry: path.join(srcPath, 'index'),
      plugins: [
        new htmlWebpackPlugin({
          // 以根目录中的index.html文件作为模板来自动生成dist/index.html文件
          // 注意,这里是相对根目录而言的,因为脚本的上下文是在根目录下
          template: 'index.html'  
          // inject: 'head', // 脚本注入的位置,可以是head, body,或者为 false默认
          // 在这里还可以自定义参数,在模板中,使用ejs方式 <%= htmlWebpackPlugin.options %>获取自定义属性
          title: 'webpack demo',
          // webpack5默认开启压缩属性,webpack4要手动设置
          // minify: {
          //   removeComments: true, // 删除注释
          //   collapseWhitespace: true  // 删除空格
          // }
        })
      ]
    }
    
    1. 删除根目录下index.html模板中手动导入的语句,并接收自在htmlWebpackPlugin设置的自定义参数
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title><%= htmlWebpackPlugin.options.title %></title>
    </head>
    <body>
      <!-- 这是注释 -->
    </body>
    </html>
    
    1. 执行打包命令npm run build,可以看到dist目录下生成了index.html
      a. 自动导入了打包后的文件
      b. 显示了自定义参数的title标题
      c. 默认开启了压缩,删除了注释和空格
    <!doctype html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>webpack demo</title><script defer="defer" src="bundle.e97c675afbdcfa8f531d.js"></script></head><body></body></html>
    

    clean-html-plugin 删除之前的打包文件

    随便修改下入口文件,发现打包新的文件时,之前生成的打包文件每次都会存在,所以我们往往配合clean-html-plugin,在每次生成新的打包文件之前,会先删除之前的打包文件

    1. 安装 npm i clean-webpack-plugin -D
    2. webpack.common.js中配置
    // webpack.common.js 公共的配置
    const path = require('path')
    const srcPath = path.join(__dirname, '..', 'src')
    const htmlWebpackPlugin = require('html-webpack-plugin')
    // webpack5写法
    const {CleanWebpackPlugin} = require('clean-webpack-plugin')
    
    module.exports = {
      entry: path.join(srcPath, 'index'),
      plugins: [
        new CleanWebpackPlugin(), // 清除之前的打包文件
        new htmlWebpackPlugin({
          // 以根目录中的index.html文件作为模板来自动生成dist/index.html文件
          // 注意,这里是相对根目录而言的,因为脚本的上下文是在根目录下
          template: 'index.html'  
        })
      ]
    }
    

    PS:webpack4中导入插件的写法为const CleanWebpackPlugin = require('clean-webpack-plugin')

    1. 再次打包时,就发现之前的包被清除了

    定义全局变量

    我们通常会有个配置文件,需要根据环境的不同,配置不同的接口地址,这时一般就会用到全局变量,webpack可以使用DefinePlugin插件来设置全局变量

    我们一般在package.json文件运行脚本中,会自定义一个环境变量NODE_ENV(,这个变量其实是自定义的,但前端约定俗成用这个变量名):

    // mac电脑
    "scripts": {
        "build": "NODE_ENV=prod webpack --config config/webpack.prod.js",
        "dev": "NODE_ENV=dev webpack server --config config/webpack.dev.js NODE_ENV=development"
      },
    // windows电脑
    "scripts": {
        "build": "set NODE_ENV=prod && webpack --config config/webpack.prod.js",
        "dev": "set NODE_ENV=dev && webpack server --config config/webpack.dev.js NODE_ENV=development"
      },
    

    然后在其它脚本中,我们就可以通过process.env.NODE_ENV来获取

    为了写一个脚本配置,适配所有电脑,所以要安装cross-env解决跨平台问题:
    npm i cross-env -D,这样,就可以只使用一个脚本:

    "scripts": {
      "build": "cross-env NODE_ENV=prod webpack --config config/webpack.prod.js",
      "dev": "cross-env NODE_ENV=dev webpack server --config config/webpack.dev.js"
    },
    

    然后在webpack.common.js中,打印process.env.NODE_ENV可以获取到脚本中的设置值,注意,这个process.env只有在配置文件中才能获取到,在其它index.js中是获取不到的,除非设置了全局变量

    // webpack.common.js
     plugins: [
        new webpack.DefinePlugin({
          'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
        })
      ]
    

    webpack4之后,上面这些操作,webpack都帮我们内置了,所以可以在任何js文件中都能获取到process.env.NODE_ENV的值,这个值对应的是webpack配置文件中的mode值,即developmentproduction

    这里主要是说明怎么接收命令行的参数,并在DefinePlugin设置全局变量的方法,方便我们在模块中使用,但注意的是,设置的对象需要使用JSON.stringify转换,包括字符串(否则字符串会被识别成变量而报错)

    开发环境启动和配置

    之前配置了开发环境脚本,但一直没用,现在有了index.html模板文件和打包后的js文件,就可以使用npm run dev启动命令,根据提示打开浏览器,访问http://localhost:8080/就可以查看结果了

    dev启动

    跨域配置

    在开发环境最常用的配置是处理跨域问题,在webpack.dev.js中设置devServer,这点和webpack4是一样的

    // webpack.dev.js
    
    const path = require('path')
    const commonConfig = require('./webpack.common')
    const {merge} = require('webpack-merge')
    const devConfig = {
      mode: 'development', // 开发环境
      output: {
        filename: 'bundle.js',  // 输出文件名
        path: path.join(__dirname, '..', 'dist')  // 输出目录
      },
      devServer: {
        // 设置代理
        proxy: {
          // 将本地 /api/xxx 代理到 localhost:6666/api/xxx
          // '/api': 'http://localhost:3000',
    
          // 将本地 /api2/xxx 代理到 localhost:6666/xxx,通常用这个,/api2仅作为代理转发的标识
          '/api2': {
              target: 'http://localhost:3000',
              changeOrigin: true,
              pathRewrite: {
                  '/api2': ''
              }
          }
        }
      }
    }
    
    module.exports = merge(commonConfig, devConfig)
    

    修改index.js文件,请求跨域的接口

    function hello() {
      console.log('hello11')
    }
    fetch('/api2/data').then(res => {
      console.log(1111)
    })
    // 显示跨域
    fetch('http://localhost:3000/data').then(res => {
      console.log(2222)
    })
    hello()
    

    写个简单的express服务器来测试:

    const express = require('express')
    const app = express()
    
    app.listen(3000, () => {
      console.log('server is running in port: 3000');
    })
    app.get('/data', (req, res) => {
      console.log('11111')
      res.send('hello')
    })
    

    然后启动开发环境:npm run dev

    image.png
    image.png

    文件资源处理

    .js文件中导入import './style/index.css'样式文件,运行,发现会报错,这是因为webpack默认只认识js文件,其它类型的文件都不识别。
    要使webpack识别它们,必须引入对应的loader去处理,将其转换成js认识的文件

    1. 处理样式文件

    识别.css文件

    1. 安装npm i css-loader style-loader -D
    2. webpack.common.js中配置module.rules规则:
      • css-loade:为了在js中使用import方式导入css文件
      • style-loader:将样式写在html文件中head标签内的<style>标签中
    module.exports = {
      entry: path.join(srcPath, 'index'),
       module: {
        rules: [
          {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
          },
        ]
      },
      },
    

    识别.less文件(sass、stylus同理)

    要在.js中使用import './src/style/xxx.less'文件:

    1. 安装npm i css-loader style-loader less-loader less -D
    2. 配置
      • less-loader:将.less文件转译成.css文件
    module: {
        rules: [
          {
            test: /\.less$/,
            use: ['style-loader', 'css-loader', 'less-loader']
          }
        ]
      },
    

    自动添加hack前缀

    1. 安装npm i postcss-loader autoprefixer -D
    2. webpack.common.js中配置
    module: {
        rules: [
          {
            test: /\.css$/,
            use: ['style-loader', 'css-loader', 'postcss-loader']
          },
          {
            test: /\.less$/,
            use: ['style-loader', 'css-loader','postcss-loader',  'less-loader']
          }
        ]
      },
      plugins: [
        require('autoprefixer')
      ]
    

    CSS文件抽离

    在生产环境中,我们往往不会将样式文件给打包到html文件中,而是单独抽离css文件

    1. 安装:npm i mini-css-extract-plugin -D
    2. 在生产环境配置文件中webpack.prod.js配置,将前面的 style-loader换成mini-css-extract-pluginloader
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    const prodConfig = {
      mode: 'production', // 生产环境
      output: {
        filename: 'bundle.[chunkhash].js',  // 输出文件名,一般要加上hash
        path: path.join(__dirname, '..', 'dist')  // 输出目录
      },
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
          },
          {
            test: /\.less$/,
            use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader']
          }
        ]
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: 'css/[name]-[contenthash].css'
        })
      ]
    }
    
    1. 打包npm run build
      css抽离

    2. 图片资源文件

    想在.css中使用url导入图片

    body {
      background-color: yellow;
      opacity: 0.7;
      transform: rotate(45deg);
      background: url('../imgs/img002.jpg');
    }
    

    或者在.js中使用import导入图片

    import img from './imgs/img002.jpg'
    

    需要借助file-loader或者url-loaderurl-loaderfile-loader差不多,只不过增加了一个设置文件大小阈值,当小于这个阈值时,使用base64导入文件

    • 开发环境
    1. 安装:npm i file-loader -D
    2. 在开发环境,因为不用考虑压缩问题,所以webpack.dev.js可以配置file-loader
    // 处理css样式文件中的url图片
          {
            test: /\.(jpg|png|jpeg|gif)$/,
            use: ['file-loader']
          }
    
    • 生产环境
    1. 安装: npm i url-loader -D
    2. 在生产环境,可以使用url-loader设置小图片使用base64方式写入
    // 处理css样式文件中的url图片
    {
            test: /\.(jpg|png|jpeg|gif)$/,
            use: {
              loader:'url-loader',
              options: {
                limit: 8192,    //限制 8kb 以下使用base64
                esMoudle: false,
                name: '[name]-[hash:8].[ext]',
                // 打包到/images目录下
                outputPath: 'images'
              }
            }
            
          }
    

    解析ES6+代码

    • 安装: npm i babel-loader @babel/core @babel/preset-env -D
    • 配置:
    // webpack.common.js
      module: {
        rules: [
          {
            test: /\.js$/,
            use: ['babel-loader'], // 1. 开启缓存
            include: srcPath, // 2. 缩小适合范围(写include或exclude)
            exclude: /node_modules/
            }
        ]
      }
    
    // 根目录创建,.babelrc
    {
      "presets": ["@babel/preset-env"],  // 一般使用@babel/preset-env就够了
      "plugins": []
    }
    
    // 如果是高版本的babel,比如v7.8.0 或更高版本的babel等
    // .babelrc 换成根目录创建 babel.config.json
    {
      "presets": [
        [
          "@babel/env",
          {
            "targets": {
              "edge": "17",
              "firefox": "60",
              "chrome": "67",
              "safari": "11.1"
            },
            "useBuiltIns": "usage",
            "corejs": "3.6.5"
          }
        ]
      ]
    }
    

    总的来说,webpack5对比webpack4来说,改动不算太多,还算是比较平稳过渡,最后,借用网上一张图,说明webpack4升级webpack5的改动:

    webpack5与webpack4差异.png

    参考:
    https://blog.csdn.net/xiaolinlife/article/details/107032533
    https://www.imooc.com/article/287156#comment

    相关文章

      网友评论

          本文标题:webpack5 基本配置

          本文链接:https://www.haomeiwen.com/subject/zotvyltx.html