webpack从入门到进阶(一)—— webpack基本使用

243 阅读3分钟

开场之前,先隆重的介绍一下今天的主角webpack。它是个啥呢?用官方的话说,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。需要特别说明的一点是,webpack配置文件遵循的common.js语法规范的。

一、核心概念

在使用webpack进行打包之前,需要先了解webpack的几个核心概念:

  • enrty(入口)
  • output(出口)
  • loader
  • plugin(插件)
  • mode(模式)

二、webpack安装配置

自从webppack4.0之后,webpack就多了一个搭配使用的好兄弟——webpack-cli。想用webpack就必须同时安装webpack-cli。凭啥官网说要一起用就非得一起用啊,我不能整点花活装一下?经过一番探索之后,在webpack的源码中发现下面这段代码,断绝了我的念想:

const cli = {
    installed: isInstalled("webpack-cli"),
};

if (!cli.installed) {
    console.error(`We will use "${packageManager}" to install the CLI via "${packageManager} ${installOptions.join("")} ${cli.package}".`;
} else {
    runCli(cli);
}

当然,webpack-cli其实是很有用处的,比如说,想要执行一次打包 npx webapack --configwebpack-cli提供的能力。在package.json里面配置命令行,可以将复杂的打包命令简化。

    "start": "webpack serve --open --config ./config/webpack.dev.js",
    "build": "webpack --config ./config/webpack.prod.js"

说到这里,不知道有没有人对webpack的配置文件命名产生过好奇。不知道大家有没有对webpack.config.js这个文件名称产生好奇,反正我是很好奇。经过一番探索发现,原来如此:

const defaultConfigFiles = [
    "webpack.config",
    ".webpack/webpack.config",
    ".webpack/webpackfile",
]
    .map((filename) =>
          // Since .cjs is not available on interpret side add it manually to default config extension list
        [...Object.keys(interpret.extensions), ".cjs"].map((ext) => ({
            path: path.resolve(filename + ext),
            ext: ext,
        module: interpret.extensions[ext],
        })),
        )
    .reduce((accumulator, currentValue) => accumulator.concat(currentValue), []);

二、entry(入口)常见应用场景

最简单的单文件入口配置:

entry: './path/to/my/entry/file.js',

在webpack优化的时候,会将第三方依赖或者公共文件剥离出来,这时会用到多入口配置,当然这里只说一下entry配置,具体优化实现,等到我们后面讲到webpack打包优化的时候再具体说一下:

entry: {
    main: './src/app.js',
    vendor: './src/vendor.js',
},

多页面的时候,配置多入口文件:

entry: {
    pageOne: './src/pageOne/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js',
},

三、output(出口)

通过配置ouput选项,告诉webpack程序往哪里输出编译文件。需要注意的是,即使是存在多个入口文件,也只有一个出口文件,而且出口文件必须是绝对路径(通过path模块处理路径)。 如果使用相对路径,打包编译的时候会报错:

[webpack-cli] Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
 - configuration.output.path: The provided value "./dist" is not an absolute path!
 -> The output directory as **absolute path** (required).

四、loader

在开始使用loader之前,我们先介绍一下loader的执行顺序:从右到左、从下到上。这是一种很常见的函数式编程逻辑。具体实现逻辑需要查看loader-runner源码,在 iteratePitchingLoaders 函数中有这样一段代码

if loaderContext.loaderIndex >= loaderContext.loaders.length) {
    return processResource(options, loaderContext, callback);
}

1.处理css样式

{
    test: /\.css$/,
    use: [
        { loader: 'style-loader' },
        {
            loader: 'css-loader',
            options: {
                modules: true
            }
        },
        { loader: 'sass-loader' }
    ]
}
  1. 处理图片文件 在webpack 5 中,可以使用内置的 Asset Modules 模块来处理文件资源,类似于 file-loader
{
    test: /\.(png|svg|jpg|jpeg|gif)$/i,
    type: 'asset/resource',
},
  1. 处理字体文件
{
    test: /.(woff|woff2|eot|ttf|otf)$/i,
    type: 'asset/resource',
},

五、plugins(插件)

  1. html-webpack-plugin
new HtmlWebpackPlugin({
    title: '首页',
    template: path.resolve(__dirname, '../public/index.html'),
    favicon: path.resolve(__dirname, '../public/favicon.svg'),
    meta: {
    keywords: 'webpack5, webpack',
    description: 'webpack 是一个模块打包器。它的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用,但它也能够胜任转换(transform)、打包(bundle)或包裹(package)任何资源(resource or asset)。',
    author: 'wyf',
    viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no',
    },
    minify: true,
    chunks: ['main']
}),
  1. clean-webpack-plugin
new CleanWebpackPlugin()

需要特殊注意的是,clean-webpack-plugin 的新版本之后,抛出的方式不再是export defaults CleanWebpackPlugin,是export { CleanWebpackPlugin },所以引入插件的时候需要注意。

六、mode

通过将配置设置为production|development来将 DefinePlugin 中 process.env.NODE_ENV 的值设置为production|development,如果没有设置,webpack 会给 mode 的默认值设置为 production

我在使用中发现,通过mode配置存在process.env.NODE_ENV为undefined的情况,这个时候,不要慌,通过在script命令中配置set NODE_ENV=production就可以轻松解决了。