Skip to content

Latest commit

 

History

History
698 lines (641 loc) · 13.6 KB

1.10.1 公共路径.md

File metadata and controls

698 lines (641 loc) · 13.6 KB

1.10.1 公共路径

publicPath 配置选项在各种场景中都非常有用。你可以通过它来指定应用程序中所有资源的基础路径。

  • 基于环境设置

    在开发环境中,我们通常有一个 assets/ 文件夹,它与索引页面位于同一级别。这没太大问题,但是,如果我们将所有静态资源托管至 CDN,然后想在生产环境中使用呢?

    想要解决这个问题,可以直接使用一个 environment variable(环境变量)。假设我们有一个变量 ASSET_PATH

    import webpack from 'webpack';
    
    // 尝试使用环境变量,否则使用根路径
    const ASSET_PATH = process.env.ASSET_PATH || '/';
    
    export default {
      output: {
        publicPath: ASSET_PATH,
      },
    
      plugins: [
        // 这可以帮助我们在代码中安全地使用环境变量
        new webpack.DefinePlugin({
          'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH),
        }),
      ],
    };

    11-multiple-env/webpack.config.js

    //...
    import webpack from 'webpack';
    
    // 尝试使用环境变量,否则使用根路径
    const ASSET_PATH = process.env.ASSET_PATH || '/';
    
    export default {
    output: {
      //...
    
      publicPath: ASSET_PATH,
    },
    
    plugins: [
      // 这可以帮助我们在代码中安全地使用环境变量
      new webpack.DefinePlugin({
        'process.env.ASSET_PATH': JSON.stringify(ASSET_PATH),
      }),
    
      //...
    ],
    };
  • Automatic publicPath

    有可能你事先不知道 publicPath 是什么,webpack 会自动根据 import.meta.urldocument.currentScriptscript.src 或者 self.location 变量设置 publicPath。你需要做的是将 output.publicPath 设为 'auto'

    module.exports = {
      output: {
        publicPath: 'auto',
      },
    };

    请注意在某些情况下不支持 document.currentScript,例如:IE 浏览器,你不得不引入一个 polyfill,例如 currentScript Polyfill

1.10.2 环境变量

想要消除 webpack.config.js开发环境生产环境 之间的差异,你可能需要环境变量(environment variable)。

webpack 命令行 环境配置--env 参数,可以允许你传入任意数量的环境变量。而在 webpack.config.js 中可以访问到这些环境变量。例如,--env production--env goal=local

npx webpack --env goal=local --env production --progress

对于我们的 webpack 配置,有一个必须要修改之处。通常,module.exports 指向配置对象。要使用 env 变量,你必须将 module.exports 转换成一个函数:

11-multiple-env/webpack.config.js

//...
module.exports = (env) => {
return {
//...
// 根据命令行参数 env 来设置不同环境的 mode
mode: env.production ? 'production' : 'development',
//...
}
}

1.10.3 拆分配置文件

目前,生产环境和开发环境使用的是一个配置文件,我们需要将这两个文件单独放到不同的配置文件中。如webpack.config.dev.js(开发环境配置)和 webpack.config.prod.js(生产环境配置)。在项目根目录下创建一个配置文件夹 config 来存放他们。

webpack.config.dev.js 配置如下:

11-multiple-env/config/webpack.config.dev.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')

module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},

output: {
filename: 'scripts/[name].js',
path: path.resolve(__dirname, './dist'),
clean: true,
assetModuleFilename: 'images/[contenthash][ext]'
},

mode: 'development',

devtool: 'inline-source-map',

plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'app.html',
inject: 'body'
}),

new MiniCssExtractPlugin({
filename: 'styles/[contenthash].css'
})
],

devServer: {
static: './dist'
},

module: {
rules: [
{
  test: /\.png$/,
  type: 'asset/resource',
  generator: {
    filename: 'images/[contenthash][ext]'
  }
},

{
  test: /\.svg$/,
  type: 'asset/inline'
},

{
  test: /\.txt$/,
  type: 'asset/source'
},

{
  test: /\.jpg$/,
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: 4 * 1024 * 1024
    }
  }
},

{
  test: /\.(css|less)$/,
  use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
},

{
  test: /\.(woff|woff2|eot|ttf|otf)$/,
  type: 'asset/resource'
},

{
  test: /\.(csv|tsv)$/,
  use: 'csv-loader'
},

{
  test: /\.xml$/,
  use: 'xml-loader'
},

{
  test: /\.toml$/,
  type: 'json',
  parser: {
    parse: toml.parse
  }
},

{
  test: /\.yaml$/,
  type: 'json',
  parser: {
    parse: yaml.parse
  }
},

{
  test: /\.json5$/,
  type: 'json',
  parser: {
    parse: json5.parse
  }
},

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

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

webpack.config.prod.js 配置如下:

11-multiple-env/config/webpack.config.prod.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')

module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},

output: {
filename: 'scripts/[name].[contenthash].js',
// 打包的dist文件夹要放到上一层目录
path: path.resolve(__dirname, '../dist'),
clean: true,
assetModuleFilename: 'images/[contenthash][ext]',
publicPath: 'http://localhost:8080/'
},

mode: 'production',

plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'app.html',
inject: 'body'
}),

new MiniCssExtractPlugin({
filename: 'styles/[contenthash].css'
})
],

module: {
rules: [
{
  test: /\.png$/,
  type: 'asset/resource',
  generator: {
    filename: 'images/[contenthash][ext]'
  }
},

{
  test: /\.svg$/,
  type: 'asset/inline'
},

{
  test: /\.txt$/,
  type: 'asset/source'
},

{
  test: /\.jpg$/,
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: 4 * 1024 * 1024
    }
  }
},

{
  test: /\.(css|less)$/,
  use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
},

{
  test: /\.(woff|woff2|eot|ttf|otf)$/,
  type: 'asset/resource'
},

{
  test: /\.(csv|tsv)$/,
  use: 'csv-loader'
},

{
  test: /\.xml$/,
  use: 'xml-loader'
},

{
  test: /\.toml$/,
  type: 'json',
  parser: {
    parse: toml.parse
  }
},

{
  test: /\.yaml$/,
  type: 'json',
  parser: {
    parse: yaml.parse
  }
},

{
  test: /\.json5$/,
  type: 'json',
  parser: {
    parse: json5.parse
  }
},

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

optimization: {
minimizer: [
new CssMinimizerPlugin()
],

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

//关闭 webpack 的性能提示
performance: {
hints:false
}
}

拆分成两个配置文件后,分别运行这两个文件:

开发环境:

[felix] 10-multiple-env $ npx webpack serve -c ./config/webpack.config.dev.js

生产环境:

[felix] 10-multiple-env $ npx webpack -c ./config/webpack.config.prod.js

1.10.4 npm 脚本

每次打包或启动服务时,都需要在命令行里输入一长串的命令。我们将父目录的 package.jsonnode_modulespackage-lock.json 拷贝到当前目录下,

image-20211023161251468

配置 npm 脚本来简化命令行的输入,这时可以省略 npx

11-multiple-env/package.json

{
"scripts": {
"start": "webpack serve -c ./config/webpack.config.dev.js",
"build": "webpack -c ./config/webpack.config.prod.js"
}
}

开发环境运行脚本:

[felix] 10-multiple-env $ npm run start
[felix] 10-multiple-env $ npm run build

1.10.5 提取公共配置

这时,我们发现这两个配置文件里存在大量的重复代码,可以手动的将这些重复的代码单独提取到一个文件里,

创建 webpack.config.common.js,配置公共的内容:

11-multiple-env/config/webpack.config.common.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const toml = require('toml')
const yaml = require('yaml')
const json5 = require('json5')

module.exports = {
entry: {
index: './src/index.js',
another: './src/another-module.js'
},

output: {
// 注意这个dist的路径设置成上一级
path: path.resolve(__dirname, '../dist'),
clean: true,
assetModuleFilename: 'images/[contenthash][ext]',
},

plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'app.html',
inject: 'body'
}),

new MiniCssExtractPlugin({
filename: 'styles/[contenthash].css'
})
],

module: {
rules: [
{
  test: /\.png$/,
  type: 'asset/resource',
  generator: {
    filename: 'images/[contenthash][ext]'
  }
},

{
  test: /\.svg$/,
  type: 'asset/inline'
},

{
  test: /\.txt$/,
  type: 'asset/source'
},

{
  test: /\.jpg$/,
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: 4 * 1024
    }
  }
},

{
  test: /\.(css|less)$/,
  use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
},

{
  test: /\.(woff|woff2|eot|ttf|otf)$/,
  type: 'asset/resource'
},

{
  test: /\.(csv|tsv)$/,
  use: 'csv-loader'
},

{
  test: /\.xml$/,
  use: 'xml-loader'
},

{
  test: /\.toml$/,
  type: 'json',
  parser: {
    parse: toml.parse
  }
},

{
  test: /\.yaml$/,
  type: 'json',
  parser: {
    parse: yaml.parse
  }
},

{
  test: /\.json5$/,
  type: 'json',
  parser: {
    parse: json5.parse
  }
},

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

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

//关闭 webpack 的性能提示
performance: {
hints:false
}
}

改写 webpack.config.dev.js:

11-multiple-env/config/webpack.config.dev.js

module.exports = {
// 开发环境不需要配置缓存
output: {
filename: 'scripts/[name].js',
},

// 开发模式
mode: 'development',

// 配置 source-map
devtool: 'inline-source-map',

// 本地服务配置
devServer: {
static: './dist'
}
}

修改 webpack.config.prod.js:

11-multiple-env/config/webpack.config.prod.js

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
// 生产环境需要缓存
output: {
filename: 'scripts/[name].[contenthash].js',
publicPath: 'http://localhost:8080/'
},

// 生产环境模式
mode: 'production',

// 生产环境 css 压缩
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
}

1.10.6 合并配置文件

配置文件拆分好后,新的问题来了,如何保证配置合并没用问题呢?webpack-merge 这个工具可以完美解决这个问题。

image-20211023142058484

安装 webpack-merge:

[felix] felixcourses $ npm install webpack-merge -D

创建 webpack.config.js,合并代码:

11-multiple-env/config/webpack.config.js

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

const commonConfig = require('./webpack.config.common.js')

const productionConfig = require('./webpack.config.prod.js')

const developmentConfig = require('./webpack.config.dev')

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

-- 本篇完 --