gulp和webpack 常用配置
首先 说说两者的区别
gulp:是工具链、构建工具,可以配合各种插件做js压缩,css压缩,less编译 替代手工实现自动化工作
(1)构建工具
(2)自动化
(3)用于:提高效率——能够优化前端工作流程,提高工作效率
(4)自动刷新页面,雪碧图,压缩css、js,编译less,检查语法等
(5)使用gulp可以配置你需要的插件,把以前需要手工做的事情让它帮你做了
webpack:是文件打包工具,可以把项目的各种js文、css文件等打包合并成一个或多个文件,主要用于模块化方案,预编译模块的方案
(1)打包工具
(2)模块化识别
(3)用于:编译模块代码方案
webpack常用配置
入口、出口配置
实现Webpack的打包最基本的就是配置好入口、出口,npm install webpack后在根目录创建webpack.config.js,代码如下:
const path = require('path');
module.exports = {
entry: { // 也可以直接写成entry: './src/index.js',默认入口就是main别名的index.js文件
main: './src/index.js' // 指把index.js设为入口文件并且设置别名为main
},
output: {
publicPath: '/', // 也可以不指定,默认为根目录
filename: '[name].js', // 这里[name]为占位符,即为变量,这里指复用入口文件的名字main
path: path.resolve(__dirname, 'dist') // 输出文件路径,必须是绝对路径,因此引用node的path模块
}
}
SourceMap配置
Webpack打包后如果文件出错会把错误指向打包后的文件中的某一行,而我们更需要知道是源文件哪一行出错,这时就需要配置source-map ,在moudule.exports加入以下配置项
mode: 'development', // 表示是开发环境,js文件不压缩,设为 production 生产环境 则会压缩
devtool: 'cheep-module-eval-source-map' // 开发环境的最佳配置
//devtool: 'cheep-module-source-map', 生产环境的source-map的最佳配置
devtool配置项中
cheep表示只具体到某一行不具体到某一列,且不检测loader的错误,有助于加快编译速度;
module 检测loader的错误,因此错误更全,方便快速查找错误 ;
eval表示soucemap的映射代码放到打包后的js文件中,而不是生成source.map.js文件;
souce-map指将错误映射到具体源文件上
热加载
当希望更改源文件时能自动重新打包文件有两种方法,第一种是在package.json里配置scripts
scripts: {
watch: 'webpack --watch'
}
即可实现效果,缺点是还是得手动刷新页面,不够智能化,因此推荐的事第二种方法,使用webpack-dev-server,npm install webpack-dev-server后,增加配置项:
devServer: {
contentBase: './dist', // 设置实时监听打包文件的目录
open: true, // 自动打开浏览器
port: 8080, // 端口
hot: true, // 启动模块热更新
hotOnly: true // 当模块热更新失败时浏览器也不自动刷新
// proxy 可以配置跨域
}
当需要更改css文件时页面不刷新,则需要设置hot,启动HotModuleReplacement:先引入webpack模块:const webpack = require('webpck'),再引入插件
plugins: [
new webpack.HotModuleReplacementPlugin()
]
之后在package.json里配置启动脚本
"scripts": {
"start": 'webpack-dev-server'
}
运行npm run start即可热加载网页
识别打包 js 文件,编译 es6
当打包 js文件时需要配置模块规则识别
module: {
rules: [{
test: /.js$/,
exclude: /node_modules/, // 忽略依赖插件目录的识别
loader: 'babel-loader' // 但需要编译es6语法时需要引入babel
}]
}
编译es6用的babel需要在根目录创建配置文件,.babelrc
{
presets: [
[
"@babel/preset-env", {
targets: {
chrome: "67" // 谷歌浏览器自动编译es6语法,因此不用babel转换
},
useBuiltIns: "usage" // 按需引入map、Promise等低版本浏览器没有的对象
}]
]
}
在IE低版本浏览器中是没有map、Promise等对象的,因此需要借用@babel/polyfill,npm install @babel/preset-env @babel/polyfill -D,之后在js文件中import "@babel/polyfill"即可,但有时我们开发开源组件时不希望polyfill污染全局变量,这是就需要另外一种配置方案,npm install -D @babel/plugin-transform-runtime @babel/runtime-corejs2 ,更改.babelrc配置为
{
"plugins": [
[
"@babel/plugin-transform-runtime", {
"corejs": 2, // 设为2才可以引入map等对象
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
识别打包图片、字体
npm install -D url-loader file-loader,两个loader均有将图片添加到dist目录里的功能。增加模块识别规则:
module: {
rules: [
{
test: /.(jpg|png|gif)$/,
use: {
loader: 'url-loader', // 功能跟file-loader差不多,区别是有转换base64的功能
options: {
name: '[name]_[hash].[ext]', // ext 是保留源文件后缀
outputPath: 'images/', // dist 目录下的images文件夹
limit: 10240 // 10kb以下的图片自动转换为base64编码插入到html中,其他正常生成图片
}
}
}, {
test: /.(eot/ttf/svg)$/,
use: {
loader: 'file-loader'
}
}
]
}
识别打包css、scss文件
npm i -D css-loader style-loader sass-loader postcss-loader ,添加模块识别规则:
module: {
rules: [
{
test: /.scss$/,
use: [ // 从下至上,从右到左执行loader
'style-loader', // 将 css 插入到style标签中
{
loader: 'css-loader', // 解析css文件,包括对应引用关系
options: {
importLoaders: 2
}
},
'sass-loader', // 解析sass,注意安装的时候要安装node-sass,sass-loader
'postcss-loader' // 添加css前缀,要有postcss.config.js配置上插件
]
},
{
test: /.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}
]
}
postcss.config.js代码如下
module.exports = {
plugins: [
require('autoprefixer')
]
}
生成 html
为了打包后自动生成html文件并引入打包的js文件,需要安装另一个插件,npm i -D html-webpack-plugin ,引入插件const HtmlWebpackPlugin = require('html-webpack-plugin'),增加插件配置项
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html' // 引用html模板,之后生成的html则会按照此模板生成并且自动引入打包后的js文件
})
]
打包前自动清除dist目录
打包前最好能自动清除dist 目录,防止冗余文件,npm i -D clean-webpack-plugin,引入插件const CleanWebpackPlugin = require('clean-webpack-plugn'),添加插件配置
plugins: [
new CleanWebpackPlugin(['dist'])
]
编译 React 代码文件
npm i --save react react-dom后即可编写React代码
import React, { Component } from 'react'
import ReactDom from 'react-dom'
class App extends Component {
render() {
return
}
}
ReactDom.render(
编译React代码则还需要npm i --save @babel/preset-react,并在.babelrc中的presets数组里增加一项"@babel/preset-react"即可正常编译
总结
webpack.config.js的完整代码如下:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = {
mode: 'development',
devtool: 'cheep-module-eval-source-map',
entry: {
main: './src/index.js',
},
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true,
hotOnly: true
},
module: {
rules: [{
test: /.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}, {
test: /.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
}, {
test: /.(eot|ttf|svg)$/,
use: {
loader: 'file-loader'
}
},
{
test: /.scss$/,
use: [ // 从下至上,从右到左执行loader
'style-loader', // 将 css 插入到style标签中
{
loader: 'css-loader', // 解析css文件,包括对应引用关系
options: {
importLoaders: 2
}
},
'sass-loader', // 解析sass,注意安装的时候要安装node-sass,sass-loader
'postcss-loader' // 添加css前缀,要有postcss.config.js配置上插件
]
},
{
test: /.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new CleanWebpackPlugin(['dist']),
new webpack.HotModuleReplacementPlugin()
],
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
最近花了两周的休息时间学习了webpack,能够可以编写自己项目所需要的配置文件,总体来说webpack是一种非常优秀的前端模块化的打包工具,非常值得花时间来研究学习。
什么是webpack,它的出现是为了解决什么问题?
webpack是一种可以融合各种前端新技术的平台,我们只需要简单地配置就可以使用jsx和typescript等一些前端新语法,得益于社区的发展,当我17年第一次接触webpack的时候,还都是英文文档,现在已经有很多优秀的中文入门教程和工程实践
我们开始配置我们的webpack.config.js
主要的api
1、entry(项目入口)
字符串,如entry:"./src/index.js"
数组形式: 如entry:[react, react-dom],可以把数组中的多个文件打包转换为一个chunk
对象形式,如果需要配置的是多页的应用,或者我们哟啊抽离出指定模块作为指定公共代码,需要采用这种形式,属性名是占位符[name]的值
如:
复制代码
entry: {
main:'./src/index2.js',
second: './src/index2.js',
vendor:['react', 'react-dom']
}
复制代码
2、output(出口文件)
会告诉webpack在哪里输出所创建的bundle.js以及如何命名
复制代码
out:{
path:path.join(__dirname, './dist'),
name: 'js/bundle-[name]-[hash].js,
chunkFilename: 'js/[name].chunk.js',
publicPath:'/dist/'
}
复制代码
3、module(模块的处理)
webpack只能处理js文件,浏览器也可能不识别一些最新的js语法,所以我们就要对传入的模块做一些预处理,这就涉及到了webpack的又一核心概念“loader”’
loader的作用和基本用法
webpack中,loader的配置主要在module.rules中进行,这是一个数组,每一个rule做了两件事
识别文件类型,来确定具体处理该数据的loader(Rule.test属性)
使用相关的loader对文件进行相关的操作转换(Rule.use属性)
比如我们想要处理react中的jsx语法
复制代码
module: {
rules:[{
test: /(.jsx|.js)/, //表示匹配规则,是一个正则表达式
use:{ //表示针对匹配文件将使用处理的loader
loader: "babel-loader",
options: {
presets: ["es2015", "react"]
}
}
}]
}
复制代码
常用的loader:
转换编译:script-loader, babel-loader,ts-loader,coffee-loader
处理样式:style-loader,css-loader,less-loader,sass-loader,postcss-loader
处理文件:raw--loader,url-loader,file-loader
处理数据:csv-loader,xml-loader
处理模板语言:html-loader,pug-loader,jade-loader,markdown-loader
清理和测试:mocha-loader,eslint-loader
此外还有许多loader,可以到loader文档里查询
4、plugin(loader不能做的处理都能交给plugin来做)
复制代码
const CleanWebpackPlugin = require("clean-webpack-plugin")
{
...
plugin:[
new webpack.DefinePlugin({
"process.env" : {
NODE_ENV: JSON.stringify("production")
}
}),
new CleanWebpackPlugin(["js"], {
root: __dirname + "/stu/",
verbose: true,
dry: false
})
]
}
复制代码
一种插件就是一种函数,通过传入不同的参数,可以实现不同的功能,webpack让人觉得难学的地方之一是哟啊自己封装plugins,对于我们大多数人来说,需要掌握的plugins并不是那么多,用的时候再查就可以
5、一些辅助开发的相关属性
devtool:打包后的代码和原始代码存在较大的差异,此选项控制是否生成以及如何生成sourcemap
devserver:通过配置devserver选项,可以开启一个本地服务器
watch:启用watch模式后,webpack将持续监听热河已经解析文件的更改,开发是开启会很方便
watchoption:用来定制watch模式的选项
performance:打包后命令行如何展示性能提示,如果超过某个大小是警告还是报错
对于webpack配置,要区分开发环境还是产环境
下面是文档的建议
我们为了避免重复应该提取公共代码
所以一般有这么几个文件
webpack.config.js
webpacl.dev.js
webpack.prod.js
webpack.common.js
此外还有单独配置babel的文件babelrc,webpack可以自动识别
GULP 的常用配置
复制代码
'use strict';
// 载入Gulp模块
var gulp = require('gulp');
var less = require('gulp-less');
var autoprefixer = require('gulp-autoprefixer');//兼容浏览器
var cssnano = require('gulp-cssnano');
var browserSync = require('browser-sync');//热刷新服务器
var reload = browserSync.reload;
// LESS编译 压缩
gulp.task('less', function() {
gulp.src(['src/css/.less', '!src/css/_.less'])
//less中使用@import url('_a.less')
.pipe(less())
.pipe(autoprefixer({
browsers: ['last 2 versions']
}))
.pipe(cssnano())
.pipe(gulp.dest('dist/css'))
.pipe(reload({
stream: true
}));
});
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var babel=require('gulp-babel')
var browserify=require('gulp-browserify')
// JS合并 压缩混淆
gulp.task('js', function() {
gulp.src('src/js/*.js')
.pipe(concat('app.js'))
.pipe(babel()) //使用es6,加此项
.pipe(browserify({ //浏览器中兼容require等,使用async时使用
insertGlobals: true
}))
.pipe(uglify())
.pipe(gulp.dest('dist/js'))
.pipe(reload({
stream: true
}));
});
// 图片复制
gulp.task('pic', function() {
gulp.src('src/pic/.')
.pipe(gulp.dest('dist/pic'))
.pipe(reload({
stream: true
}));
})
var htmlmin = require('gulp-htmlmin');
// HTML
gulp.task('html', function() {
gulp.src('src/*.html')
.pipe(htmlmin({
collapseWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeComments: true,
removeEmptyAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
}))
.pipe(gulp.dest('dist'))
.pipe(reload({
stream: true
}));
});
gulp.task('serve', ['less', 'js', 'pic', 'html'], function() {
browserSync({
notify: false,
port: 3003,
server: {
baseDir: ['dist']
}
},function (err, bs) {
console.log(bs.options.getIn(["urls", "local"]));
});
gulp.watch('src/css/.less', ['less']);
gulp.watch('src/js/.js', ['js']);
gulp.watch('src/pic/.', ['pic']);
gulp.watch('src/*.html', ['html']);
});
gulp.task('default',['serve']);
基本功能
起本地服务
启用热更新
启用代理
编译静态文件
包括html文件 将其打包到dist文件夹
包括less文件 将其打包到dist文件夹 并进行压缩
包括js文件 将其打包到dist文件夹 并进行压缩 配置了sourcemap
设置了default任务
package.json
{
"name": "g-ex",
"version": "1.0.0",
"description": "a gulp template",
"main": "index.js",
"scripts": {
"test": "echo "Error: no test specified" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^7.1.4",
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.0",
"gulp": "^3.9.1",
"gulp-babel": "^7.0.0",
"gulp-clean-css": "^3.9.0",
"gulp-concat": "^2.6.1",
"gulp-connect": "^5.0.0",
"gulp-less": "^3.3.2",
"gulp-postcss": "^7.0.0",
"gulp-rename": "^1.2.2",
"gulp-sourcemaps": "^2.6.1",
"gulp-uglify": "^3.0.0",
"http-proxy-middleware": "^0.17.4",
"uglify-es": "^3.1.3"
}
}
gulpfile.js
var gulp = require('gulp');
var connect = require('gulp-connect');
var babel = require('gulp-babel');
var sourcemaps = require('gulp-sourcemaps');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var less = require('gulp-less');
var cleanCss = require('gulp-clean-css');
var autoprefixer = require('autoprefixer');
var postCss = require('gulp-postcss');
var proxy = require('http-proxy-middleware');
// 起服务
gulp.task('connect', function() {
connect.server({
root: 'dist',
livereload: true,
port: 9000,
middleware: function(connect, opt) {
return [
proxy('/printbox', {
target: 'http://172.20.8.30:8891',
changeOrigin:true
})
]
}
});
});
// html文件
gulp.task('html', function() {
gulp.src('./src/*.html')
.pipe(connect.reload())
.pipe(gulp.dest('./dist'));
});
// css文件
gulp.task('less', ['html'], function() {
gulp.src('./src/css/*.less')
.pipe(less())
.pipe(postCss([autoprefixer({browsers: ['last 2 versions']})]))
.pipe(gulp.dest('./dist/css'))
.pipe(cleanCss())
.pipe(rename({extname: '.min.css'}))
.pipe(connect.reload())
.pipe(gulp.dest('./dist/css/min'))
});
// js文件
gulp.task('js',['html'] , function () {
gulp.src('./src/js/*.js')
.pipe(sourcemaps.init())
.pipe(babel({
presets: ['env']
}))
.pipe(gulp.dest('./dist/js'))
.pipe(uglify())
.pipe(rename({extname: '.min.js'}))
.pipe(sourcemaps.write())
.pipe(connect.reload())
.pipe(gulp.dest('./dist/js/min'))
});
// 图片
gulp.task('img', function () {
gulp.src('./src/img/.')
.pipe(connect.reload())
.pipe(gulp.dest('./dist'));
})
// 监控
gulp.task('watch', function() {
gulp.watch(['./src/*.html'], ['html']);
gulp.watch(['./src/js/*.js'], ['js']);
gulp.watch(['./src/css/*.less'], ['less']);
});
// 默认任务
gulp.task('default', ['connect', 'watch', 'js', 'less']);

浙公网安备 33010602011771号