这是我参与更文挑战的第19天,活动详情查看: 更文挑战
前言
在上一篇文章 gulp 的使用(五):处理图片 里,介绍了如何使用 gulp 处理图片。
在这篇文章里,将介绍在使用 gulp 的同时,如何去使用 webpack 去处理模块化(当然也可以利用 webpack 做其他事情)。
没错,gulp 与 webpack 皆可兼得,我全都要!!!
但是要注意,虽然可以这样做,但我并不建议,如果项目需要模块化,不要用 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
,打开网站,打开控制台。
咦?为什么没有值?不单止是 utils.test() 的内容没有输出来,index.js 自身的 console.log 的内容也没有输出来。
我们再看看终端,webpack 的配置确实是被加载了。
别急,我们再看看 dist/js 目录,可以发现原本应该命名为 index.js 的文件,被打包成了以一串随机字符串为文件名的文件,而我们的 index.html 引用的是以 index.js 为文件名的文件。
而且你会发现无论你的项目里有多少个 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…