深入浅出Webpack - 2 - webpack配置参数

webpack配置

  • 配置⽅式

    • 通过⼀个js⽂件描述配置webpack.config.js
    • 执行webpack可执行文件时通过命令行参数传入参数,如webpack--devtool source-map
  • Webpack配置导出类型

    • Object、Function、Promise、Array
  • 按照配置所影响的功能来划分参数:

    • 全局配置参数
    • Entry:配置模块的⼊⼝。
    • Output:配置如何输出最终想要的代码。
    • Module:配置处理模块的规则。
    • Resolve:配置寻找模块的规则。
    • Plugins:配置扩展插件。
    • DevServer:配置DevServer。
  • 全局配置参数

    • context,用于设置基础目录(绝对路径),webpack会基于此路径解析入口文件entry和加载去Loader中的相对路径。默认情况下,context是webpack配置文件所在的目录。
     // webpack.config.js
     const path = require('path');
    
     module.exports = {
         context: path.resolve(__dirname, 'src'), // 设置基础目录为项目根目录下的 'src'
         entry: './index.js' // 此时入口文件是 'src/index.js'
     };
    
  • Entry

    • Entry的路径及其依赖的模块的路径可能采⽤相对于context的路径来描述,context会影响到这些相对路径所指向的真实⽂件。
    • entry,配置模块的⼊⼝,Webpack执⾏构建的第⼀步将从⼊⼝开始,搜寻及递归解析出所有⼊⼝依赖的模块。
    • entry的属性值可能是string、array、object 之⼀或组合。entry还可以配置动态⼊⼝
    // JS⼊⼝⽂件
    entry: './main.js',
    // 同步函数
    entry: () => {
        return {
            a: './pages/a.js',
            b: './pages/b.js',
        }
    },
    // 异步函数
    entry: () => {
        return new Promise((resolve) => {
        resolve({
            a: './pages/a.js',
            b: './pages/b.js',
        });
    })
    
    • chunk名称:Webpack会为每个⽣成的Chunk取⼀个名称,Chunk的名称和Entry的配置有关。
      • 如果entry是⼀个string或array,就只会⽣成⼀个Chunk,这时Chunk的名称是main。
      • 如果 entry 是⼀个 object,就可能会出现多个 Chunk,这时 Chunk 的名称是object键值对中键的名称。
  • Output

    • output,是⼀个object,⾥⾯包含⼀系列配置项;

    • output.filename,配置输出⽂件的名称,为 string类型;

      • 如果只有⼀个输出⽂件,则将它写成静态不变的:filename: 'bundle.js'
      • 在有多个Chunk要输出时,借助模板和变量,根据Chunk的名称来区分输出的⽂件名filename: '[name].js'
    • output.chunkFilename,配置⽆⼊⼝的 Chunk 在输出时的⽂件名称。但chunkFilename只⽤于指定在运⾏过程中⽣成的Chunk在输出时的⽂件名称。会在运⾏时⽣成Chunk的常⻅场景包括:使⽤CommonChunkPlugin、使⽤import('path/to/module')动态加载等;

    • output.path,配置输出⽂件存放在本地的⽬录,string类型的绝对路径。通过Node.js的path模块去获取绝
      对路径:path: path.resolve(__dirname, 'dist');

    • output.publicPath,配置发布到线上资源的 URL 前缀,为 string 类型。默认值是空字符串'',即使⽤相对路径;

    • output.crossOriginLoading,⽤于配置异步插⼊的标签的crosssorigin值;

    • output.libraryTarget 配置以何种⽅式导出库。

      • var(默认):编写的库将通过var被赋值给通过library指定名称的变量。
      • commonjs:编写的库将通过CommonJS规范导出。
      • commonjs2:编写的库将通过CommonJS2规范导出
      • this:编写的库将通过this被赋值给通过library指定的名称
      • window:编写的库将通过window赋值给通过library指定的名称
      • global:编写的库将通过global赋值给通过library指定的名称
    • output.library, 配置导出库的名称。

    • output.libraryExport,配置要导出的模块中哪些⼦模块需要被导出。它只有在output.libraryTarget被设置成
      commonjs或者commonjs2时使⽤才有意义。

    // var
    // webpack输出的代码
    var LibraryName = aa
    // 使⽤库的⽅法
    LibraryName.doSomething()
    
    // commonjs
    // webpack输出的代码
    exports['LibraryName'] = aa
    // 使⽤库的⽅法
    require('LibraryNameInNpm')['LibraryName'].doSomething()
    
    // commonjs2
    // webpack输出的代码
    module.exports = aa
    // 使⽤库的⽅法
    require('LibraryNameInNpm').doSomething()
    
    // this
    // webpack输出的代码
    this['LibraryName'] = aa
    // 使⽤库的⽅法
    this.LibraryName.doSomething()
    
    // window
    // webpack输出的代码
    window['LibraryName'] = aa
    // 使⽤库的⽅法
    window.LibraryName.doSomething()
    
    // global
    // webpack输出的代码
    global['LibraryName'] = aa
    // 使⽤库的⽅法
    global.LibraryName.doSomething()
    
    
    // 要导出的模块源代码
    export const a = 1
    export default = 2
    // 想让构建输出的代码只导出其中的a,则可以将output.libraryExport设置成a,那么构建输出的代码和使⽤⽅法
    将变成如下内容
    // webpack输出的代码
    module.exports = lib_code['a]
    // 使⽤库的⽅法
    require('library-name-in-npm') === 1
    
    
  • module,配置处理模块的规则,配置Loader

    • rules,配置模块的读取和解析规则,通常⽤来配置Loader。其类型是⼀个数组,数组⾥的每⼀项都描述了如何处理部
      分⽂件。配置⼀项rules时⼤致可通过以下⽅式来完成。
      • 条件匹配:通过test、include、exclude三个配置项来选中Loader要应⽤规则的⽂件。
      • 应⽤规则:对选中的⽂件通过use配置项来应⽤Loader,可以只应⽤⼀个Loader或者按照从后往前的顺序应⽤⼀组Loader,同时可以分别向Loader传⼊参数。
      • 重置顺序:⼀组Loader的执⾏顺序默认是从右到左执⾏的,通过enforce选项可以将其中一个Loader的执行顺序放到最前或者最后。
    • noParse,告诉 webpack 不解析某些模块(没采用模块化的文件,递归解析耗时无意义),用于提高构建性能。
    • parser,更细粒度地配置哪些模块语法被解析、哪些不被解析。同noParse配置项的区别在于,parser可以精确到语法层⾯,⽽noParse只能控制哪些⽂件不被解析。
      • 全局 parser:module.parser
      • 规则级 parser:module.rules[].parser
      • 规则级配置会覆盖全局配置
    module.exports = {
        module: {
            noParse: RegExp | [RegExp] | function, // 不解析某些模块
            parser: { /* 解析选项 */ }, // 模块解析配置
            rules: [ /* loader规则 */ ], // 模块处理规则
            defaultRules: [ /* 默认规则 */ ], // 默认loader规则(v5+)
            unsafeCache: boolean | function // 缓存配置
        }
    }
    
    module: {
        noParse: /jquery|lodash/, // 正则表达式
        // 或
        noParse: (content) => /some-library/.test(content) // 函数形式
    }
    
    module: {
        parser: {
            javascript: {
                commonjsMagicComments: true, // 支持CommonJS魔法注释
                requireInclude: false, // 禁用require.include
                requireEnsure: false, // 禁用require.ensure
                requireContext: false, // 禁用require.context
                dynamicImportMode: 'eager', // 动态导入模式
                // 更多解析选项...
            },
            asset: {
                dataUrlCondition: {
                    maxSize: 8 * 1024 // 8kb以下转base64
                }
            }
        }
    }
    
    module: {
        rules: [
            {
                test: /\.ext$/, // 匹配条件
                include: path, // 包含路径
                exclude: path, // 排除路径
                enforce: 'pre' | 'post', // 执行顺序
                use: [ // 使用的loader
                    { loader: 'loader-name', options: {} }
                ],
                type: 'javascript/auto' | 'asset/resource' | 'json'..., // 模块类型
                parser: { /* 规则特定parser配置 */ },
                generator: { /* 资源生成配置 */ },
                resolve: { /* 解析配置 */ },
                oneOf: [ /* 条件规则 */ ],
                rules: [ /* 嵌套规则 */ ]
            }
        ]
     }
    
     // 示例
    const path = require('path');
    
    module.exports = {
        module: {
            noParse: /(jquery|lodash)/,
            
            parser: {
            javascript: {
                dynamicImportMode: 'lazy',
                requireEnsure: false
            },
            asset: {
                dataUrlCondition: {
                    maxSize: 4 * 1024 // 4kb以下转base64
                }
            }
            },
            
            rules: [
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: {
                        loader: 'babel-loader'
                    },
                    parser: {
                        system: false // 禁用SystemJS语法
                    }
                },
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader'],
                    type: 'css/auto' // Webpack 5+ 资源模块类型
                },
                {
                    test: /\.png$/,
                    type: 'asset/resource',
                    generator: {
                        filename: 'images/[hash][ext]'
                    }
                }
            ]
        }
    }
    
  • resolve,配置Webpack如何寻找模块所对应的⽂件

    • resolve.alias,通过别名来将原导⼊路径映射成⼀个新的导⼊路径。alias 还⽀持通过$符号来缩⼩范围到只命中以关键字结尾的导⼊语句。
    • resolve.mainFields,决定优先采⽤哪份代码,有⼀些第三⽅模块会针对不同的环境提供⼏份代码。
      在导⼊语句没带⽂件后缀时,Webpack 会⾃动带上后缀后去尝试访问⽂件是否存在。
    • resolve.extensions⽤于配置在尝试过程中⽤到的后缀列表。
    • resolve.modules,配置 Webpack 去哪些⽬录下寻找第三⽅模块,默认只会去 node_modules ⽬录下寻找,可以增加其他⽂件夹名称。
    • resolve.descriptionFiles,配置描述第三⽅模块的⽂件名称,也就是 package.json⽂件。
    • resolve.enforceExtension,若被配置为true,则所有导⼊语句都必须带⽂件后缀
    • enforceModuleExtension,和enforceExtension的作⽤类似,但enforceModule Extension 只对 node_modules 下的模块⽣效
  • plugin,⽤于扩展Webpack的功能

    • plugins配置项接收⼀个数组,数组⾥的每⼀项都是⼀个要使⽤的Plugin的实例,Plugin需要的参数通过构造函数传
      ⼊。
  • DevServer,⽤来提⾼开发效率的

    • devServer.hot,是否启⽤模块热替换功能。DevServer的默认⾏为是在发现源代码被更新后通过⾃动刷新整个⻚⾯
      来做到实时预览,开启模块热替换功能后,将在不刷新整个⻚⾯的情况下通过⽤新模块替换⽼模块来做到实时预览。
    • DevServer的实时预览功能依赖⼀个注⼊⻚⾯⾥的代理客户端,去接收来⾃DevServer的命令并负责刷新⽹⻚的⼯
      作。
    • devServer.inline,⽤于配置是否将这个代理客户端⾃动注⼊将运⾏在⻚⾯中的Chunk⾥,默认⾃动注⼊。DevServer会根据我们是否开启inline来调整它的⾃动刷新策略。
      • 如果开启inline,则DevServer会在构建变化后的代码时通过代理客户端控制⽹⻚刷新。
      • 如果关闭 inline,则 DevServer 将⽆法直接控制要开发的⽹⻚。这时它会通过iframe的⽅式去运⾏要开发的⽹⻚。在构建完变化后的代码时,会通过刷新iframe来实现实时预览,但这时我们需要去 http://localhost:8080/webpack￾dev-server/实时预览⾃⼰的⽹⻚。
    • devServer.historyApiFallback,⽤于⽅便地开发使⽤了 HTML5 History API 的单⻚应⽤
    • devServer.contentBase,配置DevServer HTTP服务器的⽂件根⽬录。在默认情况下为当前的执⾏⽬录,通常是项⽬根⽬录
    • devServer.headers,可在HTTP响应中注⼊⼀些HTTP响应头
    • devServer.host,⽤于配置DevServer服务监听的地址,只能通过命令⾏参数传⼊
    • devServer.port,⽤于配置DevServer服务监听的端⼝,默认使⽤8080端⼝
    • devServer.allowedHosts,配置⼀个⽩名单列表,只有HTTP请求的HOST在列表⾥才正常返回
    • devServer.disableHostCheck,配置项⽤于配置是否关闭⽤于DNS重新绑定的HTTP请求的HOST检查。DevServer默认只接收来⾃本地的请求,关闭后可以接收来⾃任意HOST的请求。
    • DevServer默认使⽤HTTP服务,它也能使⽤HTTPS服务
    • devServer.clientLogLevel,配置客户端的⽇志等级,取值:none、error、warning、info。
    • devServer.compress,配置是否启⽤Gzip压缩
    • devServer.open,⽤于在DevServer启动且第⼀次构建完时,⾃动⽤我们的系统的默认浏览器去打开要开发的⽹⻚。还
      提供了
    • devServer.openPage, 配置项来打开指定 URL的⽹⻚。
  • devtool ,配置 Webpack 如何⽣成 Source Map

  • target,让Webpack构建出针对不同运⾏环境的代码

  • watch,开启监听模式

  • watchOptions,配置监听参数

  • externals,⽤来告诉在Webpack要构建的代码中使⽤了哪些不⽤被打包的模块

  • ResolveLoader ,⽤来告诉 Webpack 如何去寻找 Loader

// 整体配置参数参考
const path = require('path');

module.exports = {
  // 入口配置
  entry: { /*...*/ },
  
  // 输出配置
  output: { /*...*/ },
  
  // 模块处理规则
  module: { /*...*/ },
  
  // 解析配置
  resolve: { /*...*/ },
  
  // 插件配置
  plugins: [ /*...*/ ],
  
  // 开发服务器配置
  devServer: { /*...*/ },
  
  // 优化配置
  optimization: { /*...*/ },
  
  // 开发模式配置
  mode: 'development' | 'production',
  
  // 其他配置
  devtool: 'source-map',
  target: 'web',
  externals: { /*...*/ },
  stats: { /*...*/ }
};

// 入口配置
entry: {
  main: './src/index.js',
  vendor: './src/vendor.js'
}

// 出口配置
output: {
  path: path.resolve(__dirname, 'dist'),
  filename: '[name].[contenthash].js',
  publicPath: '/',
  clean: true,
  library: {
    name: 'MyLibrary',
    type: 'umd'
  }
}

// 模块处理
module: {
  noParse: /jquery|lodash/,
  parser: {
    javascript: { /*...*/ }
  },
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: ['babel-loader']
    },
    {
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
    }
  ]
}

// 解析配置
resolve: {
  extensions: ['.js', '.jsx', '.json'],
  alias: {
    '@': path.resolve(__dirname, 'src')
  },
  modules: ['node_modules'],
  mainFields: ['browser', 'module', 'main']
}

// 插件配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

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

// 开发服务器
devServer: {
  static: {
    directory: path.join(__dirname, 'public')
  },
  compress: true,
  port: 9000,
  hot: true,
  historyApiFallback: true,
  proxy: {
    '/api': 'http://localhost:3000'
  }
}

// 优化配置
optimization: {
  splitChunks: {
    chunks: 'all'
  },
  runtimeChunk: 'single',
  minimize: true,
  minimizer: [
    new TerserPlugin(),
    new CssMinimizerPlugin()
  ]
}

// 其他配置
mode: 'production' // 或 'development' 或 'none'
devtool: 'cheap-module-source-map'
target: 'web' // 或 'node' 或 ['web', 'es5']
externals: {
  jquery: 'jQuery'
}
// 统计信息
stats: {
  colors: true,
  modules: false
}



参考&感谢各路大神

  • [深入浅出Webpack-吴浩麟]
posted @ 2024-08-19 07:56  安静的嘶吼  阅读(7)  评论(0)    收藏  举报