Webpack4 入门到带你打包一个简单单页应用项目

1,833 阅读7分钟
正文前先吐槽下, webpack 对新手入门真的有点不友好,各个版本在配置上都有或多或少的差异,导致在对照各种教程学习的过程中免不了掉进各种坑里,所以写这篇文章旨在简单明了的解释说明 webpack 的各种常用配置,希望能让新人接触 webpack 时少走些弯路。

一、搭建项目

1. 我们先新建一个项目 project 并用 npm 命令初始化项目(一路回车)
npm init
2. 安装 webpack 与 webpack-cli ( 4 版本需要cli才能执行命令)
npm install --save-dev webpack webpack-cli
3. 新建 src 文件夹,存放我们要打包的源码,默认输入文件是 index.js,所以我们在 src 下新建一个index.js文件
document.write("测试文件打包")
4. 执行命令,便能实现最简单的 “ 项目打包 ”
webpack
5. 输入命令打包完成后会生成一个 dist 文件夹,里面就存放着我们需要打包的文件,这样一个最简单的 webpack 打包流程到此完工,接下来就要进入正片了。

二、命令部分

1. webpack 默认打包命令

第一部分我们使用过 webpack 命令进行打包,其实这个命令是不完整的,细心的小伙伴会发现执行时控制台会有提示该命令有 production(生产) 与 development (开发)模式,完整命令如下:

// 两个命令有和不同就请大家自己手动试一下,这里就不赘述了
webpack --mode production
webpack --mode development
2. webpack 根据配置文件打包命令

实际中我们打包项目根据需要会有各种配置,因此常用的是根据配置文件来进行打包,所以我们在项目根目录下新建一个 webpack.conf.js 文件来保存配置信息

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
  }
}

稍后会对这个文件进行详细讲解,这里先执行命令看是否能成功进行按需打包

// webpack.conf.js 可根据自己需要命名 打包方法是 --config 配置文件路径
webpack --mode production --config ./webpack.conf.js

打包成功会发现在 dist 下现在生成的文件名已经由默认变成了我们指定的 bundle.js

3. 改写 npm 命令

由于 webpack 指令比较长,输入时很不方便,我们有个小技巧可以简化这一步骤,就是对项目的 package.json 文件中的 script 部分进行修改

  "scripts": {
    "dev": "webpack --mode development --config ./webpack.conf.js",
    "build": "webpack --mode production --config ./webpack.conf.js"
  },

然后执行以下命令就相当于执行了我们所设置对应的完整 webpack 命令

npm run dev
npm run build

三、配置部分

这部分会涉及很多内容,包括一些常用插件,我会逐步带大家完善 webpack.conf.js 文件,但基本点到即止,详细配置还需参考官方文档自行配置

1. 关于文件路径

配置文件会有许多关于文件路径的设置,这方面一不小心就会出现问题,这里推荐采以下方法对相对路径进行处理

const path = require('path')
// 此方法会根据传入的相对路径自动转化为绝对路径,确保路径的正确
path.resolve(__dirname, '文件的相对路径')
  • webpack.conf.js 配置例子
const path = require('path')

module.exports = {
  entry: path.resolve(__dirname, './src/index.js'),
  output: {
    filename: 'main.js',
  }
}

2. 配置文件结构总览

主要包含以下 4 个部分 entry:配置文件入口 output:配置输出文件名与路径 plugins:配置引入的插件 module: 配置文件转换的规则

const path = require('path')

module.exports = {
  // 输入路径配置
  entry: path.resolve(__dirname, './src/index.js'),
  // 输出文件名和路径配置
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, './dist')
  },
  // 引入插件配置
  plugins: [],
  // 文件类型转换配置
  module: {}
}

对文件结构有个总体了解后我们接下来就开始逐步完善

3. 完善 js 文件输出路径

通常项目我们有一个专门的 js 文件夹进行存放 js 文件,并且为了区分版本,我们有时会使用 hash 进行区分( hash 值仅当源码文件被修改时才会更新)

  • webpack.conf.js 配置例子
const path = require('path')

module.exports = {
  // 输入路径配置
  entry: path.resolve(__dirname, './src/index.js'),
  // 输出文件名和路径配置
  output: {
    // [name] 可自行配置,参考文档
    // [hash:4] 使用 hash 取前 4 位
    filename: 'js/[name]-[hash:4].js',
    path: path.resolve(__dirname, './dist')
  },
  // 引入插件配置
  plugins: [],
  // 文件类型转换配置
  module: {}
}

4. 使用插件,引入 html 模板

目前为止,我们打包的都只有 js 文件,作为前端项目,怎么可以没有 html 文件呢,为了实现打包自动生成 html 文件,我们开始引入我们的第一个插件

  • 安装插件 html-webpack-plugin
npm install --save-dev html-webpack-plugin
  • 在项目根目录下新建 index.html 文件作为模板,供配置文件引入
  • webpack.conf.js 配置例子
const path = require('path')
const htmlWebpackPlugins = require('html-webpack-plugin')

module.exports = {
  // 输入路径配置
  entry: path.resolve(__dirname, './src/index.js'),
  // 输出文件名和路径配置
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, './dist')
  },
  // 引入插件配置
  plugins: [
    new htmlWebpackPlugins({
      // 输出文件名
      filename: 'index.html',
      // 所引用模板文件位置
      template: 'index.html',
      // js 文件插入的位置
      inject: 'body'
    }),
  ],
  // 文件类型转换配置
  module: {}
}

现在尝试下打包,基本的 html 和 js 文件就有了,但这远远还不够,我们还需要对 html 与 js 的相关配置进行处理,为了使项目更完整,我们还要新建一些文件。

5. 完善项目目录

  • 在 src 目录下新建 components 文件夹,分别新建 html, js, css 文件 ,下面以 scroll 组件为例

scroll.html

<div class="scroll">
  <p>scroll</p>
</div>

scroll.js

// import tpl from './scroll.html'
// import './scroll.css'

function scroll () {
  return {
    name: 'scroll',
    // tpl: tpl
  }
}

export default scroll

scroll.css

.scroll {
  height: 500px;
  width: 500px;
  background: red;
}

.scroll p {
  display: flex;
}
  • 文件新建完还需在我们的入口文件 index.js 中引入
import Scroll from './components/scroll'

const App = function () {
  var dom = document.getElementById('app')
  var scroll = new Scroll()
  dom.innerHTML = scroll.tpl
  document.write(scroll.name)
}

new App()
  • 最后修改下我们的 index.html 模板,新增 app 模块
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

这时尝试打包,便可把我们新增的 scroll.js 引入进来了,但是这时我们 tpl 也就是 scroll.html 还处于注释状态,想要正确引入,还需添加其他插件

6. 使用插件,配对 .html 类型文件(之后的 .css, .png等其他类型的文件引入方法与此类似)

  • 安装插件 html-loader
npm install --save-dev html-loader
  • 修改我们的 webpack.conf.js ,在 module 中完善我们的文件转换配置
const path = require('path')
const htmlWebpackPlugins = require('html-webpack-plugin')

module.exports = {
  entry: path.resolve(__dirname, './src/index.js'),
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, './dist')
  },
  plugins: [
    new htmlWebpackPlugins({
      filename: 'index.html',
      template: 'index.html',
      inject: 'body'
    }),
  ],
  // 文件类型转换配置
  module: {
    rules: [
      {
        // 正则匹配 html 文件
        test: /\.html$/,
        use: [
          {
            // 引入 html 文件加载插件
            loader: 'html-loader'
          }
        ]
      }
    ]
  }
}
  • 修改下我们的 scroll.js 文件,将之前的注释取消
import tpl from './scroll.html'
// import './scroll.css'

function scroll () {
  return {
    name: 'scroll',
    tpl: tpl
  }
}

export default scroll
  • OK ~ 尝试打包,现在应该就能正确的把 scroll.thml 的内容也打包进去了,成功之后我们就只剩 .css 类型文件没有打包进去,那么继续我们的配置

7. 使用插件,配对 .css 类型文件

  • 安装插件 css-loader 与 style-loader
npm install --save-dev css-loader style-loader
  • 修改我们的 webpack.conf.js, 添加匹配规则
const path = require('path')
const htmlWebpackPlugins = require('html-webpack-plugin')

module.exports = {
  // 输入路径配置
  entry: path.resolve(__dirname, './src/index.js'),
  // 输出文件名和路径配置
  output: {
    filename: 'js/main.js',
    path: path.resolve(__dirname, './dist')
  },
  // 引入插件配置
  plugins: [
    new htmlWebpackPlugins({
      filename: 'index.html',
      template: 'index.html',
      inject: 'body'
    }),
  ],
  // 文件类型转换配置
  module: {
    rules: [
      {
        // 正则匹配 html 文件
        test: /\.html$/,
        use: [
          {
            // 引入 html 文件加载插件
            loader: 'html-loader'
          }
        ]
      },
      {
        // 正则匹配 css 文件
        test: /\.css$/,
        use: [
          {
            // 引入 style 文件加载插件
            loader: 'style-loader'
          },
          {
            // 引入 css 文件加载插件
            loader: 'css-loader'
          }
        ]
      },
    ]
  }
}
  • 修改下我们的 scroll.js 文件,将之前 css 的注释也取消
import tpl from './scroll.html'
import './scroll.css'

function scroll () {
  return {
    name: 'scroll',
    tpl: tpl
  }
}

export default scroll
  • 进行打包,成功后自己看看效果,这样一个简单 webpack 打包流程就已经走完了

至此,相信你对 webpack 的基本工作流程有了一定的了解,不过这只是刚刚开始,上面的例子离我们实际工作中的应用还有一段距离,例如 js 没有实现 ES6 到 ES5 的转换,css 样式不是以一个文件的形式插入,遇到引入图片文件时上面的配置会出现错误,还有许多我们常用的框架文件如 vue 等文件类型要打包时都是需要重新配置的,本文就不再对配置进行深究,只是简单多介绍一些常用插件供大家学习了解

8. 插件介绍

  • babel-loader , babel-preset-latest , babel-core 用于ES6 到 ES5 的转换
  • autoprefixer , postcss-loader 用于 css 根据配置的浏览器版本进行自动添加前缀
  • less, less-loader 用于试别 less 类型样式文件(sass等同理,引入相应插件进行配置)
  • url-loader 用于加载图片类型文件
  • image-webpack-loader 用于优化图片文件加载
  • mini-css-extract-plugin 用于分离压缩 css 文件