webpack入门学习以及踩坑记录

前言

webpack是一个现代化的前端打包工具,用于构建和打包Web应用程序的静态资源。通过将多个模块和文件打包成一个或者多个最终可部署文件,可以提高应用程序的性能和加载速度。它有以下功能:

  • 模块打包:webpack支持将应用程序拆分成模块,并通过模块之间的依赖关系进行组织。它可以处理javascript、CSS和图片等等,将它们打包成最终的静态资源文件;
  • 资源优化:一个web应用程序包含了很多文件,功能模块也很复杂,这时就要压缩优化文件,拆分模块,实现按需加载。而Webpack提供了多个的优化功能,比如压缩、代码分离、文件合并、Tree Shaking(消除未使用的代码)等等,可以解决以上问题;
  • 开发环境支持:提供很多开发环境下的实用工具,比如自动刷新、热模块替换(HMR)、Source Map(调试工具)、DevServer(配置临时服务器)等等,可以高效开发和调试应用程序;
  • 扩展性和生态系统:可以通过插件(plugin)和加载器(loader)来自定义和扩展功能。

在了解了webpack的作用以及功能之后,下面就让我们来学习webpack的使用!
webpack中文文档:https://webpack.docschina.org/
在学习的过程要多看文档,多看文档,多看文档!文档可以解决很多问题,可以解决你的一些疑惑。

安装

在使用之前,首先安装webpack

npm i webpack webpack-cli  webpack-dev-server -D

webpack :前端打包工具。
webpack-clii:与 Webpack 配合使用的命令行工具。它提供了一些命令,用于在命令行界面中与 Webpack 进行交互。通过 Webpack-cli,你可以运行 Webpack 的构建命令、配置文件,执行不同的构建任务,管理和控制 Webpack 的行为。
webpack-dev-server:是一个基于 Express 的开发服务器,用于在开发环境中快速搭建一个本地服务器。它提供了文件监听、自动刷新、热模块替换(HMR)等功能。

核心概念

入口(entry)

用来定义web应用程序的入口文件,webpack会从入口文件开始寻找哪些依赖是入口文件需要的。
我们需要新建一个webpack配置文件 webpack.config.js,在这个文件中就可以自定义我们的入口文件。

const path = require('path')
module.exports = {
  entry: './src/index.js',   //  入口文件路径,一个入口文件
  //如果是多个入口文件,就用对象包裹起来
  /*
  entry:{
    a: './src/index.js',
    b: './src/app.js',
  }
  */
};

注意:这里用的是node.js模块导入导出方式(CommonJs规范),这是因为Webpack是基于node.js运行的工具。还有这里涉及到的文件路径,都是按照node.js模块寻址规则来的。所以出入口文件路径一定要处理好!!!

输出(output)

从字面上意思就可以看出,这个属性是定义出口文件,也就是打包之后文件的输出路径。
如果你的文件目录结构复杂,一定要注意输出文件的路径!

module.exports = {
  // 入口文件
  entry: './src/index.js',
  // 输出文件
  output: {
    path: path.resolve(__dirname, 'dist'),  //  输出文件路径
    filename: 'bundle.js',   //  打包后生成js文件的文件名
  },
  }
entry、output实践

在了解了入口、输出文件之后,就让我们来实践一下吧!来验证一下理论知识。
首先我的文件目录结构是这样的:
在这里插入图片描述
a.js

export default function add(a, b) {
  console.log(a + b);
}

index.js

import add from './app/a'
add(1, 2)

在准备好这些之后,还要配置一下package.json文件,配置好运行webpack打包命令。
在这里插入图片描述
在执行npm run build 命令之后,控制台会输出一下内容,同时也会生成对应bundle.js文件,但是注意看,控制台出现了一个警告,意思是说模式还没有设置,并且给出了解决方案:设置mode为development(开发环境模式)或者production(生产环境模式)。所以只要在配置文件里加上mode属性即可。这样就不会有这个警告出现了。
在这里插入图片描述
在这里插入图片描述

加载器(loader)

从上面的例子可以看出,webpack可以打包js文件,那如果我们想处理css文件,又或者是stylus、less、sass、hbs文件呢?这时候就可以loader加载器进行处理。
比如这里是使用webpack加载css文件,首先安装相对应的loader,

npm install --save-dev style-loader css-loader

之后就可以将loader引入到你的配置文件中:

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,  //  正则匹配css文件
        use: ["style-loader", "css-loader"],  //  这里要注意loader引入的顺序,先style-loader后			css-loader
      },
    ],
  },
};

编写好css文件,然后在入口文件index.js引入css文件,记得在html文件也要引入打包生成的bundle.js文件,因为无论是js文件还是css文件还是stylus文件,最后打包了都汇集在一个文件里面。
在这里插入图片描述
效果图:
在这里插入图片描述
又比如你想用webpack加载stylus文件,首先先安装对应的loader,

npm install --save-dev stylus-loader // 如果你没有安装style-loader css-loader这两个,记得要安装上

之后就可以将loader引入到你的配置文件中:

module.exports = {
  module: {
    rules: [
    {
        test: /\.styl$/i,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
          {
            loader: "stylus-loader",
          }
        ]
      },
    ],
  },
};

这里要注意loader的加载顺序,使用方法跟上面加载css文件差不多的,一步步照着来就行。
也可以用webpack来管理图片,这里就不展开来说了。

插件(plugin)

loader用来处理某些特殊的文件或模块,插件可以用于处理更广的任务。webpack提供的插件接口非常强大,使插件可以完成各种任务。

loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。

想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。

// webpack.common.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

module.exports = {
  entry: {
    app: './app/main.js'
  },
  plugins: [
    // new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './index.html',
    }),
    new BundleAnalyzerPlugin()
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, '../dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.hbs$/,
        loader: "handlebars-loader"
      },
      {
        test: /\.styl$/i,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
          {
            loader: "stylus-loader",
          }
        ]
      },
    ]
  }
};

上面代码是根据我的项目来创建的一个配置文件
html-webpack-plugin插件可以创建一个html文件,如果你不设置任何参数,那么它就会生成最简单的html文件,比如像这样

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>webpack App</title>
  </head>
  <body>
    <script src="index_bundle.js"></script>
  </body>
</html>

但如果你想以某个html文件为模板生成一个新的html文件,那就需要添加template参数

 new HtmlWebpackPlugin({
      template: './index.html',
    }),

clean-webpack-plugin插件用来清除一些不必要的文件,每次打包都会更新dist文件夹。在打包的过程中如果你发现的图片、css文件等文件消失不见了的时候,请看一下有没有使用了这个插件,因为有可能被清理掉了

webpack-bundle-analyzer插件可以用来分析各个模块之间的依赖关系,以便于后面代码分离、压缩代码等操作

在这里插入图片描述

开发工具 webpack-dev-server

是一个基于 Express 的开发服务器,用于在开发环境中快速搭建一个本地服务器。它提供了文件监听、自动刷新、热模块替换(HMR)等功能。
它的配置:

module.exports =  {
  // 开发环境下的临时服务器
  devServer: {
    static: 'public',  // 静态资源路径
    hot: true,  // 是否开启热更新
    host: 'localhost',
    port: 8080,
    open: true,  //  是否自动打开,设置为true,会自动打开html页面
  },
};

在开发环境使用webpack-dev-server的时候,webpack-dev-server 在编译之后不会写入到任何输出文件,而是将 bundle 文件保留在内存中,然后将它们 serve 到 server 中,就好像它们是挂载在 server 根路径上的真实文件一样。如果你的页面希望在其他不同路径中找到 bundle 文件,可以通过 dev server 配置中的 publicPath 选项进行修改。

代码调试 source map

当 webpack 打包源代码时,可能会很难追踪到 error(错误)和 warning(警告)在源代码中的原始位置。例如,如果将三个源文件(a.jsb.jsc.js)打包到一个 bundle(bundle.js)中,而其中一个源文件包含错误,那么堆栈跟踪就会直接指向到 bundle.js。但是你可能需要准确地知道错误来自于哪个源文件,所以这种提示这通常不会提供太多帮助。

为了更容易地追踪 error 和 warning,JavaScript 提供了 source map 功能,可以将编译后的代码映射回原始源代码。source map 会直接告诉你错误来源于哪一个源代码。


module.exports =  {
  devtool: 'inline-source-map',
};

开发生产环境双配置

开发环境和生产环境使用的加载器和插件肯定会有所不同,下面对配置文件进行优化,实现相同配置优化,把开发环境和生产环境独有的配置项独立出来。
比如这个是开发生产环境都使用同一个配置文件:

// 使用node.js的模块导入和导出方式

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
  mode: 'development',

  // 生产环境下
  entry: './src/index.js',
  // 生产环境下
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    // assetModuleFilename: 'images/[hash][ext][query]'
  },
  // 开发环境下 保留源码
  devtool: 'inline-source-map',
  // 开发环境下的临时服务器
  devServer: {
    proxy: { // proxy URLs to backend development server
      '/': 'http://localhost:8080'
    },
    static: path.join(__dirname, '/dist/'),
    compress: true, 
    historyApiFallback: true, 
    hot: true,
    open: true
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.styl$/,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
          {
            loader: "stylus-loader",
          }
        ]
      },
      {
        test: /\.hbs$/,
        loader: "handlebars-loader",
      },
      {
        test: /\.(png|jpg|gif)$/,
        type: 'asset/resource'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "Webpack",
      template: "index.html"
    }),
    new CleanWebpackPlugin()
  ]

}

所以需要把原来的webpack.config.js配置文件拆分三个或者四个文件:
(下面的划分是根据我的项目来的)

  • webpack.common.js 公共环境的配置文件
  • webpack.dev.js 开发环境下的配置文件
  • webpack.prod.js 生产环境下的配置文件
  • webpack.parts.js 各个配置零件的配置文件

webpack.common.js 公共环境的配置文件

// webpack.common.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

module.exports = {
  entry: {
    app: './app/main.js'
  },
  plugins: [
    // new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './index.html',  //  注意路径
    }),
    new BundleAnalyzerPlugin()
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, '../dist')   //  注意路径
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.hbs$/,
        loader: "handlebars-loader"
      },
      {
        test: /\.styl$/i,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
          {
            loader: "stylus-loader",
          }
        ]
      },
    ]
  }
};

webpack.dev.js 开发环境下的配置文件

// webpack.dev.js
const { merge } = require('webpack-merge');
const path = require('path')
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
  // 开发环境下 保留源码  inline-source-map
  devtool: 'eval',
  // 开发环境下的临时服务器
  devServer: {
    static: 'dist',
    hot: true,
    host: 'localhost',
    port: 8080,
    open: true,
  },
});

webpack.prod.js 生产环境下的配置文件

// webpack.prod.js
const common = require('./webpack.common');
const {merge} = require('webpack-merge');
// const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');

module.exports = merge(common,{
  mode: "production", //development|production
  output: {
    filename: '[name].[hash:7].js'
  },
  // 排除某些依赖包不被打包,只在运行时从CDN引入
  externals: {
    // jquery: 'jQuery',
    // wangeditor: 'wangEditor'
  },
  plugins:[
    // new UglifyjsWebpackPlugin()
  ],
  // 将公共模块单独打包,使得它们可以被缓存和复用
  optimization: {
    splitChunks: {
      cacheGroups: {  // 用于配置缓存组的对象
        commons: {
          test: /[\\/]node_modules[\\/]/,  // 匹配node_modules目录下的模块
          name: 'vendors',  //  提取的公共模块的文件名
          chunks: 'all',  // 对所有的代码进行优化
        },
      },
    },
  },
})

在进行划分了之后,在package.json文件中新增三条快捷命令

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

在划分了三个文件之后,涉及到文件路径的地方一定要多加注意,因为很容易就会出错,项目目录结构越复杂就越容易出错!!!

报错记录

Invaild options object.Dev Server has been initalized…

在这里插入图片描述
这个报错的意思是某个属性找不到,错误的原因是我用的时候webpack 5+版本,而我用了webpack 4+的但webpack 5+已经弃用了的属性。

生产环境下打包没有在相对应的dist文件夹里面生成js和html文件

我的项目目录结构:
在这里插入图片描述
原因分析:经过分析是输出文件路径的问题
在这里插入图片描述
我当时的输出文件路径是path: path.resolve(__dirname, 'dist'),而webpack.dev.js等配置文件是在config文件夹里面的,这样的话输出文件是在config文件夹下的dist下,但明显不是,打包都的输出文件要在与Index.html同目录的dist文件夹,所以需要修改路径为path: path.resolve(__dirname, '../dist')

webpack-dev-server在编译后找不到css文件和图片

在这里插入图片描述

原因分析:
首先在开发环境使用webpack-dev-server的时候,webpack-dev-server 在编译之后不会写入到任何输出文件,而是将 bundle 文件保留在内存中,然后将它们 serve 到 server 中,就好像它们是挂载在 server 根路径上的真实文件一样;

其次我的开发环境配置里面可访问的资源路径是public,而输出文件路径是dist,当编译之后,服务器就会以/dist/为根目录,访问里面的资源,而dist文件里有没有css和image文件,所以访问不到资源。
所以我把可访问的静态资源路径和输出文件路径都设置一样,最后就可以正常访问了。

Refused to apply style from ‘http://localhost:8080/css/index.css’ because its MIME type (‘text/html’) is not a supported stylesheet MIME type, and strict MIME checking is enabled.

在这里插入图片描述
原因分析:我在html文件引入了css文件,而我的css文件又存放在输出文件里,由于我又使用clean-webpack-plugin插件,每次打包的时候都会更新dist文件夹里的内容,所以把css文件给清理掉,导致无法引入css文件。所以我把这个插件给注释掉,重新生成一份css文件就可以了。

最后

这是我入门学习webpack之后整理的一些学习笔记和踩的一些坑记录下来,如有不对的地方或者需改善的地方,欢迎大家批评指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_北冥有鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值