Webpack 5(四)基础配置

mode

可以在命令行或配置文件来指定 mode:

命令行:

webpack --mode development

配置文件:

moedule.exports = {
  mode: 'production'
}

mode 的值可以是:

  • none
  • development
  • production(默认值)

none

none 模式下,webpack 不会帮你做任何配置

development

development 模式下,将侧重于功能调试和优化开发体验,包含如下内容:

  1. 浏览器调试工具
  2. 开发阶段的详细错误日志和提示
  3. 快速和优化的增量构建机制

production

production 模式下,将侧重于模块体积优化和线上部署,包含如下内容:

  1. 开启所有的优化代码
  2. 更小的 bundle 大小
  3. 去除掉只在开发阶段运行的代码
  4. Scope hoisting 和 Tree-shaking
  5. 自动启用 terser 对代码进行压缩

process.env.NODE_ENV

参考文档

mode 的值决定了打包生成的 chunk 中 process.env.NODE_ENV 的值,根据开发模式下和生产模式执行不同的代码:

/* app.js */

if (process.env.NODE_ENV === 'production') {
  doSomething()
} else if (process.env.NODE_ENV === 'development') {
  doSomethingElse()
}

一共在两个地方可以使用 process.env.NODE_ENV

  • 在 webpack 配置文件中使用 process.env.NODE_ENV
  • 在项目源代码中使用 process.env.NODE_ENV

在 webpack 配置文件中使用 process.env.NODE_ENV,访问的是通过命令行传入的参数 NODE_ENV,也就是 package.json 文件中 scripts 里面定义的 NODE_ENV 的值。

/* package.json */
  
{
  "scripts": {
    "build": "NODE_ENV=production webpack",
    "dev": "NODE_NEV=development webpack serve --open"
  }
}
/* webpack.config.js */
 
console.log(process.env.NODE_ENV) // 这里的值是通过命令行传入的参数值,如果是 npm run build,则值为 production。

在项目源代码中使用 process.env.NODE_ENV,访问的是在配置文件中通过 DefinePlugin 定义的值,而不是通过命令行传入的值。将配置文件的 mode 设置为 development 或者 production,相当于自动通过 DefinePlugin 定义了可以在源代码中访问的 process.env.NODE_ENV 为 mode 的值。

/* webpack.config.js */

const webpack = require('webpack');

module.exports = {
  mode: 'development',
  entry: {
      app: './src/app'
  },
  output: {
      path: 'dist',
      filename: 'bundle.js'
  },
  plugins: [
      new webpack.DefinePlugin({
          // 这里定义了可以在模块中访问的 process.env.NODE_ENV 的值
          'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      })
  ]
};
/* src/index.js */

console.log(process.env.NODE_ENV); // 这里输出的是在配置文件中 mode 指定的值

context

基础目录,用于查找 entry 和 loader 中的文件。必须是绝对路径,默认为配置文件所在的目录。entry 和 loader 中的文件指定相对路径,相对于 context 的路径。

module.exports = {
  context: path.resolve(__dirname)
  entry: {
   // 相对路径,相对 context 选项
   index: './src/index.js',
   // 模块路径,根据模块的解析规则来解析
   vendor: 'lodash'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        // 推荐使用模块路径
        use: ['./node_modules/style-loader', 'css-loader']         
      }     
    ]
  }
}

entry

entry 的值可以是:

  • 字符串,简写形式,chunkname 为 main
  • 数组,简写形式,chunkname 为 main
  • 对象,推荐使用对象来设置 entry 的值
  • 函数,动态 entry
module.exports = {
  entry: './src/index.js'
}

module.exports = {
  entry: ['./src/index.js', './lib/func.js']
}

module.exports = {
  entry: {
    main: './src/index.js'
  }
}

module.exports = {
  entry: {
    main: ['./src/index.js', './lib/func.js']
  }
}

module.exports = {
  entry: () => './src/index.js'
}

推荐使用对象来设置 entry 的值:

  • 格式:键值对,一个键值对会打包成一个 initial chunk
  • 键名:键名是 chunk name,output.filename 占位符中的 [name] 就是 chunk name 的值
  • 键值:键值是入口文件路径,可以是相对路径或模块路径,相对路径相对于 context,模块路径根据模块解析规则来解析
  • 键值:可以是字符串、数组、对象

将一张依赖图生成一个 chunk,同一个 chunk 中不存在重复的模块

module.exports = {
  entry: {
    main: './src/index.js'
  }
}

将多张依赖图生成一个 chunk,同一个 chunk 中不存在重复的模块(不同依赖图中的相同模块只会打包成一个模块,不会重复打包,通过 webpack_require 来多次引入)

module.exports = {
  entry: {
    main: ['./src/index.js', './lib/func.js']
  }
}

将多张依赖图生成多个 chunk,不同 chunk 中可能存在重复的模块

module.exports = {
  entry: {
    index: './src/index.js',
    about: './src/about.js',
    admin: './src/admin.js',
  },
  optimazation: {
    runtimeChunk: 'multiple'
  }
}
module.exports = {
  entry: {
    home: './home.js',
    shared: ['react', 'react-dom', 'redux', 'react-redux'],
    catalog: {
      import: './catalog.js',
      filename: 'pages/catalog.js',
      dependOn: 'shared',
      chunkLoading: false, // Disable chunks that are loaded on demand and put everything in the main chunk.
    },
    personal: {
      import: './personal.js',
      filename: 'pages/personal.js',
      dependOn: 'shared',
      chunkLoading: 'jsonp',
      asyncChunks: true, // Create async chunks that are loaded on demand.
      layer: 'name of layer', // set the layer for an entry point
    },
  },
}

output

output.filename

指定 initial chunk 的全名,以及从 initial chunk 中分离出来的 split chunk (runtime, vendor, common) 的全名

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

占位符:

  • [name]:chunk name
  • [id]:chunk id
  • [contenthash]:根据 chunk 的内容创建唯一哈希值

生产模式下,推荐 chunk 文件名 filename: [name].[contenthash].js

output.chunkFilename

指定 async chunk 的全名,以及从 async chunk 中分离出来的 split chunk (vendor, common) 的全名

module.exports = {
  output: {
    chunkFilename: '[name].chunk.js'
  }
}

output.path

打包生成的 chunk 文件和资源文件所在的目录,必须是绝对路径

module.exports = {
  output: {
    path: path.resolve(__dirname, 'dist')
  }
}

output.publicPuth

module.exports = {
  output: {
    publicPath: '',
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].bundle.js',
    chunkFilename: '[name].chunk.js',
    clean: true
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      },
      {
        test: /\.(jpg|jpeg|png|gif)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'images/[hash][ext]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: 'css/[name].css'
    })
  ],
}

资源访问路径 = output.publicPath + 资源名称

  • 通过 output.publicPath + output.filename 访问 initial chunk 文件
  • 通过 output.publicPath + output.chunkFilename 访问 async chunk 文件
  • 通过 output.publicPath + MiniCssExtractPlugin 插件的 options.filename 访问 css 文件
  • 通过 output.publicPath + {图片资源 rule}.generator.filename 访问 asset/resource 资源文件

output.publicPath 可以是绝对路径、相对于服务的路径、相对于页面的路径。不管是哪种路径,都要以 / 结尾

publicPath: "https://cdn.example.com/assets/", // CDN(总是 HTTPS 协议)
publicPath: "//cdn.example.com/assets/", // CDN (协议相同)
publicPath: "/assets/", // 相对于服务(server-relative)
publicPath: "assets/", // 相对于 HTML 页面
publicPath: "../assets/", // 相对于 HTML 页面
publicPath: "", // 相对于 HTML 页面(目录相同),默认值
  1. 如果 output.publicPath 是绝对路径 http://www.google.com/

HtmlWebpackPlugin 生成的 index.html 文件:

<script defer src="http://www.google.com/app.bundle.js"></script>
<link href="http://www.google.com/css/app.min.css" rel="stylesheet">

MiniCssExtractPlugin 生成的 css 文件:

.container {
  background: url(http://www.google.com/images/01dfd42294af18c510ac.jpg) no-repeat;
}
  1. 如果 output.publicPath 是相对服务的路径 /backend/

HtmlWebpackPlugin 生成的 index.html 文件:

<script defer src="/backend/app.bundle.js"></script>
<link href="/backend/css/app.min.css" rel="stylesheet">

MiniCssExtractPlugin 生成的 css 文件:

.container {
  background: url(/backend/images/01dfd42294af18c510ac.jpg) no-repeat;
}
  1. 如果 output.publicPath 是相对页面的路径 ./backend/

HtmlWebpackPlugin 生成的 index.html 文件:

<script defer src="./backend/app.bundle.js"></script>
<link href="./backend/css/app.min.css" rel="stylesheet">

MiniCssExtractPlugin 生成的 css 文件:

.container {
  background: url(./backend/images/01dfd42294af18c510ac.jpg) no-repeat;
}

不管通过哪种路径设置 output.publicPath,都只是影响 HtmlWebpackPlugin 和 MiniCssExtractPlugin 生成的文件中引用其他资源的路径。具体能不能根据资源路径访问到相应的资源,还得正确的部署 output.path 目录到服务器。

在开发模式下,devServer 自动开启一个开发服务器,并且将所有打包生成的资源存储到内存当中,然后通过 http://[devServer.host]:[devServer.port]/[output.publicPath]/资源名称来访问对应的资源。 这时候 output.publicPath 应该设置为相对服务的路径,例如 /。如果你的页面希望在其他不同路径中找到资源文件,则可以通过 devServer 配置中的 devMiddleware.publicPath 选项进行修改。

在生产模式下,推荐将 output.publicPath 设置为绝对路径,然后将 output.path 目录部署与绝对路径对应的服务器中。

output.clean

是否在生成文件之前清空 output.path 目录

module.exports = {
  output: {
    clean: true
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容