安装 nrm:
npm install -g nrm
NRM 常用命令:
# 查看可选源
nrm ls
# 测试 taobao 源响应时间
nrm test taobao
# 切换到 taobao 源
nrm use taobao
# 增加 taobao 定制源,地址为 http:192.168.0.0.1:8080
nrm add taobao http:192.168.0.0.1:8080
# 删除 taobao 源
nrm del taobao
使用 nvm 可以用来管理不同版本的 node.
reduce() 接收一个函数作为累加器:
// 使用 reduce 进行累加求和
let sum = arr.reduce(function (prev, cur, index, arr) {
return prev + cur;
}, 0);
// 求出数组中最大值
let max = arr.reduce(function (prev, cur) {
return Math(prev, cur);
});
// 数组去重
let res = arr.reduce(function (prev, cur) {
prev.indexOf(cur) == -1 && prev.push(cur);
return prev;
}, []);
新增的数组遍历方法 for of:
// 遍历数组的值
for (let item of arr.values()) {
console.log(item);
}
// 遍历数组的索引
for (let item of arr.keys()) {
console.log(item);
}
// 索引和值都要
for (let [index, item] of arr.entries()) {
console.log(index, item);
}
数组中的元素替换 fill:
let arr = [1, 2, 3, 4, 5];
arr.fill("imooc", 1, 3);
console.log(arr); // [1, "imooc", "imooc", 4, 5]
可以使用 includes 查找数组中是否含有 NaN:
let arr = [1, 2, 3, NaN];
console.log(arr.includes(NaN)); // true
console.log(arr.indexOf(NaN)); // -1
1、不可当做构造函数
2、不可以使用 arguments 对象,但可以使用 rest 运算符获取参数
let foo = (...args) => {
console.log(args);
};
foo(1, 2, 3);
let obj = {
name: "123",
age: 18,
school: "xxx",
};
// 方法1
Object.keys(obj).forEach((key) => {
console.log(key, obj[key]);
});
// 方法2
Object.getOwnPropertyNames(obj).forEach((key) => {
console.log(key, obj[key]);
});
// 方法3
Reflect.ownKeys(obj).forEach((key) => {
console.log(key, obj[key]);
});
// 检查类型
let checkType = (data) => {
return Object.property.toString.call(data).slice(8, -1);
};
// 深拷贝
let deepClone = (obj = {}) => {
if (typeof obj !== "object" || object == null) {
// obj 不是对象类型,或者 obj 是对象类型但为 null,直接返回
return obj;
}
// 初始化返回结果
let result;
result = checkType(obj) === "Array" ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key]);
}
}
return result;
};
// 父类
function Animal(name) {
this.name = name;
}
Animal.prototype.showName = function () {
console.log(`名字是:` + this.name);
};
// 子类
function Dog(name, color) {
Animal.call(this, name); // 继承属性
this.color = color;
}
Dog.prototype = new Animal(); // 继承方法
Dog.prototype.constructor = Dog; // 把原型复原
let d1 = new Dog("wangcai", "white");
console.log(d1);
d1.showName();
class People {
constructor(name, age) {
this.name = name;
this.age = age;
this._sex = -1; // 给类添加静态方法
}
get sex() {
// 静态类属性的获取
if (this._sex === 1) {
return "male";
} else if (this._sex === 0) {
return "female";
} else {
return "error";
}
}
set sex(val) {
// 静态类属性的设置
if (val === 0 || val === 1) {
this._sex = val;
}
}
showName() {
console.log(this.name);
}
static getCount() {
return 5;
}
}
let p1 = new People("lyc", 18);
console.log(p1);
p1.sex = 1; // 父类类的静态属性的设置
console.log(p1.sex); // 父类的静态属性的获取
console.log(p1.getCount()); // 报错,实例调用父类静态方法会报错
class Coder extends People {
constructor(name, age, company) {
super(name, age);
this.company = company;
}
showCompany() {
console.log(this.company);
}
}
let c1 = new Coder("zhangsan", 18, "xxx");
console.log(c1);
c1.showName();
c1.showCompany();
c1.sex = 1; // 实例可以继承和获取父类的 get / set 属性
console.log(c1.sex);
console.log(Coder.getCount()); // 子类可以继承父类的静态方法
1、for……in、for……of 循环无法遍历 symbol 属性 2、Object.getOwnPropertySymbols() 只能能获取到 symbol 属性 3、Reflect.ownKeys() 既能获取到普通属性,又能获取到 symbol 属性
// symbol()
let s1 = Symbol("foo");
let s2 = Symbol("foo");
s1 === s2; // false
// symbol.for():在全局定义
let s1 = Symbol.for("foo");
let s2 = Symbol.for("foo");
s1 === s2; // true
使用 symbol() 去耦合
const shapeType = {
triangle: Symbol(),
circle: Symbol(),
};
function getArea(shape) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = 1;
break;
case shapeType.circle:
ares = 2;
break;
}
return area;
}
console.log(getArea(shapeType.triangle));
let s = new Set([1, 2, 3, 2]);
s.add("imooc").add("es"); // 增
s.delete(2); // 删
s.clear(); // 清空
console.log(s.has("imooc")); // 查
console.log(s.size); // 大小(长度)
// 遍历
s.forEach((item) => console.log(item));
for (let item of s) {
console.log(item);
}
for (let item of s.keys()) {
console.log(item); // set 的 key 与 value 相同
}
for (let item of s.values()) {
console.log(item); // set 的 key 与 value 相同
}
for (let item of s.entries()) {
console.log(item[0], item[1]); // set 的 key 与 value 相同
}
// 使用 set 求交集
let s1 = new Set(arr1);
let s2 = new Srt(arr2);
let result = new Set(arr1.filter((item) => s2.has(item)));
console.log(Array.from(result));
// 使用 set 求差集
let arr3 = new Set(arr1.filter((item) => !s2.has(item)));
let arr4 = new Set(arr2.filter((item) => !s1.has(item)));
console.log([...arr3, ...arr4]);
1、WeakSet 里只能传入对象,可传入多个对象
2、WeakSet 不能被遍历
let map = new Map([
["name", "xxx"],
["age", 5],
]);
console.log(map);
// {
// 0: {"name" => "xxx"}
// 1: {"age" => 5}
// size: {...}
// }
console.log(map.size);
console.log(map.has("name"));
console.log(map.get("age"));
map.set("name", "zhangsan");
console.log(map);
// {
// 0: {"name" => "zhangsan"}
// 1: {"age" => 5}
// size: {...}
// }
// 带标签的模板字符串
const foo = (a, b, c, d) => {
console.log(a);
console.log(b);
console.log(c);
console.log(d);
};
const name = "xxx";
const age = 18;
foo`这是${name},他的年龄是${age}岁`;
// 打印: {
// ["这是", ",他的年龄是", "岁", raw: Array(3)]
// xxx
// 18,
// undefined
// }
ES5 的正则修饰符:i(忽略大小写) m(多行匹配) g(全局匹配)
ES6 新增:y(粘连修饰符),g 是每次匹配剩余的,y 是从剩余的第一个开始匹配
u: unicode 模式匹配
// 十进制 -> 二进制
const a = 5;
console.log(a.toString(2)); // 101
// 二进制 -> 十进制
const b = 101;
console.log(parseInt(b, 2)); // 5
// ES6 0B二进制 0O八进制
const a = 0b101;
console.log(a); //5
const b = 0o777;
console.log(b); //511
// 最简易的代理
let obj = {};
let p = new Proxy(obj, {});
p.name = "imooc";
console.log(obj.name); // 'imooc'
for (let key in obj) {
console.log(key); // 'name'
}
// get 拦截对象属性的读取,比如proxy.foo或proxy['foo']
let dict = {
hello: "你好",
world: "世界",
};
dict = new Proxy(dict, {
get(target, prop) {
// target:
// {
// 'hello': '你好',
// 'world': '世界'
// };
// dict["world"] 时 prop 为 "world"
// dict["xxx"] 时 prop 为 "xxx"
return prop in target ? target[prop] : "error";
},
});
console.log(dict["world"]); // 世界
console.log(dict["xxx"]); // 'error'
// set 拦截对象属性的设置,返回一个布尔值,比如proxy.foo=v,或数组的push、unshift等
let arr = [];
arr = new Proxy(arr, {
set(target, prop, val) {
if (typeof val === "number") {
target[prop] = val;
return true;
} else {
return false;
}
},
});
arr[1] = 7;
arr.push(5);
console.log(arr[0], arr[1], arr[2], arr.length); // undefined 7 5 3
// has 拦截 proKey in proxy 的操作,返回一个布尔值
let range = {
start: 1,
end: 5,
};
range = new Proxy(range, {
has(target, prop) {
return prop >= target.start && prop <= target.end;
},
});
console.log(2 in range); // true
console.log(9 in range); // false
// ownKeys 拦截属性遍历包括 getOwnPropertyNames、getOwnPropertySymbols、keys、for……in, 返回一个数组
// 前面知识复习:
let obj = {
name: "imooc",
[Symbol("es")]: "es6",
};
console.log(Object.getOwnPropertyNames(obj)); // ['name']
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(es)]
console.log(Object.keys(obj)); // ['name']
for (let key in obj) {
console.log(key); // ['name']
}
// ownKeys 使用:
let userinfo = {
username: "lyc",
age: 34,
_password: "***",
};
userinfo = new Proxy(userinfo, {
ownKeys(target) {
return Object.keys(target).filter((key) => !key.startsWidth("_"));
},
});
for (let key in userinfo) {
console.log(key); // username age
}
console.log(Object.keys(userinfo)); // ['username', 'age']
// deleteProperty 拦截 delete proxy[proxyKey]的操作,返回一个布尔值
// apply 拦截函数调用、call 和 apply 操作
let sum = (...args) => {
let sum = 0;
args.forEach((item) => {
num += item;
});
return num;
};
sum = new Proxy(sum, {
apply(target, ctx, args) {
return target(...args) * 2;
},
});
console.log(sum(1, 2)); // 6
console.log(sum.call(null, 1, 2, 3)); // 12
console.log(sum.apply(null, [1, 2, 3])); // 12
// construct 拦截 new 命令,返回一个对象
let User = class {
constructor(name) {
this.name = name;
}
};
User = new Proxy(User, {
construct(target, args, newTarget) {
console.log("construct");
return new target(...args);
},
});
console.log(new User("imooc"));
1、将 Object 属于语言内部的方法放到 Reflect 上
// Object 上的方法
Object.defineProperty();
// Reflect 上的方法
Reflect.defineProperty();
2、修改某些 Object 方法的返回结果,让其变得更合理
// 原始方法判断某个对象的某个属性能否被定义
try {
Object.defineProperty(); // 如果不能将报错
} catch (e) {}
// 使用 Reflect
if (Reflect.defineProperty()) {
// 能否被定义将返回布尔类型的值,而不是报错
// bollean
} else {
}
3、让 Object 操作变成函数行为
// 原始写法判断 Object 里是否有 assign 方法
console.log("assign" in Object); // true
// 使用 Reflect
console.log(Reflect.has(Object, "assign")); // true
4、Reflect 对象的方法与 Proxy 对象的方法一一对应
// 回调地狱改成 promise
// callback hell
ajax("static/a.json", (res) => {
console.log(res);
ajax("static/b.json", (res) => {
console.log(res);
ajax("static/c.json", (res) => {
console.log(res);
});
});
});
// promise
new Promise((resolve, reject) => {
// 请求 a.json
ajax("static/a.json", (res) => {
console.log(res);
resolve();
});
}).then(res=>{
console.log('a 成功')
return new Promise((resolve, reject) => {
// 请求 b.json
ajax("static/b.json", (res) => {
console.log(res);
resolve();
});
}).then(res=>{
console.log('b 成功')
return new Promise((resolve, reject) => {
// 请求 c.json
ajax("static/c.json", (res) => {
console.log(res);
resolve();
});
}).then(res=>{
console.log('c 成功')
});
// 优化
function getPromise(url){
return new Promise(resolve, reject){
ajax(url, res => {
resolve(res)
})
}
}
getPromise('static/a.json').then(res => {
console.log(res)
return getPromise('static/b.json')
}).then(res => {
console.log(res)
return getPromise('static/c.json')
}).then(res => {
console.log(res)
})
// promise.all
const imgArr = ['1.jpg', '2.jpg', '3.jpg']
let promiseArr = []
imgArr.forEach(item => {
promiseArr.push(new Promise(resolve, reject)=>{
// 图片上传的操作
resolve()
})
})
Promise.all(promiseArr).then(res => {
// 插入数据库的操作
console.log('图片全部上传完成')
})
// 使用 promise.race 限制请求加载时间
function getImg(){
return new Promise((resolve, reject) => {
let img = new Image()
img.onload = function(){
resolve(img)
}
img.src = 'http://www.xxx.com/xxx.jpg'
})
}
function timeOut(){
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('图片请求超时')
}, 2000)
})
}
Promise.race([getImg(), timeOut()]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
function* gen(x) {
let y = 2 * (yield x + 1);
let z = yield y / 3;
return x + y + z;
}
let g = gen(5);
console.log(g.next()); // 6
console.log(g.next()); // NaN
console.log(g.next()); // NaN
let g = gen(5);
console.log(g.newxt()); // 6
console.log(g.newxt(12)); // 8 y=24
console.log(g.newxt(13)); // 42 z=13 x=5
// 自增 7 的生成器
function* count(x = 1) {
while (true) {
if (x % 7 === 0) {
yield x;
}
x++;
}
}
let n = count();
console.log(n.next().value); // 7
console.log(n.next().value); // 14
console.log(n.next().value); // 21
console.log(n.next().value); // 28
console.log(n.next().value); // 35
// 使用生成器连续发送请求
function request(url) {
ajax(url, (res) => {
getData.next(res);
});
}
function* gen() {
let res1 = yield request("static/a.json");
console.log(res1);
let res2 = yield request("static/b.json");
console.log(res2);
let res3 = yield request("static/c.json");
console.log(res3);
}
let getData = gen();
getData.next();
对于可迭代对象有两种情况: 1、可迭代协议:Symbol.iterator 2、迭代器协议:
// 把不可迭代的对象可迭代化
return {
next() {
return { value, done };
},
};
原生具备 Iterator 接口的数据结构: Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象
function makeIterator(arr) {
let nextIndex = 0;
return {
next() {
return nextIndex < arr.length
? {
value: arr[nextIndex++],
done: false,
}
: {
value: undefined,
done: true,
};
},
};
}
let it = makeIterator(["a", "b", "c"]);
console.log(it.next()); // {value: 'a', done: false}
console.log(it.next()); // {value: 'b', done: false}
console.log(it.next()); // {value: 'c', done: false}
console.log(it.next()); // {value: undefined, done: true}
// 数组原生的 iterator
let arr = ["a", "b", "c"];
console.log(arr);
let it = arr[Symbol.iterator]();
console.log(it.next()); // {value: 'a', done: false}
console.log(it.next()); // {value: 'b', done: false}
console.log(it.next()); // {value: 'c', done: false}
console.log(it.next()); // {value: undefined, done: true}
// 让对象可迭代
let courses = {
allCourse:{
frontend: ['ES', '小程序', 'Vue', 'React']
backend: ['Java', 'Python', 'SpringBoot']
webapp: ['Android', 'IOS']
}
}
courses[Symbol.iterator] = function(){
let allCourse = this.allCourse
let keys = Reflect.ownKeys(allCourse)
let values = []
return{
next(){
if(!values.length){
if(keys.length){
values = allCourse[keys[0]]
keys.shift()
}
}return{
done:!values.length,
value:values.shift()
}
}
}
}
// 使用
for(let c of courses){
console.log(c)
}
// 使用 generator 实现
courses[Symbol.iterator] = function* (){
let allCourse = this.allCourse
let keys = Reflect.ownKeys(allCourse)
let values = []
while(true){
if(!values.length){
if(keys.length){
values = allCourse[keys[0]]
keys.shift()
yield value.shift()
} else {
return false
}
} else {
yield values.shift()
}
}
}
function timeout() {
return new Promise((resolve) => {
setTimeout(() => {
console.log(1);
resolve();
}, 1000);
});
}
// 使用 await 与不使用 await
// 使用 await
async function foo1() {
await timeout();
console.log(2); // 先打印 1 后打印 2
}
// 不使用 await
async function foo2() {
timeout();
console.log(2); // 先打印 2 后打印 1
}
// 使用 async await 处理失败的 promise
function timeout() {
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('success');
reject("fail");
}, 1000);
});
}
async function foo() {
return await timeout();
}
foo()
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
// async await 实现 axios 伪代码
async function request() {
const data = await axios.get("http://xxx.com");
console.log(data);
}
// 使用 async await 实现 ajax 的异步操作按顺序执行
function request(url) {
return new Promise((resolve) => {
ajax(url, (res) => {
resolve(res);
});
});
}
async function getData() {
const res1 = await request("static/a.json");
console.log(res1);
const res2 = await request("static/b.json");
console.log(res2);
const res3 = await request("static/c.json");
console.log(res3);
}
getData();
// 数组的同步迭代遍历 for……of
const arr = ["es6", "es7", "es8", "es9"];
arr[Symbol.iterator] = function () {
let nextIndex = 0;
return {
next() {
return nextIndex < arr.length
? {
value: arr[nextIndex++],
done: false,
}
: {
value: undefined,
done: true,
};
},
};
};
for (let item of arr) {
console.log(item);
}
// 数组的异步迭代遍历 for await……of
function getPromise(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
value: time,
done: false,
});
}, time);
});
}
const arr = [getPromise(1000), getPromise(2000), getPromise(3000)];
arr[Symbol.asyncIterator] = function () {
let nextIndex = 0;
return {
next() {
return nextIndex < arr.length
? arr[nextIndex++]
: {
value: undefined,
done: true,
};
},
};
};
async function test() {
for await (let item of arr) {
console.log(item);
}
}
test();
// 1 秒后打印 1000
// 再隔 2 秒后打印 2000
// 再隔 3 秒后打印 3000
// 具名组匹配
const reg = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const groups = reg.exec("2020-02-01").groups;
const { year, month, day } = groups;
console.log(year, month, day);
// 先行断言
const str = "ecmascript";
console.log(str.match(/ecma(?=script)/)); // 匹配后面是 script 的 ecma
// 后行断言
console.log(str.match(/(?<=ecma)script/)); // 匹配前面是 ecma 的 script
console.log(str.match(/(?<!ecma)script/)); // 匹配前面不是 ecma 的 script
// 过滤对象中大于 80 的项
const course = {
math: 80,
english: 85,
chinese: 90,
};
const res = Object.entries(course).filter(([key, value]) => val > 80);
console.log(Object.fromEntries(res));
const arr = [1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, 12]]]];
console.log(arr.flat(Infinity)); // arr.flat 传入的参数为扁平化层级
const str = `
<html>
<body>
<div>第一个div</div>
<p>这是p</p>
<div>第二个div</div>
<span>这是span</span>
<div>第三个div</div>
</body>
</html>
`;
// 使用正则对象的 exec g 匹配全部的 div
function selectDiv(regExp, str) {
let matches = [];
while (true) {
console.log(regExp.lastIndex);
const match = regExp.exec(str);
console.log(match);
if (match == null) {
break;
}
matches.push(match[1]);
}
return matches;
}
const regExp = /<div>(.*)<\/div>/g; // 不使用 g 模式匹配,会在每次匹配后重头开始匹配,导致 while 死循环
const res = selectDiv(regExp, str);
console.log(res);
// 字符串的 match 方式实现
console.log(str.match(regExp)); //['<div>第一个div</div>, '<div>第二个div</div>', '<div>第三个div</div>']
// 字符串的 replace 方式实现
function selectDiv(regExp, str) {
let matches = [];
str.replace(regExp, (all, first) => {
matches.push(first);
});
return matches;
}
const res = selectDiv(regExp, str);
console.log(res); // ['第一个div, '第二个div', '第三个div']
// 字符串的 matchAll 方式实现
function selectDiv(regExp, str) {
let matches = [];
for(let match of str.matchAll(regExp)){
matches.push(match[1]);
});
return matches;
}
const res = selectDiv(regExp, str)
console.log(res); // ['第一个div, '第二个div', '第三个div']
Promise.allSettled([
Promise.resolve({
code: 200,
data: [1, 2, 3],
}),
Promise.reject({
code: 500,
data: [],
}),
Promise.resolve({
code: 200,
data: [7, 8, 9],
});
]).then(res=>{
const data = res.filter(item => item.status === 'fulfilled')
console.log(data)
})
async created(){
const {data} = await axios.get('http://www.xxx.com')
// 对数据的升序降序进行代理
this.proxy = new Proxy({},{
get(target, key){
if(key === 'asc'){ // 升序
return [].concat(data).sort((a, b) => a.name > b.name ? 1 : -1)
}else if(key === 'desc'){ // 降序
return [].concat(data).sort((a, b) => b.name > a.name ? 1 : -1)
}else{
return data
}
},
set(){
return false
}
})
this.userLst = this.proxy.data.default
},
methods:{
asc(){
this.userList = this.proxy.asc
},
desc(){[].concat(data this.userList = this.proxy.desc
},
reset(){
this.userList = this.proxy.default
}
}
多图片上传到云存储:
<div>
<label for="uploadImg" :class="{upLoading: isUploading}"
>请选择上传图片</label
>
<input
type="file"
multiple
id="uploadImg"
style="display:none;"
accept="image/*"
@change="onChange"
ref="imgFile"
:disabled="isUploading"
/>
<p>提示:一次可选择多张图片,最多不超过9张(单张大小 < 1M)</p>
<ul class="img-container">
<li
v-for="(item, index) in imgList"
:key="index"
:style="{background: `url(${item}) no-repeat center/contain`}"
></li>
</ul>
</div>
<script>
import OSS from "ali-oss";
export default {
data() {
return {
client: new OSS({
region: "oss-cn-beijing",
bucket: "xxx",
accessKeyId: "自己的id",
accessKeySecret: "自己的密码",
}),
imgList: [], // 存放上传完成的图片的列表
isUploading: false, // 当前图片是否正在上传
};
},
methods: {
onChange() {
// 可选链
const newFiles = this.$refs?.imgFile?.files;
// 校验
if (newFiles.length > 9) {
alert("最多可以一次选择9张图片");
return false;
}
const files = [];
for (const file of newFiles) {
const size = file.size / 1024 / 1024; // 把单位转化成 M
if (size > 1) {
alert("请选择1M以内的图片");
return false;
}
files.push(file);
}
this.uploadFilesByOSS(files);
},
// 上传多图到阿里云OSS
uploadFilesByOSS(files) {
this.isUploading = true;
const uploadRequest = [];
for (const file of files) {
new Promise((resolve, reject) => {
this.client
.put(`${Math.random()}-${file.name}`, file)
.then((res) => {
resolve(res.url);
})
.catch((err) => {
console.log(err);
reject(err);
});
});
}
Promise.allSettled(uploadRequest)
.then((res) => {
const imgs = [];
for (const item of res) {
if (item.status === "fulfilled") {
imgs.push(item.value);
}
}
this.imgList = imgs;
this.isUploading = false;
})
.catch((err) => {
console.log(err);
});
},
// 使用 async / await 更优雅的实现上传多图到阿里云OSS
async uploadFilesByOSS2(files) {
this.isUploading = true;
const imgs = [];
for (const file of files) {
const result = await this.client.put(
`${Math.random()}-${file.name}`,
file
);
imgs.push(result.url);
}
this.imgList = imgs;
this.isUploading = false;
},
},
};
</script>
<style>
.img-container > li {
list-style: none;
width: 150px;
height: 100px;
float: left;
margin: 0 30px 30px 0;
border: 1px solid #ccc;
}
</style>
1、Loader:
loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块
module.exports = {
module: {
rules: [
{
test: /\.txt$/,
use: "raw-loader",
},
];
}
}
2、Plugin:
loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务,比如打包优化、资源管理、注入环境变量等
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 用于为 html 文件自动引入外部资源
const webpack = require("webpack"); // 用于访问内置插件
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
};
对某一个目录下的文件不进行 webpack 打包编译,直接拷贝过去:
const copyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new copyPlugin([
{ from: "source", to: "dest" }, // 从 source 目录原方不动的拷贝到 dest 目录下
{ from: "other", to: "public" }, // 从 other 目录原方不动的拷贝到 public 目录下
]),
],
};
package.json:
"scripts":{
"start": "webpack-dev-server --mode=development --config ./build/webpack.config.js",
"build": "webpack --mode=production --config ./build/webpack.config.js"
}
webpack.config.js:
const merge = require("webpack-merge");
const baseConfig = require("./webpack.base.config.js");
const devConfig = require("./webpack.dev.config.js");
const proConfig = require("./webpack.pro.config.js");
module.exports = (env, argv) => {
// 此处的 argv 参数需要在 package.json 中传入
const config = argv.mode === "development" ? devConfig : proConfig;
return merge(baseConfig, config);
};
webpack.base.config.js:
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "entry",
},
],
],
},
},
},
],
},
};
webpack.dev.config.js:
module.exports = {
devtool: "cheap-module-eval-source-map",
};
webpack.pro.config.js:
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
plugins: [new CleanWebpackPlugin()],
};
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。