webpack高级

1. HTML中img标签的图片资源处理

读取html中所有img的路径,帮我们把路径作统一的进行转换,处理并且把对应的资源打包
把html中所有的img对应的路径打包

  1. 安装npm intall -S html-withimg-loader
  2. webpack.config.js文件中添加loader
	{
		test: /\.(htm|html)$/i,
		loader: 'html-withimg-loader'
	}

使用时, 只需要在html中正常引用图片即可, webpack会找到对应的资源进行打包, 并修改html中引用路径

copy-webpack-plugin 的作用是将源代码中的一些资源文件拷贝到指定位置
html-withimg-loader 的作用是把html中所有的img对应的路径打包

2. 多页应用的打包

多页应用:
咱们当前的vue项目中都是一个html页面,里面可以引入一个main.js, main.js作为html的唯一入口,可以引入各种各样的js, css, less, sass等等, 包括各种各样的第三方模块等,都可以引入, 而index.html只需要引入这一个main.js就足够了.这就是webpack帮我们实现的最终的目的,这样做的好处就是打包完成之后只会有一个html, 也就是我们俗称的单页面应用程序(SPA, single page application)

  1. webpack.config.js中修改入口和出口配置
  // 1. 修改为多入口
  entry: {
      main: './src/main.js',
      other: './src/other.js'
  },
  output: {
    path: path.join(__dirname, './dist/'),
    // filename: 'bundle.js',
    // 2. 多入口无法对应一个固定的出口, 所以修改filename为[name]变量
    filename: '[name].js',
    publicPath: '/'
  },
  plugins: [
      // 3. 如果用了html插件,需要手动配置多入口对应的html文件,将指定其对应的输出文件
      new HtmlWebpackPlugin({
          template: './index.html',
          filename: 'index.html',
          chunks: ['main']
      }),
      new HtmlWebpackPlugin({
          template: './index.html',
          filename: 'other.html',
          // chunks: ['other', 'main']
          chunks: ['other']
      })
  ]
  1. 修改入口为对象, 支持多个js入口, 同时修改 output 输出文件名为'[name].js'表示各自以入口文件名作为输出文件名, 但是html-webpack-plugin不支持此功能, 所以需要再拷贝一份插件, 用于生成两个html页面,事项多页应用.

3. 第三方库的两种引入方式

比如说我们希望把一个jQuery导入到项目中,并挂载到全局作用域中,也就是说,我希望它放到window身上,而事实上,我们使用webpack导入进来的其实并没有挂载到全局作用域中,它实际上是挂载到了当前这个模块的闭包作用域,因为webpack的原理其实就是把每一个模块作为一个闭包来进行打包. 所以你在任何一个模块导入的jQuery他其实都是在局部变量中,并没有在全局window下面. 所以这个第三方的库,如果我们想作为全局引入,需要借助一个loader.

可以通过expose-loader 进行全局变量注入, 同时也可以使用内置插件 webpack.ProvidePlugin 对每个模块的闭包空间, 注入一个变量, 自动加载模块, 而不必到处importrequire

  • expose-loader 将库引入到全局作用域
    找到node_modules下面的jquery, 注入到全局
  1. 安装expose-loader
    npm i -D expose-loader
  2. 配置loader
	module: {
	  rules: [{
	    test: require.resolve('jquery'),
	    use: {
	      loader: 'expose-loader',
	      options: '$'
	    }
	  }]
	}

tips: require.resolve 用来获取模块的绝对路径. 所以这里的loader只会作用于 jquery 模块. 并且只在 bundle 中使用到它时, 才进行处理.

  • webpack.ProvidePlugin 将库自动加载到每个模块
  1. 引入 webpack

    	const webpack = require('webpack')
    
  2. 创建插件对象
    要自动加载jquery, 我们可以将两个变量都指向对应的node模块

    	new webpack.ProvidePlugin({
    		$:'jquery',
    		jQuery: 'jquery'
    	})
    

4. Development / Production 不同配置文件打包

项目开发时一般需要使用两套配置文件, 用于开发阶段打包 ( 不压缩代码, 不优化代码, 增加效率 ) 和上线阶段打包 ( 压缩代码, 优化代码, 打包后直接上线使用 )

抽取三个配置文件:

  • webpack.base.js
  • webpack.prod.js
  • webpack.dev.js

步骤如下:

  1. 将开发环境和生产环境共用的配置放入base中, 不同的配置各自放入 prod 或 dev 文件中 ( 例如: mode )
  2. 然后再 dev 和 prod 中使用webpack-merge 把自己的配置与 base 的配置进行合并后导出
    npm i -D webpack-merge
  3. 将 package.json 中的脚本参数进行修改, 通过--config 手动指定特定的配置文件

5. 定义环境变量

除了区分不同的配置文件进行打包, 还需要在开发时知道当前的环境时开发阶段或上线阶段, 所以可以借助内置插件 DefinePlugin 来定义环境变量. 最终可以实现开发阶段与上线阶段的 api 地址自动切换

  1. 引入 webpack
	const webpack = require('webpack')
  1. 创建插件对象, 并定义环境变量
	new webpack.DefinePlugin({
		// 这里的字符串 false会被解析成布尔类型的false
		// 如果想输入字符串, 需要套两层引号'"false"'
		// 这里相当于会把引号内的内容作为js代码解析
		IS_DEV: 'false'
	})

3.在src打包的代码环境下可以直接使用

6. 使用 devServer 解决跨域问题

在使用webpack开发的过程中, 我们势必会用到 webpack-dev-server, 一旦用到 webpack-dev-server, 就一定会涉及到跨域.

在这里插入图片描述
webpack-dev-server内部其实就是一个服务器, 比如说我们在localhost:3000端口启用了这个服务, 客户端去访问 localhost:3000端口的时候会得到服务器给的响应, 也就是我们看到的html和我们打包好的 bundle.js

客户端拿到这个 html 和 js 之后, 仍然需要通过 ajax 向数据接口服务器获取网络数据, 由于是浏览器中使用 ajax, 就会有一个同源策略的限制. 这就意味着, 我们发送请求到webpack-dev-server 这个localhost:3000端口的位置, 得到了响应, js想发起新的 ajax 请求, 就必须只能发送到 localhost:3000端口, 不能发别的地方, 而且协议, 域名, 端口号都必须相同. 只要有一个地方不相同, 就会被浏览器给阻止掉. 这就是非常经典的跨域问题.

目前解决跨域主要的方案有:

  1. jsonp (淘汰)
  2. cors ( cross-origin-resource-share ) 跨域资源共享
    原理: 在数据接口服务器加一个响应头信息, 告诉客户端, 我信任你
  3. http proxy
    此处介绍的使用 devServer 解决跨域, 其实原理就是 http proxy

将所有 ajax 请求发送给 devServer 服务器, 再由 devServer 服务器做一次转发, 发送给数据接口服务器

由于 ajax 请求时发送给 devServer 服务器的, 所以不存在跨域, 而 devServer 由于是用 node 平台发送的 http 请求, 自然也不涉及到跨域问题, 可以完美解决!

在这里插入图片描述

服务器代码 (返回一段字符串即可) :

	const express = require('express')
	const app = express()
	// const cors = require('cors')
	// app.use(cors())
	app.get('/api/getUserInfo', (req, res) => {
	  res.send({
	    name: '安吉拉',
	    age: 13
	  })
	});
	
	app.listen(9999, () => {
	  console.log('http://localhost:9999!');
	});

前端需要配置 deServer 的 proxy 功能, 在 webpack.dev.js 中进行配置:

	devServer: {
	    open: true,
	    hot: true,
	    compress: true,
	    port: 3000,
	    // contentBase: './src'
	    proxy: {
	      '/api': 'http://localhost:9999'
	    }
	  },

意为前端请求/api 的url时, webpack-dev-server 会将请求转发给 http://localhost:9999/api处, 此时如果请求地址为http://localhost:9999/api/getUserInfo, 只需要直接写 /api/getUserInfo 即可, 代码如下:

	axios.get('/api/getUserInfo').then(result => console.log(result))

如果我们请求的接口是/getUserInfo, 我们是不是需要在proxy中再加一条配置呢?
事实上我们有更优秀的处理方式,仔细瞧好了哈

服务端代码:

	app.get('/getUserInfo', (req, res) => {
	  res.send({
	    name: '安吉拉',
	    age: 13
	  })
	});

webpack.dev.js 配置:

	devServer: {
	    open: true,
	    hot: true,
	    compress: true,
	    port: 3000,
	    // contentBase: './src'
	    proxy: {
	      '/api': {
			target: 'http://localhost:9999',
			// 表示转发请求时不携带 /api, /api 被重写成''
			pathRewrite: {
			  '^/api': ''
			}
		  }
	    }
	  },

请求:

	axios.get('/api/getUserInfo').then(result => console.log(result))

7. HMR的使用

需要对某个模块进行热更新 ( 不刷新页面的局部更新 ) 时, 可以通过 module.hot.accept 方法进行文件监视

只要模块内容发生变化, 就会触发回调函数, 从而可以重新读取模块内容, 做对应的操作

	if (module.hot) {
	  module.hot.accept('./hotmodule.js', function() {
	    console.log('hotmodule.js更新了');
	    let str = require('./hotmodule.js')
	    console.log(str)
	  })
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值