新手入门webpack4踩坑记录

509 阅读4分钟

0 前言

最近在工作过程中遇到一个需求,需要将前端项目打包为静态资源并且部署到CDN。这个对于我这个刚入行的前端小菜鸟来说,完全是一脸懵逼,大概只知道这个跟webpack有关。因为项目的基础搭建工作是另一位老鸟搭建的,期间我只会写写业务代码。这次的任务对我来说是个挑战,所以只能硬着头皮上了。
任务完成之后趁着有点闲暇时间,觉得非常有必要学习下webpack的知识。在掘金找到了一篇详细的入门讲解 webpack4.x最详细入门讲解,作者写得非常详细且完整,完全是手摸手教的级别,于是跟着巧了一遍代码,受益匪浅,在此感谢原文作者。但是在时间过程中也难免会遇到版本不一致的导致的问题,在此记录一下,算作是对原文的补充吧。

1 踩坑记录

1.1 执行 webpack src/index.js --output dist/bundle.js 命令时报错 Unknown argument: --output

原因分析:可能跟操作系统有关,使用的终端是 Windows Powershell,使用 git 自带的终端也提示这个错误。
解决方法:把 --optput 改为 -o

1.2 webpack src/index.js -o dist/bundle.js 命令提示 Can't resolve 'src/index.js' in 'E:\02_learning\webpack'

原因分析:可能跟终端读取路径有关
解决方法:把命令中的 src/index.js 改为 ./src/index.js

1.3 构建得到的生成文件夹而不是文件

原因分析

  • ① 没有指定输出文件名;
  • ② webpack-cli版本太高。本人在时间过程中使用 yarn add webpack webpack-cli -D 命令安装时,webpack 和 webpack-cli 的版本分别如下 原来的 package.json
    毕竟是webpack4的教程,发现问题后改为4的版本,对应的 webpack-cli 改为3.3的版本,如下图
    更改后的 package.json
    解决方法
  • ① 在 webpack.config.js 配置文件中配置输出的文件路径和文件名
// webpack.config.js
module.exports = {
    entry: __dirname + "/src/index.js", // 入口文件
    output: {
        path: __dirname + "/dist", //打包后的文件存放的地方
        filename: "bundle.js" //打包后输出文件的文件名
    }
}
  • ② 降低 webpack-cli 版本

1.4 yarn 安装依赖时提示 An unexpected error occurred: "EPERM: operation not permitted, unlink 'XXX'

原因分析:当前的 binding.node 进程正在运行中,必须断开进程才能继续安装当前的依赖。
解决方法ctrl+c 结束正在进行的进程再执行安装.(参考:yarn add依赖的时候报错

1.5 使用 clean-webpack-plugin 插件在打包过程中,抛出 TypeError: CleanWebpackPlugin is not a constructor 的错误

原因分析clean-webpack-plugin 3.0 版本引入模块方式改变。
解决方法:将原来的引用方式

const CleanWebpackPlugin = require('clean-webpack-plugin') // 错误的写法

改为如下方式引用

const { CleanWebpackPlugin } = require('clean-webpack-plugin') // 正确的写法

参考:clean-webpack-plugin 3.0以上报错,TypeError: CleanWebpackPlugin is not a constructor
除此之外,webpack-merge 模块的引用也是使用这种方式,否则报同样的错误

// 正确的写法
const { merge } = require("webpack-merge") 

// 错误的写法
// const merge = require("webpack-merge")

1.6 使用 postcss-loaderautoprefixer 添加css前缀无效

原因分析:未配置 browserslist
解决方法:在 package.json 文件中添加 browserslist,如下

//package.json
{
    ...
    "browserslist": [
        "last 2 versions",
        "> 1%",
        "iOS 7",
        "last 3 iOS versions"
    ]
}

参考:记一次webpack配置postcss-loader下的autoprefixer无效的情况

1.7 使用 mini-css-extract-plugin 插件分离 css 文件

说明:原作者使用的是 extract-text-webpack-plugin 插件,经查阅发现现在 webpack 更推荐使用 mini-css-extract-plugin 插件,故自己照猫画虎实践了一番。
使用方法
安装模块:

yarn add mini-css-extract-plugin -D // 安装 mini-css-extract-plugin 插件

webpack.common.js 文件中进行配置

// webpack.common.js
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    // 其他配置省略
    ...
    module: {
        rules: [
            {
                test: /\.css$/, // 匹配以.css结尾的文件
                use: [
                    // 采用对象的形式配置loader
                    {
                        loader: MiniCssExtractPlugin.loader, // 使用mini-css-extract-plugin插件提取css
                    },
                    {
                        loader: "style-loader",
                    },
                    {
                        loader: "css-loader",
                    },
                    {
                        loader: "postcss-loader", // 使用postcss-loader。其配置也单独抽离到postcss.config.js文件中
                    },
                ],
            },
            // 其他配置省略
            ...
        ],
    },
    // 使用插件
    plugins: [
        // 其他配置省略
        ...
        new MiniCssExtractPlugin({
            filename: "css/[name].css",
        }), // 将css分离到/dist文件夹下独立为css文件
    ],
};

遇到问题:使用命令 yarn buildmini-css-extract-plugin 插件报错 Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ReferenceError: document is not defined
原因分析mini-css-extract-plugin 的 loader 与 stye-loader 冲突。
解决办法:注释掉 stye-loader,如下:

// webpack.common.js
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    // 其他配置省略
    ...
    module: {
        rules: [
            {
                test: /\.css$/, // 匹配以.css结尾的文件
                use: [
                    // 采用对象的形式配置loader
                    {
                        loader: MiniCssExtractPlugin.loader, // 使用mini-css-extract-plugin插件提取css
                    },
                    // {
                    //     loader: "style-loader", // 此loader与mini-css-extract-plugin插件冲突
                    // },
                    {
                        loader: "css-loader",
                    },
                    {
                        loader: "postcss-loader", // 使用postcss-loader。其配置也单独抽离到postcss.config.js文件中
                    },
                ],
            },
            // 其他配置省略
            ...
        ],
    },
    // 使用插件
    plugins: [
        // 其他配置省略
        ...
        new MiniCssExtractPlugin({
            filename: "css/[name].css",
        }), // 将css分离到/dist文件夹下独立为css文件
    ],
};

参考:Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ReferenceError: document is not defined

2 其他

原文作者在项目中使用的是 javascrpt 内置的 path 模块,在表示路径语法是 path.join( __dirname, "/dist"),本人全程使用的是 node.js 中的一个全局变量 __dirname,表示为 __dirname + "/dist"

3 总结

学到很多,受益匪浅,感谢原文作者大佬。
此文仅为记录个人在实践过程中遇到的问题,仅供参考。源码以提交 github,如有不正确或者不完整还望各位大佬斧正。