大前端学习--使用node、grunt、gulp实现前端项目工程化(含视频讲解)
【摘要】
使用node、grunt、gulp实现前端项目工程化
我把熬夜录制的讲解视频也放在下面了,本宝宝是不是很贴心😄😄😄😄😄😄😄😄😄😄😄😄
1. 概述脚手架实现的过程,并使用Node...
使用node、grunt、gulp实现前端项目工程化
我把熬夜录制的讲解视频也放在下面了,本宝宝是不是很贴心😄😄😄😄😄😄😄😄😄😄😄😄
1. 概述脚手架实现的过程,并使用NodeJS完成一个自定义的小型脚手架工具
脚手架的实现过程就是在启动脚手架之后,自动地去询问一些预设问题,通过回答的结果结合一些模板文件,生成项目的结构。
使用NodeJS开发一个小型的脚手架工具:
-
用
yarn init
初始化一个空文件夹:jal-pro
-
在
package.json
中添加bin
属性指定脚手架的命令入口文件为cli.js
{ "name": "jal-pro", "version": "1.0.0", "main": "index.js", "bin": "cli.js", "license": "MIT", "dependencies": { "ejs": "^3.1.3", "inquirer": "^7.1.0" } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
-
编写
cli.js
#!/usr/bin/env node // Node CLI 应用入口文件必须要有这样的文件头 // 如果Linux 或者 Mac 系统下,还需要修改此文件权限为755: chmod 755 cli.js // 脚手架工作过程: // 1. 通过命令行交互询问用户问题 // 2. 根据用户回答的结果生成文件 const path = require('path') const fs = require('fs') const inquirer = require('inquirer') // 发起命令行交互询问 const ejs = require('ejs') // 模板引擎 inquirer.prompt([ { type: 'input', name: 'name', message: 'Project name?' } ]).then(answer => { console.log(answer) // 模板目录 const tempDir = path.join(__dirname, 'templates') // 目标目录 const destDir = process.cwd() // 将模板下的文件全部转换到目标目录 fs.readdir(tempDir, (err, files) => { if (err) throw err files.forEach(file => { // 通过模板引擎渲染文件 ejs.renderFile(path.join(tempDir, file), answer, (err, result) => { if(err) throw err // 将结果写入到目标目录 fs.writeFileSync(path.join(destDir, file), result) }) }) }) })
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
-
命令行中修改
cli.js
文件权限:chmod 755 cli.js
-
模板文件
templates/index.html
如下:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title><%= name %></title> </head> <body> </body> </html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
-
执行命令将该cli程序link到全局:
yarn link
-
然后再其他文件夹中执行:
jal-pro
命令,就可以根据模板自动化创建文件了
2. 尝试使用Gulp完成项目的自动化构建
视频演示地址:
gulp讲解
gulpfile.js
// 实现这个项目的构建任务
const {src, dest, parallel, series, watch} = require('gulp')
const del = require('del')
const browserSync = require('browser-sync')
const bs = browserSync.create()
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const {sass, babel, swig, imagemin, ghPages, eslint, sassLint} = plugins
const config = {
production: false,
port: 2080,
open: false
}
const isMini = () => config.production
const calculateConfig = () => {
const argv = process.argv
console.log(argv)
const task = argv[2]
if(task === 'serve') {
config.production = false
config.open = argv.includes('--open')
config.port = argv.includes('--port') && parseInt(argv[argv.indexOf('--port')+1], 10) || 2080
config.root = 'temp'
} else if (task === 'build') {
config.production = argv.includes('--production') || argv.includes('--prod')
} else if (task === 'start') {
config.open = argv.includes('--open')
config.port = argv.includes('--port') && parseInt(argv[argv.indexOf('--port')+1], 10) || 2080
config.root = 'dist'
} else if (task === 'deploy') {
config.production = true
config.branch = argv.includes('--branch') && argv[argv.indexOf('--branch')+1] || 'gh-pages'
}
console.log('config', config)
}
calculateConfig()
const data = {
menus: [
{
name: 'Home',
icon: 'aperture',
link: 'index.html'
},
{
name: 'Features',
link: 'features.html'
},
{
name: 'About',
link: 'about.html'
},
{
name: 'Contact',
link: '#',
children: [
{
name: 'Twitter',
link: 'https://twitter.com/w_zce'
},
{
name: 'About',
link: 'https://weibo.com/zceme'
},
{
name: 'divider'
},
{
name: 'About',
link: 'https://github.com/zce'
}
]
}
],
pkg: require('./package.json'),
date: new Date()
}
// Clean the dist & temp files.
const clean = () => {
return del(['dist', 'temp'])
}
const myeslint = () => {
return src(['src/assets/scripts/*.js'])
.pipe(eslint({
rules: {
'my-custom-rule': 1,
'strict': 2
},
globals: [
'jQuery',
'$'
],
envs: [
'browser'
]
}))
.pipe(eslint.format())
}
const mysasslint = () => {
return src(['src/assets/styles/*.scss'])
.pipe(sassLint())
.pipe(sassLint.format())
.pipe(sassLint.failOnError())
}
const style = () => {
return src('src/assets/styles/*.scss', { base: 'src' })
.pipe(sass({ outputStyle: 'expanded' }))
.pipe(dest('temp'))
.pipe(bs.reload({stream: true}))
}
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('temp'))
.pipe(bs.reload({stream: true}))
}
const page = () => {
return src('src/**/*.html', { base: 'src' })
.pipe(swig({ data, defaults: { cache: false } })) // 防止模板缓存导致页面不能及时更新
.pipe(dest('temp'))
.pipe(bs.reload({ stream: true }))
}
const image = () => {
return src('src/assets/images/**', {base: 'src'})
.pipe(imagemin())
.pipe(dest('dist'))
}
const font = () => {
return src('src/assets/fonts/**', {base: 'src'})
.pipe(imagemin())
.pipe(dest('dist'))
}
const extra = () => {
return src('public/**', {base: 'public'})
.pipe(dest('dist'))
}
const browser = () => {
watch('src/assets/styles/*.scss', style)
watch('src/assets/scripts/*.js', script)
watch('src/*.html', page)
watch([
'src/assets/images/**',
'src/assets/fonts/**',
'public/**'
], bs.reload)
bs.init({
notify: false,
port: config.port,
open: config.open,
// files: 'temp/**',
server: {
baseDir: [config.root, 'src', 'public'], // 按顺序查找
routes: {
'/node_modules': 'node_modules'
}
}
})
}
const useref = () => {
return src('temp/*.html', { base: 'temp' })
.pipe(plugins.useref({ searchPath: ['temp', '.'] }))
.pipe(plugins.if(/\.js$/, plugins.uglify()))
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.html$/, plugins.htmlmin({
collapseWhitespace: isMini(),
minifyCSS: isMini(),
minifyJS: isMini()
})))
.pipe(dest('dist'))
}
const mydeploy = () => {
return src('dist/**/*')
.pipe(ghPages([{
branch: config.branch
}]))
}
const lint = parallel(myeslint, mysasslint)
const compile = parallel(style, script, page)
const serve = series(compile, browser)
const build = series(
clean,
parallel(
series(compile, useref),
image,
font,
extra
)
)
const start = series(build, browser)
const deploy = series(build, mydeploy)
module.exports = {
clean,
compile,
build,
serve,
start,
deploy,
lint
}
/*
演示命令:
yarn clean
yarn lint
yarn compile
yarn serve
yarn serve --port 5210 --open
yarn build
yarn build --production
yarn start --port 5210 --open
yarn deploy --branch gh-pages
*/
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
package.json的部分内容
{
"scripts": {
"clean": "gulp clean",
"compile": "gulp compile",
"serve": "gulp serve",
"build": "gulp build",
"start": "gulp start",
"lint": "gulp lint",
"deploy": "gulp deploy --production"
},
"devDependencies": {
"@babel/core": "^7.10.2",
"@babel/preset-env": "^7.10.2",
"browser-sync": "^2.26.7",
"del": "^5.1.0",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-clean-css": "^4.3.0",
"gulp-eslint": "^6.0.0",
"gulp-gh-pages": "^0.5.4",
"gulp-htmlmin": "^5.0.1",
"gulp-if": "^3.0.0",
"gulp-imagemin": "^7.1.0",
"gulp-load-plugins": "^2.0.3",
"gulp-sass": "^4.1.0",
"gulp-sass-lint": "^1.4.0",
"gulp-swig": "^0.9.1",
"gulp-uglify": "^3.0.2",
"gulp-useref": "^4.0.1"
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
3. 使用Grunt完成项目的自动化构建
视频演示地址:
grunt自动化构建
gruntfile.js
const sass = require('sass')
const fs = require('fs')
const useref = require('useref')
const loadGruntTasks = require('load-grunt-tasks')
const browserSync = require('browser-sync')
const bs = browserSync.create()
const data = {
menus: [
{
name: 'Home',
icon: 'aperture',
link: 'index.html'
},
{
name: 'Features',
link: 'features.html'
},
{
name: 'About',
link: 'about.html'
},
{
name: 'Contact',
link: '#',
children: [
{
name: 'Twitter',
link: 'https://twitter.com/w_zce'
},
{
name: 'About',
link: 'https://weibo.com/zceme'
},
{
name: 'divider'
},
{
name: 'About',
link: 'https://github.com/zce'
}
]
}
],
pkg: require('./package.json'),
date: new Date()
}
module.exports = grunt => {
grunt.initConfig({
clean: ['dist/**'],
sass: {
options: {
sourceMap: true,
implementation: sass, // implementation指定在grunt-sass中使用哪个模块对sass进行编译,我们使用npm中的sass
},
main: {
files: {
'dist/assets/styles/main.css': 'src/assets/styles/main.scss'
}
}
},
babel: {
options: {
presets: ['@babel/preset-env'],
sourceMap: true
},
main: {
files: {
'dist/assets/scripts/main.js': 'src/assets/scripts/main.js'
}
}
},
web_swig: {
options: {
swigOptions: {
cache: false
},
getData: function (tpl) {
return data;
}
},
main: {
expand: true,
cwd: 'src/',
src: "**/*.html",
dest: "dist/"
},
},
uglify: {
production: {
files: [{
expand: true,
cwd: 'dist/',
src: ['assets/scripts/*.js'],
dest: 'dist/',
}]
},
dev: {}
},
cssmin: {
production: {
files: [{
expand: true,
cwd: 'dist/',
src: ['assets/styles/*.css'],
dest: 'dist/',
}]
},
dev: {}
},
htmlmin: {
production: {
options: {
removeComments: true,
collapseWhitespace: true
},
files: [{
expand: true,
cwd: 'dist/',
src: ['**/*.html'],
dest: 'dist/'
}]
},
dev: {}
},
image: {
production: {
options: {
optipng: false,
pngquant: true,
zopflipng: true,
jpegRecompress: false,
mozjpeg: true,
gifsicle: true,
svgo: true
},
files: [{
expand: true,
cwd: 'dist/',
src: ['assets/fonts/*', 'assets/images/*'],
dest: 'dist/'
}]
},
dev: {}
},
eslint: {
options: {
rulePaths: ['src/assets/scripts/']
},
target: ['src/assets/scripts/main.js']
},
sasslint: {
main: {
options: {
configFile: 'config/.sass-lint.yml',
rulePaths: ['src/assets/scripts/']
},
target: ['src/assets/styles/main.scss']
}
},
copy: {
main: {
files: [{
expand: true,
cwd: 'public/',
src: ['**'],
dest: 'dist/'
},
{
expand: true,
cwd: 'src',
src: ['assets/fonts/*'],
dest: 'dist/'
},
{
expand: true,
cwd: 'src',
src: ['assets/images/*'],
dest: 'dist/'
}
]}
},
watch: {
js: {
files: ['src/js/*.js'],
tasks: ['babel', 'bs-reload']
},
css: {
files: ['src/scss/*.scss'],
tasks: ['sass', 'bs-reload']
},
html: {
files: ['src/**/*.html'],
tasks: ['web_swig', 'bs-reload']
}
},
ghDeploy: {
options: {
repository: 'https://github.com/2604150210/pages-boilerplate-grunt.git',
deployPath: 'dist',
branch: grunt.option('branch') || 'gh-pages',
message: 'Auto deplyment ' + grunt.template.today()
},
}
})
grunt.registerTask("jal-useref", function () {
const done = this.async()
const cwd = 'dist/'
const htmls = ['index.html', 'about.html']
htmls.forEach((html, index) => {
const inputHtml = fs.readFileSync(cwd + html, "utf8")
const [code, result] = useref(inputHtml)
for (let type in result) {
const dests = Object.keys(result[type])
dests.forEach(dest => {
const src = result[type][dest].assets
let read
const files = src.map(file => {
read = cwd + file
if(file[0] === '/') {
read = file.substr(1)
}
return fs.readFileSync(read)
})
fs.writeFile(cwd + dest, files.join(''), (err) => {
if (err) {
return console.error(err);
}
console.log(`${cwd + dest}数据写入${read}成功!`);
})
})
}
fs.writeFile(cwd + html, code, (err) => {
if (err) {
return console.error(err);
}
console.log(`${cwd + html}重写成功!`);
if(index === htmls.length - 1) {
done()
}
})
})
});
// grunt.loadNpmTasks('grunt-sass')
// 启动browserSync
grunt.registerTask("bs", function () {
const done = this.async();
bs.init({
notify: false,
port: grunt.option('port') || 2080,
open: grunt.option('open'),
// files: 'temp/**',
server: {
baseDir: ['dist', 'src', 'public'], // 按顺序查找
routes: {
'/node_modules': 'node_modules'
}
}
}, function (err, bs) {
done();
});
});
grunt.registerTask("bs-reload", function () {
bs.reload()
});
// 获取命令行参数是否含有production或者prod,判断是开发模式还是生产模式
const mode = (grunt.option('production') || grunt.option('prod')) ? 'production': 'development'
loadGruntTasks(grunt) // 自动加载所有的grunt插件中的任务
// 根据命令行参数判断是否需要压缩
grunt.registerTask('mini:production', ['image', 'uglify', 'cssmin', 'htmlmin'])
grunt.registerTask('mini:development', [])
grunt.registerTask('lint', ['sasslint', 'eslint'])
grunt.registerTask('compile', ['sass', 'babel', 'web_swig'])
grunt.registerTask('serve', ['compile', 'bs', 'watch'])
grunt.registerTask('build', ['clean', 'compile', 'copy', 'jal-useref', `mini:${mode}`])
grunt.registerTask('start', ['clean', 'compile', 'copy', 'jal-useref', 'mini:production', 'bs', 'watch'])
grunt.registerTask('deploy', ['clean', 'compile', 'copy', 'jal-useref', 'mini:production', 'ghDeploy'])
}
/*
演示命令:
yarn clean
yarn lint
yarn compile
yarn serve
yarn serve --port=5210 --open
yarn build
yarn build --production
yarn start --port=5210 --open
yarn deploy --branch=gh-pages
*/
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
package.json的部分内容
{
"scripts": {
"clean": "grunt clean",
"compile": "grunt compile",
"lint": "grunt lint",
"serve": "grunt serve",
"build": "grunt build",
"start": "grunt start",
"deploy": "grunt deploy --production"
},
"devDependencies": {
"@babel/core": "^7.10.2",
"@babel/preset-env": "^7.10.2",
"browser-sync": "^2.26.7",
"concat": "^1.0.3",
"grunt": "^1.1.0",
"grunt-babel": "^8.0.0",
"grunt-browser-sync": "^2.2.0",
"grunt-contrib-clean": "^2.0.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-csslint": "^2.0.0",
"grunt-contrib-cssmin": "^3.0.0",
"grunt-contrib-htmlmin": "^3.1.0",
"grunt-contrib-jshint": "^2.1.0",
"grunt-contrib-uglify": "^4.0.1",
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^23.0.0",
"grunt-gh-deploy": "^0.1.3",
"grunt-html-build": "^0.7.1",
"grunt-html-template": "^0.1.6",
"grunt-image": "^6.3.0",
"grunt-sass": "^3.1.0",
"grunt-sass-lint": "^0.2.4",
"grunt-scss-lint": "^0.5.0",
"grunt-web-swig": "^0.3.1",
"load-grunt-tasks": "^5.1.0",
"sass": "^1.26.8",
"useref": "^1.4.3"
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
文章来源: blog.csdn.net,作者:爱玲姐姐,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/jal517486222/article/details/106948869
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)