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

正文前先吐槽下, 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 文件
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容