gulp 的使用(六):利用 webpack 流实现模块化

1,239 阅读5分钟

这是我参与更文挑战的第19天,活动详情查看: 更文挑战

前言

在上一篇文章 gulp 的使用(五):处理图片 里,介绍了如何使用 gulp 处理图片。

在这篇文章里,将介绍在使用 gulp 的同时,如何去使用 webpack 去处理模块化(当然也可以利用 webpack 做其他事情)。

没错,gulp 与 webpack 皆可兼得,我全都要!!!

image.png

但是要注意,虽然可以这样做,但我并不建议,如果项目需要模块化,不要用 gulp,请直接使用 webpack !!!

使用 webpack 流

在第一篇文章 gulp 的使用(一):起步 里,我就已经说过了 gulp 自身无法处理模块化,它只是一个基于流的自动化构建工具,如果要处理模块化,它可以利用 webpack 来处理模块化部分。

webpack-stream 其实就是一个 webpack,不过它与普通的 webpack 不同,它是以流的形式存在,与 gulp 集成。

安装 webpack-stream

npm i -D webpack-stream

在项目根目录里创建 webpack 配置文件 webpack.config.js,写上以下基础代码。

console.log('利用了 webpack !!!')

module.exports = {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map',
  module: {
    rules: [
      
    ]
  },
  resolve: {
    alias: {

    }
  },
}

在 gulpfile.js 引入 webpack-stream 和 webpack.config.js,并且修改 js 任务。

const webpack = require('webpack-stream')
const webpackConfig = require("./webpack.config.js")

...

function js() {
  return src(['src/js/**/*.js'])
    .pipe(changed('dist/js/**/'))
    .pipe(webpack(webpackConfig))
    .pipe(plumber())
    .pipe(uglify())
    .pipe(dest('dist/js'))
}

我们再在 src/js 目录创建 utils.js,写上以下测试代码。

export default {
  test() {
    console.log('测试模块化成功!!!')
  }
}

在 index.js 使用 es6 的 import 引入 utils.js。

function print() {
  console.log('测试')
}

print()

import utils from './utils'

utils.test()

运行 npm run dev,打开网站,打开控制台。

image.png

咦?为什么没有值?不单止是 utils.test() 的内容没有输出来,index.js 自身的 console.log 的内容也没有输出来。

我们再看看终端,webpack 的配置确实是被加载了。

image.png

别急,我们再看看 dist/js 目录,可以发现原本应该命名为 index.js 的文件,被打包成了以一串随机字符串为文件名的文件,而我们的 index.html 引用的是以 index.js 为文件名的文件。

image.png

而且你会发现无论你的项目里有多少个 js,打包出来的始终只有一个 js,那是因为 webpack 在默认配置里使用的是单页面模式去打包。

熟悉 webpack 的小伙伴可能会说,这是因为我没有配置 webpack 的 entry 和 output,的确我没有进行配置,这也是一种方法,也有另一种方法可以解决,各有优缺点,下面逐一介绍。

如何开发多页面

方法1:配置 webpack 的 entry 和 output

我们只要在 webpack.config.js 配置上 entry 和 output 就可以了。

console.log('利用了 webpack !!!')

const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map',
  entry: {
    index: path.resolve(__dirname, './src/js/index.js'),
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, './dist'),
  },
  module: {
    rules: [
      
    ]
  },
  resolve: {
    alias: {

    }
  },
}

不过,你有没有发现如果这样做,以后页面每需要引入一个 js,都需要终端当前的 dev 服务,再在 webpack 里写好新加入的 entry,然后再启动 dev 服务测试。

也许你会想到可以用以下代码进行监听 webpack 配置,每当 webpack 配置被修改,都会去执行 js 任务。

watch('webpack.config.js', series(js))

不过经过实际试验,这是行不通的,webpack 配置只有第一次任务执行才会被加载。

那么该怎么办呢?我们可以使用另一种方法

方法2:使用 vinyl-named 插件

vinyl-named 插件可以解决多页面开发的问题。

安装 vinyl-named

npm i -D vinyl-named

配置 gulpfile.js,引入 vinyl-named。

const Path = require('path')

...

const named = require('vinyl-named')

...

function js() {
  return src(['src/js/**/*.js'])
    .pipe(changed('dist/js/**/'))
    .pipe(named(function (file) {
      return file.relative.slice(0, -Path.extname(file.path).length)
    }))
    .pipe(webpack(webpackConfig))
    .pipe(plumber())
    .pipe(uglify())
    .pipe(dest('dist/js'))
}

运行 npm run dev,当我们在 src/js 里新增 js 时,你会发现 dist/js 目录里会自动生成对应的 js 文件。

注意,不要直接写上 named(),这样写的话,如果 js 有一个目录 aa,aa 目录里面有一个 aa.js,打包出来的 aa.js 是位于 dist/js/aa.js,而不是在 dist/js/aa/aa.js,少了一个 aa 目录

function js() {
  return src(['src/js/**/*.js'])
    .pipe(changed('dist/js/**/'))
    /*.pipe(named(function (file) {
      return file.relative.slice(0, -path.extname(file.path).length)
    })) */
    .pipe(named()) // 不要这样写
    .pipe(webpack(webpackConfig))
    .pipe(plumber())
    .pipe(uglify())
    .pipe(dest('dist/js'))
}

当然,这种方法也有自身的缺点,你有没有发现作为模块的 utils.js 也被打包出来了,实际上 utils.js 并不需要打包出来,index.js 已经包含了需要的 utils.js 代码。如果你用的是 webpack 的 entry-output 方法,你会发现 utils.js 是不会打包出来。

请注意此项目将使用 vinyl-named 插件来处理多页面。

结语

webpack-stream 只是其中一种方式,还有 browserify 插件可以令 gulp 项目实现模块化,不过这种方式我没用过,听说有坑。

要弄模块化,我还是比较建议直接使用 webpack,不要使用这种以 gulp 为主,webpack 为辅的方式。因为这种开发方式很不伦不类,核心问题在于 webpack 构建打包出来的东西,gulp 怎么在任务去感知并进行关联。上面的 js 打包问题是因为有 vinyl-named 插件的存在得以解决,但是当你的项目越来越大,需要使用 webpack 的代码分离进行优化的时候,你会遇到很棘手的 html 与 js 的如何关联问题。如果我们都用 webpack 去进行管理 html,进行如何去关联 js,那么为什么我们不一开始就直接使用 webpack 去构建项目呢?

完整项目

2021.8.30,我重新整理了一遍项目,已放到 gitee 上,大家可以 clone 下来直接用,代码的提交记录顺序和我这个系列文章教程顺序是一致的,大家看到哪一篇文章时,就回滚代码到哪一个版本,这样看项目代码会更直观。

gitee 库链接:gitee.com/only1zhuo/g…

image.png

“gulp 的使用”系列文章