清除输出目录:clean-webpack-plugin npm i -D clean-webpack-plugin
自动生成目录:html-webpack-plugin npm i -D html-webpack-plugin
复制静态资源:copy-webpack-plugin npm i -D copy-webpack-plugin
开发服务器
在开发阶段,目前遇到的问题是打包、运行、调试过程过于繁琐,回顾一下我们的操作流程:
编写代码
2. 控制台运行命令完成打包
3. 打开页面查看效果
4. 继续编写代码,回到步骤2
并且,我们往往希望把最终生成的代码和页面部署到服务器上,来模拟真实环境。为了解决这些问题,webpack官方制作了一个单独的库:webpack-dev-server;它既不是plugin也不是loader;( 它并不会像真正的webpack打包,而是搭建了一个临时服务器环境,通过地址直接访问。它是开发阶段的,所以必须依赖开发环境。 )
怎么用?1. 安装 2. 执行**`webpack-dev-server`**
命令webpack-dev-server
命令几乎支持所有的webpack命令参数,如--config
、--env
等等,可以把它当作webpack命令使用;这个命令是专门为开发阶段服务的,真正部署的时候还是得使用webpack命令;当我们执行**webpack-dev-server**
命令后,它做了以下操作:内部执行webpack命令,传递命令参数
2. 开启watch
3. 注册hooks:类似于plugin,webpack-dev-server会向webpack中注册一些钩子函数,主要功能如下:
a. 将资源列表(aseets)保存起来 b. 禁止webpack输出文件
4. 用express开启一个服务器,监听某个端口,当请求到达后,根据请求的路径,给予相应的资源内容
配置
针对webpack-dev-server的配置,参考:https://www.webpackjs.com/configuration/dev-server/
常见配置有:
- port:配置监听端口
- proxy:配置代理,常用于跨域访问
- stats:配置控制台输出内容
普通文件处理:(普通文件处理,这个文件里面也不是css代码,也不是js代码,而是像图片、字体……文件,之前我们用(copy-webpack-plugin)复制静态资源,静态资源里面有一些图片……,要原封不动copy到dist中,其中html页面当中有img.src是写死的。有的时候,它可能是js根据情况,往页面上添加,比方说在src中的assets文件中,通常我们根据 js 嵌入的资源都放到了assets中,在index.js页面中,const png = require(”./asssets/webpack.png”); if ( math.random < 0.5){ 用js添加一张图片let img = document.createElement(‘img’); img.src = png; document.body,appendChild(img); },我们希望的是导入的模块结果是一个可用的资源路径。但是这个是不符合要求的。因为这个模块webpack是把这个图片当做js处理的,到了抽象语法树的一分析就报错了,不是有效的js代码,因此这个时候打包是会遇到问题的。所以就要用到了loader,给我一个源代码返回另外一个源代码。file-loader就可以处理这样的一个问题)
file-loader: 生成依赖的文件到输出目录,然后将模块文件设置为:导出一个路径\
js<br />**//file-loader**<br />**function loader(source){**<br />** // source:文件内容(图片内容 buffer)**<br />** // 1. 生成一个具有相同文件内容的文件到输出目录**<br />** // 2. 返回一段代码 export default "文件名"**<br />**}**<br />
url-loader:将依赖的文件转换为:导出一个base64格式的字符串
js<br />**//file-loader**<br />**function loader(source){**<br />** // source:文件内容(图片内容 buffer)**<br />** // 1. 根据buffer生成一个base64编码**<br />** // 2. 返回一段代码 export default "base64编码"**<br />**}**<br />
解决路径问题
在使用file-loader或url-loader时,可能会遇到一个非常有趣的问题
比如,通过webpack打包的目录结构如下:
yaml<br />dist<br /> |—— img<br /> |—— a.png #file-loader生成的文件<br /> |—— scripts<br /> |—— main.js #export default "img/a.png"<br /> |—— html<br /> |—— index.html #<script src="../scripts/main.js" ></script><br />
这种问题发生的根本原因:模块中的路径来自于某个loader或plugin,当产生路径时,loader或plugin只有相对于dist目录的路径,并不知道该路径将在哪个资源中使用,从而无法确定最终正确的路径; 面对这种情况,需要依靠webpack的配置publicPath解决
webpack内置插件
所有的webpack内置插件都作为webpack的静态属性存在的,使用下面的方式即可创建一个插件对象
```js
const webpack = require(“webpack”)
new webpack.插件名(options)
```
DefinePlugin
全局常量定义插件,使用该插件通常定义一些常量值,例如:
js<br />**new webpack.DefinePlugin({**<br />** PI: `Math.PI`, // PI = Math.PI**<br />** VERSION: `"1.0.0"`, // VERSION = "1.0.0"**<br />** DOMAIN: JSON.stringify("duyi.com")**<br />**})**<br />
这样一来,在源码中,我们可以直接使用插件中提供的常量,当webpack编译完成后,会自动替换为常量的值
## BannerPlugin
它可以为每个chunk生成的文件头部添加一行注释,一般用于添加作者、公司、版权等信息
js<br />**new webpack.BannerPlugin({**<br />** banner: `**<br />** hash:[hash]**<br />** chunkhash:[chunkhash]**<br />** name:[name]**<br />** author:yuanjin**<br />** corporation:duyi** ** `**<br />**})**<br />
## ProvidePlugin
自动加载模块,而不必到处 import 或 require
js<br />**new webpack.ProvidePlugin({**<br />** $: 'jquery',**<br />** _: 'lodash'**<br />**})**<br />
然后在我们任意源码中:
js<br />**$('#item'); // <= 起作用**<br />**_.drop([1, 2, 3], 2); // <= 起作用**<br />
练习区域查询
请求地址:http://yuanjin.tech:5100/api/local
https://open.duyiedu.com/api/student/findAll?appkey=Diana_1602512479606
method:GET
query:(npm i -D query-string专门做地址栏参数解析的)
- parentId: 可选,若不填,则查询所有省份,若填写省份id,则查询省份下的所有城市
使用env区别环境的时候在package.json中配置的时候 需要这样 webpack —env abc
开发服务器
webpack.config.js---
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: "development",
devtool: "source-map",
output: {
filename: "scripts/[name].[chunkhash:5].js"
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./public/index.html"
})
],
devServer: {
port: 8000,
open: true,
proxy: { //代理规则
"/api": {
target: "http://open.duyiedu.com",
changeOrigin: true //更改请求头中的host和origin
}
},
stats: {
modules: false,
colors: true
}
},
// stats: {
// modules: false,
// colors: true
// }
}
./src/index.js---
const url = `/api/student/findAll?appkey=demo13_1545210570249`;
fetch(url).then(resp => resp.json()).then(resp => {
console.log(resp)
})
/* 我们访问的页面的主机名:http://localhost:8080 请求的地址是 https:developer.duyiedu.com……就是跨域了,协议
主机端口号都不一样。之前用的是jsonp 和 cros解决的跨域,但是都是需要服务器参与进来的,如果服务器没有解决这种问题呢?
在我们前端开发页面和js开发完成后往往会部署到同一个域中。比如:后台的服务器域,http://duyi.com,那么前端开发完成
后的放到服务器的域:http://duyi.com往往是一样的,最终访问的域是http://duyi.com,这样的话没有跨域问题了。但是现在
还没有开发完,还在开发阶段,这个跨域问题是在开发阶段发生了,实际上开发完了之后并不会产生这种问题,这个时候就因为是
同一个域可以直接用/api/student/findAll?appkey=demo13_1545210570249然后就不会出问题了;但是会找不到。所以就用
到了proxy */
普通文件处理
webpack.config.js---
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: "development",
devtool: "source-map",
output: {
filename: "scripts/[name].[chunkhash:5].js"
},
module: {
rules: [
{
test: /\.(png)|(gif)|(jpg)$/,
use: [{
loader: "url-loader",
options: {
// limit: false //不限制任何大小,所有经过loader的文件进行base64编码返回
limit: 10 * 1024, //只要文件不超过 100*1024 字节,则使用base64编码,否则,交给file-loader进行处理
name: "imgs/[name].[hash:5].[ext]"
}
}]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./public/index.html"
})
],
devServer: {
open: true
},
stats: {
modules: false,
colors: true
}
}
./src/index.js---
//希望导入的模块结果是一个可用的资源路径
import png from "./assets/webpack.png"
console.log(png)
var img = document.createElement("img");
img.src = png;
document.body.appendChild(img);
webpack内置插件
webpack.config.js---
const webpack = require("webpack")
module.exports = {
mode: "development",
devtool: "source-map",
plugins: [
new webpack.DefinePlugin({
PI: `Math.PI`, // const PI = Math.PI
VERSION: `"1.0.0"`, // VERSION = "1.0.0"
DOMAIN: JSON.stringify("duyi.com") // DOMAIN = "duyi.com"
}),
new webpack.BannerPlugin({
banner: ` hash:[hash]
chunkhash:[chunkhash]
name:[name]
author:yuanjin
corporation:duyi `
}),
new webpack.ProvidePlugin({
$: 'jquery',
_: 'lodash'
})
]
}
src/index.js---
// console.log(PI);
// console.log(VERSION);
// console.log(DOMAIN);
var r1 = $('#item'); // <= 起作用
var r2 = _.drop([1, 2, 3], 2); // <= 起作用
console.log(r1, r2);
练习--区域查询
webpack.config.js---
const prodConfig = require('./webpack.prod')
const devConfig = require('./webpack.dev')
const baseConfig = require('./webpack.base')
module.exports = function (env) {
// console.log({...baseConfig})
if(env && env.abc){
return{
...baseConfig,
...prodConfig
}
}
else{
return{
...baseConfig,
...devConfig
}
}
}
webpack.dev.js---
module.exports = {
mode:"development",
devServer:{
open:true,
openPage:'list.html',//用来打开指定的html
proxy:{
"/api":{
target:"https://open.duyiedu.com",
changeOrigin: true
}
}
}
}
webpack.prod.js---
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
mode:"production",
plugins:[
new CleanWebpackPlugin(),//清除之前生成输出目录
]
}
webpack.base.js---
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry:{
list: './src/list/index.js',
detail: './src/detail/index.js'
},
output:{
filename:"scripts/[name][chunkhash:5].js",
path: path.resolve(process.cwd(), 'dist'),//这个是cleanwebpackplugin需要的
},
stats:{
modules: false,//控制台中输出模块信息减少
colors:true//控制台中的信息加重点颜色区分
},
plugins:[
// new CleanWebpackPlugin(),//清除之前生成输出目录
new HtmlWebpackPlugin({
template:"./public/list.html",
filename:"list.html",
chunks: ['list']
}),
new HtmlWebpackPlugin({//拿模板
template:"./public/detail.html",//copy模板的地址
filename:"detail.html",//生成模板之后的文件名字
chunks: ['detail']//规定引入的js文件 找到输出文件的名字
}),
new CopyWebpackPlugin({//用来复制文件的
patterns: [
{ from: "./public", to: "./" },
]
})
]
}
./src/detail/index.js---
import $ from "jquery"
import {getProvinces} from '../util/areaService';
const dl = $("dl");
getProvinces().then(res=>{
for(const p of res.data){
$("<dd>").text(`${p.address}`).appendTo(dl)
}
})
./src/list/index.js---
import $ from "jquery"
import {getProvinces} from '../util/areaService';
console.log('aa')
getProvinces().then(res=>{
console.log(res.data)
const ul = $(".provinces");
for(const p of res.data){
const li = $("<li>").appendTo(ul);
const a = $("<a>").text(p.name).appendTo(li);
a.prop("href", `detail.html`)
}
})
./src/util/areaService.js---
export async function getProvinces(){
return await fetch('api/student/findAll?appkey=Diana_1602512479606').then(res=>res.json())
}
-----------------------------------------------------------------------------------------------------
./src/util/areaService.js---
/* 得到所有的省份*/
export async function getProvinces() {
return await fetch("/api/local").then(resp => resp.json())
}
/*根据省份id得到所有的城市*/
export async function getCities(parentId) {
const url = `/api/local?parentId=${parentId}`;
return await fetch(url).then(resp => resp.json())
}
./src/list/index.js----
import { getProvinces } from "@/util/areaService"
import $ from "jquery"
getProvinces().then(ps => {
//ps:省份的数组
const ul = $(".provinces");
for (const p of ps) {
const li = $("<li>").appendTo(ul);
const a = $("<a>").text(p.simpleName).appendTo(li);
a.prop("href", `detail.html?name=${p.areaName}&id=${p.id}`)
}
});
./src/detail/index.js---
import { getCities } from "@/util/areaService"
import qs from "query-string"
import $ from "jquery"
const parsed = qs.parse(location.search);
$(".title").text(parsed.name)
const dl = $("dl")
getCities(parsed.id).then(cs=>{
for(const c of cs){
$("<dd>").text(c.simpleName).appendTo(dl)
}
})