webpack使用教程(二)

一、webpack安装(4.0)

  1. webpack webpack-cli -D 安装前npm init -y 初始化 本地开发环境依赖安装

二、webpack可以进行0配置

  1. 打包工具 --- 输出后的结果(js模块化)
  2. 打包(支持我们的js的模块化)

三、手动配置webpack 文件名 webpack.confifg.js

  1. 配置入口以及打包出口
    entry: './src/index.js',//打包时的入口文件
    output: {
    	filename: "bundle.js",//打包后的文件名
    	path: path.resolve(__dirname, 'build'),//打包后文件的路径  必须是绝对路径  __dirname当前项目的根目录 物理路径
    	publicPath:"./"  //统一配置  给打包后的文件添加路径  可以是域名以及路径  可以按模块单独配置
    }      
    
  2. 手动修改webpack.config.js文件名
    scripts:{
        "build": "webpack --config webpack-config.my.js"  //直接执行npm run build
    }
    
  3. 安装服务的开发依赖
    • npm install webpack-dev-server -D 不会真实的打包 但会进行内存中的打包,把文件写在内存中 会生成一个访问地址
    • 运行命令 npx webpack-dev-server
    devServer: {//开发环境下服务器的配置
    	port: 3000,//修改端口号 默认8080
    	progress: true,//内存打包时进度条
    	contentBase: './build',//以dist文件为静态目录打开
    	compress:true//启动压缩
    
    },
    
  4. 配置通过index.html模板页面把打包生成的js塞到模板中并打包之后塞到打包build目录下 支持HTML
    • 应用插件并安装插件npm install html-webpack-plugin -D
    let HtmlWebpackPlugin = require('html-webpack-plugin')
    plugins: [//数组 放着所有的webpack插件
    	new HtmlWebpackPlugin({
    		template: "./src/index.html",//打包模板路径
    		filename: "index.html",//打包后的文件,默认index
    		minify: {//压缩打包后的html页面
    			removeAttributeQuotes: true,// 移除属性的双引号
    			collapseWhitespace: true,//打包后的html折叠
    		},
    		hash:true,//打包的js添加哈希戳
    
    	})
    ]
    output: {
    	filename: "bundle.[hash:8].js",//打包后的文件名 加上hash让每次打包都生成不同的文件以避免缓存8代表值显示8位
    	path: path.resolve(__dirname, 'build'),//打包后文件的路径  必须是绝对路径  __dirname当前项目的根目录 物理路径
    },
    
  5. css按模块的方式引入
    • css模块基本配置
    module: {//配置模块
    	rules: [//配置规则  css-loader处理css文件 负责解析@import这种语法
    		//style-loader它是把css插入到head的标签  loader的特点:希望单一
    		/*
    		*   loader的用法
    		*   1.字符串只用一个loader  多个loadeer需要用数组  默认从右向左执行
    		*   2.loader还可以写成对象  默认从下往上执行
    		* */
    		{
    			test: /\.css$/,//检测css文件正则
    			//use:'css-loader',字符串
    			//use:['style-loader','css-loader'],数组
    			use:[
    				{
    					loader: "style-loader",
    					options: {
    						insertAt:'top',//使模板里面的样式优先级最高
    					}
    				},
    				'css-loader'
    			]
    		},
    		{
    			//可以处理less文件   sass stylus node-sass sass-loader stylus stylus-loader
    			test: /\.less$/,//检测css文件正则
    			//use:'css-loader',字符串
    			//use:['style-loader','css-loader'],数组
    			use:[
    				{
    					loader: "style-loader",
    					options: {
    						insertAt:'top',//使模板里面的样式优先级最高
    					}
    				},
    				'css-loader',//解析路径以及@import
    				'less-loader'//把less转换成css
    			]
    		}
    	]
    }
    
    • npm install mini-css-extract-plugin -D 抽离css样式插件
    plugins: [//数组 放着所有的webpack插件
    	new HtmlWebpackPlugin({
    		template: "./src/index.html",//打包模板路径
    		filename: "index.html",//打包后的文件,默认index
    		minify: {//压缩打包后的html页面
    			removeAttributeQuotes: true,// 移除属性的双引号
    			collapseWhitespace: true,//打包后的html折叠
    		},
    		hash:true,//打包的时候加上哈希戳
    	}),
    	new MiniCssExtractPlugin({ //抽离css样式文件
    		filename:'css/main.css',//文件名   设置打包后的文件输出路径以及文件名
    
    	})
    ],
    module: {//配置模块
    	rules: [//配置规则  css-loader处理css文件 负责解析@import这种语法
    		//style-loader它是把css插入到head的标签  loader的特点:希望单一
    		/*
    		*   loader的用法
    		*   1.字符串只用一个loader  多个loadeer需要用数组  默认从右向左执行
    		*   2.loader还可以写成对象  默认从下往上执行
    		* */
    		{
    			test: /\.css$/,//检测css文件正则
    			//use:'css-loader',字符串
    			//use:['style-loader','css-loader'],数组
    			use:[
    				// {
    				// 	loader: "style-loader",
    				// 	options: {
    				// 		insertAt:'top',//使模板里面的样式优先级最高
    				// 	}
    				// },
    				MiniCssExtractPlugin.loader,//创建link标签引入
    				'css-loader'
    			]
    		},
    		{
    			//可以处理less文件   sass stylus node-sass sass-loader stylus stylus-loader
    			test: /\.less$/,//检测css文件正则
    			//use:'css-loader',字符串
    			//use:['style-loader','css-loader'],数组
    			use:[
    				// {
    				// 	loader: "style-loader",
    				// 	options: {
    				// 		insertAt:'top',//使模板里面的样式优先级最高
    				// 	}
    				// },
    				MiniCssExtractPlugin.loader,
    				'css-loader',//解析路径以及@import
    				'less-loader'//把less转换成css
    			]
    		}
    	]
    }
    
    • 安装autoprefixer自动添加浏览器前缀 postcss-loader 处理autoprefixer的loader
    • npm install postcss-loader autoprefixer -D 自动添加浏览器前缀以及样式
    module: {//配置模块
    	rules: [//配置规则  css-loader处理css文件 负责解析@import这种语法
    		//style-loader它是把css插入到head的标签  loader的特点:希望单一
    		/*
    		*   loader的用法
    		*   1.字符串只用一个loader  多个loadeer需要用数组  默认从右向左执行
    		*   2.loader还可以写成对象  默认从下往上执行
    		* */
    		{
    			test: /\.css$/,//检测css文件正则
    			//use:'css-loader',字符串
    			//use:['style-loader','css-loader'],数组
    			use:[
    				// {
    				// 	loader: "style-loader",
    				// 	options: {
    				// 		insertAt:'top',//使模板里面的样式优先级最高
    				// 	}
    				// },
    				MiniCssExtractPlugin.loader,//创建link标签引入
    				'css-loader',
    				'postcss-loader'//解析css之前添加
    			]
    		},
    		{
    			//可以处理less文件   sass stylus node-sass sass-loader stylus stylus-loader
    			test: /\.less$/,//检测css文件正则
    			//use:'css-loader',字符串
    			//use:['style-loader','css-loader'],数组
    			use:[
    				// {
    				// 	loader: "style-loader",
    				// 	options: {
    				// 		insertAt:'top',//使模板里面的样式优先级最高
    				// 	}
    				// },
    				MiniCssExtractPlugin.loader,
    				'css-loader',//解析路径以及@import
    				'postcss-loader',//解析css之前添加
    				'less-loader'//把less转换成css
    			]
    		}
    	]
    }
    //并创建postcss.config.js文件
    module.exports = {
        plugins:[require('autoprefixer')]//放用到的插件
    }
    
    • npm install optimize-css-assets-webpack-plugin 压缩静态资源 使用了这插件覆盖了之前js的压缩,也就是js不会压缩必须使用插件去压缩uglifyjs-webpack-plugin
    optimization: {//优化项   生产环境下生效  开发环境下不生效
    	minimizer:[
    		new OptimizeCSSAssetsPlugin(),
    		new UglifyJsPlugin({
    			cache: true,//缓存
    			parallel: true,//支持并发打包
    			sourceMap:true//源码映射
    		})
    	]
    },
    
  6. babel-loader es6语法转换为es5语法的loader @babel/core babel核心模块 @babel/preset-env 高级语法转为低级语法 npm install @babel/plugin-proposal-class-properties -D 支持es7类的用法
{
	test:/\.js$/,
	use:{
		loader:'babel-loader',
		options: {//用babel-loader需要把es6语法转换为es5语法
			presets:[//预设
				'@babel/preset-env'
			],
			plugins:[
				["@babel/plugin-proposal-decorators", { "legacy": true }],
				["@babel/plugin-proposal-class-properties", { "loose" : true }]
			]
		}

	}
},
  1. 处理js语法以及校验
    • npm install --save-dev @babel/plugin-transform-runtime 开发环境下
    • npm install --save @babel/runtime 生产环境下
    {
    	test:/\.js$/,
        use:{
    		loader:'babel-loader',
    		options: {//用babel-loader需要把es6语法转换为es5语法
    			presets:[
    				'@babel/preset-env'
    			],
    			plugins:[
    				["@babel/plugin-proposal-decorators", { "legacy": true }],
                    ["@babel/plugin-proposal-class-properties", { "loose" : true }],
    						"@babel/plugin-transform-runtime"
    					]
    				}
    	},
    	include:path.resolve(__dirname,'src'),//校验src下面的js
    	exclude:/node_modules/,//排除modules下面js
    },
    
  2. 实例上面的方法默认不会帮解析 @babel/polyfill require('@babel/polyfill')
  3. eslint校验js语法 npm install eslint eslint-loader
{
				test: /\.js$/,
				use: {
					loader: 'eslint-loader',
					options:{
						enforce:'pre'//previous  post 后面  强制在js转换之前执行校验语法
					}
				}
			},
  1. webpack中第三方模块的使用
    • npm install jquery
    第一种
    //通过内联loader把jquery暴露出全局的$   npm install expose-loader
    import $ from 'expose-loader?$!jquery'  
    //expose-loader  //暴露全的loader  内联的loader pre 前面执行的loader 普通loader  后者post  loader
    console.log(window.$)
    rules:
    第二种
    {
    	test:require.resolve('jquery'),
    	use:'expose-loader?$'
    },
    import $ from 'jquery'
    第三种  在每个模块中注入$
    let webpack = require('webpack') 通过webpack插件
    new Webpack.ProvidePlugin({  在每个模块中注入$
    		$:'jquery'
    }) 
    第四种   引入不打包 
    cdn引入 import $ from 'jquery'
    //不属于plugin插件配置
    external:{//引用一个库,但是又不想让webpack打包
    	jquery:'$'
    },
    
  2. webpack打包图片
    • 在js中创建图片来引入 必须以模块的形式引入 require或者import引入
    //file-loader  npm install file-loader 默认会在内部生产一张图片到build目录下,并把生产的图片的名字返回来    
    import logo from './a01.jpg' //把图片引入,返回的结果是一个新的图片地址
    console.log(logo);
    let image = new Image();
    image.src = logo; //就是一个字符串
    document.body.appendChild(image)
    
    {
    	test: /\.(png|jpg|gif)$/,
    	use:'file-loader'
    
    },
    
    • 在css引入背景图片
    可以直接普通的去使用(background:url('./logo.png'))
    
    • html中通过img使用 npm install html-withimg-loader html-withimg-loader编译html页面中的img编译图片路径
    {
    			test: /\.html$/,
    			use:'html-withimg-loader'
    
    		},
    
    • 转换为base64 url-loader npm install url-loader
    {
    			test: /\.(png|jpg|gif)$/,
    			//做一个限制  当我们的图片 小于多少k的时候  用base64来转换  不然使用file-loader展示真实的图片
    			use:{
    				loader: 'url-loader',
    				options: {
    					limit:200*1024,//限制图片的大小
    					outputPath:'/img/',//设置打包之后文件分类目录
    					publicPath:"http://baidu.com" //配置图片的路径 可以在output里面统一配置,也可以单独配置
    				}
    			}
    
    		},
    

四、打包多页面应用

1.基本配置以及应用

let path = require('path')
let HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
	 mode:'development',
	    //多入口
	    entry: {
		    home: './src/index.js',
		    other: './src/other.js'
	    },
	    output:{
		    filename: '[name].js',
		    path: path.resolve(__dirname,'bundle')
	    },
	    plugins: [ //new 两次
	    	new HtmlWebpackPlugin({
			    template: "./index.html",
			    filename: "home.html",
			    chunks: ['home'] //代码块
	    	}),
	    	new HtmlWebpackPlugin({
		    	template: "./index.html",
		    	filename: "other.html",
		    	chunks: ['other','home'] //代码块
	    	}),
    	]
}
  1. sourceMap的使用
    //1. 源码映射  会单独生成一个sourcemap文件,出错了 辉表示当前报错的列和行  大切全
	//devtool: "source-map",//增加映射文件 可以帮助我们调试源代码
	//2. 不会产生单独的文件  但是会显示行和列
	//devtool: "eval-source-map",
	//3.不会产生列  但是是一个单独的映射文件
	//devtool: "cheap-module-source-map",//产生后可以保留起来调试
	//4. 不会产生文件 集成在打包后的文件中  不会产生列
	devtool: "cheap-module-eval-source-map",
  1. watch的用法(监控代码变化 并且实时编译)
watch: true,
watchOptions: {//监控选项
	poll: 1000,//每秒监控  问1000要不要更新
	aggregateTimeout:500,//防抖  我一直输入代码  500毫秒打包一次
	ignored: /node_modules/,//不需要进行监控文件
},
  1. webpack小插件
1. cleanWebpackPlugin  //删除文件
new CleanWebpackPlugin('./bundle') //删除那个文件 再产生
2. copyWebpackPlugin  //拷贝文件
new CopyWebpackPlugin([  
    {
        from:'doc',   //从哪里copy到哪里去
        to:'./'
    }

]) //删除那个文件 再产生
3. bannerPlugin   内置模块  需要引入webpack模块

new webpack.BannerPlugin('make 2019')
  1. 跨域问题
        //第二种  我们前端只想单纯的模拟数据
		before(app){ //提供的方法 钩子
			app.get('/user',(req,res) => {
				res.json({
					name:"不不不11"
				})
			});
		},
		//第一种
		proxy: {
			'/api': {
				target: "http://localhost:3000",//配置一个代理  以api开头的都去道理服务上面找
				pathRewrite: {
					'/api': '' //替换api为空
				}
			},
		},
		
		服务端启动webpack
		//npm install webpack-dev-middleware -D  中间件  在服务端启动webpack

        let webpack = require('webpack')
        let middle = require('webpack-dev-middleware')
        let config = require('./webpack.config.js')
        let compiler = webpack(config) //webpack经过处理

        app.use(middle(compiler))
  1. resolve属性配置
resolve: { //解析 第三方包
		modules: [path.resolve('node_modules')],  //当前目录下查找  不回去上级目录下查找
		// alias: {//别名
		// 	bootstrap:'bootstrap/dist/css/bootstrap.css'
		// },
		//mainFields:  ['style','main'],  //主入口  先找style style找不到再找main
		//mainFiles: [] , //入口文件的名字  默认找index.js
		extensions: ['.css','.js','.json']
	}
  1. 定义环境变量
new webpack.DefinePlugin({//定义插件
			DEV:JSON.stringify('dev')
		})
  1. 区分不同环境
npm install webpack-merge -D  合并
创建开发环境 webpack.dev.js 
let merge = require('webpack-merge')
let base = require('./webpack.base.js')  //开发环境以及生成环境共用的配置
module.exports = merge(base,{
	mode:"development",
	devServer:{  //生成环境配置

	}
})

创建生成环境webpack.pro.js
let merge = require('webpack-merge')
let base = require('./webpack.base.js')  //开发环境以及生成环境共用的配置
module.exports = merge(base,{ //开发环境配置
	mode:"production",
	optimization:{

	}

})

五、webpack优化

  1. noParse:/jquery/, //不去解析jquery依赖库
module: {
		noParse:/jquery/, //不去解析jquery依赖库
		rules: [
			{
				test:/.\.js$/,
				exclude:/node_nodule/,//排除node_modules中的js
				include:path.resolve('src'), //包含在src的js
				use: {
					loader: "babel-loader",
					options: {
						presets:[
							"@babel/preset-env",
							"@babel/preset-react"
						]
					}
				}
			}
		]
	}
  1. IgnorePlugin 插件 webpack内置插件 忽略插件
new Webpack.IgnorePlugin(/\.\/locale/,/moment/),  //只引入moment中中文语言包  忽略其他的
  1. dllPlugin 动态链接库 抽离第三方库 不需要打包 先独立的进行打包第三方库 我们打包好的文件之后直接进入打包好的第三方库文件
创建webpack.config.react.js
let path = require('path')
let Webpack = require('webpack')
module.exports = {
	mode: "development",
	entry: ['react','react-dom'],  //要打包的第三方包名
	// entry: './src/test.js',
	output: {
		filename: '_dll_[name].js', //产生的文件名
		path: path.resolve(__dirname,'dist'),
		//library: 'ab',//打包后的文件返回值赋值给a
		library: '_dll_[name]',//打包后的文件返回值赋值给a   变量名与产生的文件名一致
		//libraryTarget:'commonjs' //模块输出 umd模式 var

	},
	plugins: [
		new Webpack.DllPlugin({
			name:"_dll_[name]",//name === library
			path:path.resolve(__dirname,'dist','manifest.json')  //产生清单的路径
		})

	]
}

webpack.config.js
new Webpack.DllReferencePlugin({
	manifest: path.resolve(__dirname,'dist','manifest.json')
})
  1. 多线程打包 happypack 可以实现多线程来打包 第三方插件
webpack.config.js
new Happypack({  //调用下面的loader去打包
	id:'js',
	use: [{
		loader: "babel-loader",
		options: {
			presets:[
				"@babel/preset-env",
				"@babel/preset-react"
			]
		}
	}]
})
		
rules: [
	{
		test:/.\.js$/,
		// use: {
		// 	loader: "babel-loader",
		// 	options: {
		// 		presets:[
		// 			"@babel/preset-env",
		// 			"@babel/preset-react"
		// 		]
		// 	}
		// }
		use:'Happypack/loader?id=js'  //使用happypack/loader进行打包  并标识是js
	}
]
  1. 多页面打包时抽取公共代码
webpack.config.js
optimization: {
		splitChunks: { //分割代码块
			cacheGroups: {//缓存组
				common: {//公共的模块
					chunks: "initial",//提取公共代码的入口
					minSize: 0,//公用的字节大于0
					minChunks: 2,//公用的次数
				},
				vendor: {
					priority: 1,//权重  先抽第三方模块
					test: /node_modules/,  //把你抽离出来
					chunks: "initial",//提取公共代码的入口
					minSize: 0,//公用的字节大于0
					minChunks: 2,//公用的次数
				}
			}

		}
	},
  1. 懒加载
index.js
let button = document.createElement('button')
button.innerHTML = "hello"
button.addEventListener('click',function () {
	console.log("click");

	//es6 草案中的语法  jsonp实现动态加载文件  返回的是个promise  vue路由懒加载的实现原理  react
	import('./source.js').then(data => {
		console.log(data);
	})
})
  1. 热更新
webpack.config.js
plugins: [
		new HtmlWebpackPlugin({
			template: "./public/index.html",
			filename: "index.html"
		}),
		new Webpack.IgnorePlugin(/\.\/locale/, /moment/),  //只引入moment中中文语言包  忽略其他的
		// new Webpack.DllReferencePlugin({
		// 		// 	manifest: path.resolve(__dirname,'dist','manifest.json')
		// 		// }),
		new Webpack.NamedModulesPlugin({ //指定模块更新  打印更新的模块路径

		}),
		new Webpack.HotModuleReplacementPlugin({ //热更新插件

		})
	],
	devServer: {
		port: 3000,
		open: true,
		contentBase: './dist',
		hot:true  //启用热更新
	},
	
index.js
import str from './source'
console.log(str)


if(module.hot){//支持热更新
	module.hot.accept('./source',() => {
		let str = require('./source')
		console.log(str);
	})

}

版权声明:本文为sodakii原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。