目录
一、安装webpack和webpack-cli
二、指令方式运行
三、配置文件方式运行
四、less-loader解析less
五、一般es6语法转换
六、JS兼容性处理(包括ie)
七、使用url-loader解析样式中的图片
八、打包html中图片资源
九、打包html文件
十、打包字体等资源
十一、自动编译打包运行
十二、多页面配置打包
十三:ESLint 校验 JS 代码
十四、提取css成单独文件
十五、添加css兼容
十六、打包 Ts 和 Scss
十七、压缩js、css和html
十八、Resolve 模块解析
十九、Source-Map 配置(devtool映射)
二十、watch 监听和 clean 清理
二十一、HMR 热替换
二十二、请求代理设置
二十三、支持vue单文件组件
二十四:环境分离设置
二十五、webpack中path、outputPath、publicPath联系与区别
二十六、总结
二十七、项目完整代码
npm i [email protected] [email protected] -g //全局安装,作为指令使用
npm i [email protected] [email protected] -D //本地安装,作为本地依赖使用
注意:如果是局部安装,则需要在package.json中配置scripts,通过运行"npm run start"或"npm start"运行webpack:
{
"scripts": {
"start": "webpack"
}
}
开发配置指令:
webpack src/js/index.js -o dist/js/index.js --mode=development
生产配置指令:
webpack src/js/index.js -o dist/js/index.js --mode=production
可在package.json中配置scripts,通过运行"npm run build"运行webpack:
"scripts": {
"build": "webpack src/js/index.js -o dist/js/index.js --mode=production"
}
webpack.config.js:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist/js'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: 'bundle.js'
},
mode: 'development',
devtool: 'inline-source-map'
};
配置好上述文件后在cmd中通过:
webpack
命令即可运行
假如webpack配置文件为“./config/webpack.base.config.js”,则package.json中打包命令配置为:
"scripts": {
"build": "webpack --config ./config/webpack.base.config.js"
}
概述:webpack不能直接解析less文件,需要借助loader编译解析。
1、安装loader:
npm i [email protected] [email protected] [email protected] [email protected] -D
less-loader基于less,所以要安装less。
注意各包的版本,否则会报错。
package.json:
{
"name": "webpack4",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"css-loader": "^4.3.0",
"less": "^3.12.2",
"less-loader": "^7.0.1",
"style-loader": "^2.0.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
}
}
2、配置loader:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist/js'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: 'bundle.js'
},
mode: 'production',
//1、所有的loader都要添加在module对象的rules中
//2、rules是一个数组,数组中的每一个对象就是一个loader
//3、loader特点:下载后无需引入,只需申明
module: {
rules: [{
test: /\.less$/, //匹配所有less文件
use: [
'style-loader', //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}]
}
};
3、运行指令:webpack
附:
src/css/demo.less:
.demo1{
width: 500px;
height: 500px;
background: #FF0000;
}
.demo2{
width: 200px;
height: 200px;
background: #000000;
}
src/js/index.js:
import func1 from './moudle1'
import func2 from './moudle2'
import '../css/demo.less'
console.log(func1(1, 2));
console.log(func2(2, 3));
console.log("webpack!");
index.html:
Document
高版本的火狐、chrome等标准浏览器直接支持es6中const和箭头函数等一般语法及promise等高级语法,但低版本的火狐、chrome等标准浏览器及ie不行,使用babel-loader可以将一般es6语法转换成es5语法。
安装loader:
npm i [email protected] @babel/[email protected] @babel/[email protected] -D
babel-loader:与 Webpack 协同工作的模块,加载处理 js 文件;
@babel/core:Babel 编译器的核心模块,是 babel-loader 依赖;
@babel/preset-env:Babel 预置器,用于分析 ES6 语法;
配置loader:
module: {
rules: [{
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}]
}
我们在 src 中的 js 文件,使用 ES6 的箭头函数来尝试一下;
let fn = (x, y) => x + y;
console.log(fn(10, 20));
PS:在没有使用 Babel 时,它打包会原封不动的使用 ES6 语法;
PS:在使用 Babel 之后,编译后的代码如下:
var fn = function fn(x, y) {
return x + y;
};
console.log(fn(10, 20));
如果你使用了未纳入标准(提案中)的代码,打包时,它会提醒你安装相关插件:
//提案中,尚未纳入标准的语法
class Person {
#name;
constructor() {
this.#name = 'Mr.Lee';
}
}
安装相关插件:
npm i @babel/plugin-proposal-class-properties -D
options: {
presets : [
'@babel/preset-env'
],
plugins : [
'@babel/plugin-proposal-class-properties'
]
}
高版本的火狐、chrome等标准浏览器直接支持es6中const和箭头函数等一般语法及promise等高级语法,但低版本的火狐、chrome等标准浏览器及ie不行,使用polyfill或core.js可以将所有es6语法转换成es5语法,使得其兼容性更强(包括兼容ie)。
1、使用polyfill
安装polyfill:
cnpm i @babel/[email protected] -D
使用:
入口文件中直接引入:
import '@babel/polyfill'
/**
* 当前文件是入口文件,可汇总js、css、字体、图片、音频、视频
*/
import '@babel/polyfill' //包括es6高级语法的转换,不管编码人员使用了哪些新语法,全部新语法都转换
import module1 from './module1'
import module2 from './module2'
import module3 from './module3'
import '../css/demo.less'
module2().then(data => {
console.log("promise resolve:" + data);
}).catch(error => {
console.log("promise reject:" + error);
})
console.log(module2);
console.log(module3);
setTimeout(function(){
console.log("定时器到点了");
}, 1000)
优点:解决babel只能转换部分低级语法的问题,引入polyfill后可转换高级语法,比如Promise。
缺点:将所有高级语法进行转换,不管实际使用情况。
2、借助core.js按需引入(babel+core.js,使用core.js时可以不用polyfill):
安装core-js:
npm i [email protected] -D
使用core-js:
配置文件中loader方式引入
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //使用corejs的方式,表示按需加载
corejs: { version: 3 }, //指定core-js的版本
targets: { //要兼容的目标浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存,只编译未编译代码,可减少编译时间
}
}
}]
}
图片文件分为css引入图片和html插入图片。css加载图片都是背景图。小图片采用base64转换字符串,小图片、大图片都需要单独的loader插件来完成。
用到的处理图片的loader插件如下:
安装loader:
npm i [email protected] [email protected] -D
说明:url-loader基于file-loader,且多了能针对不同图片大小进行不同处理的功能。
配置loader:
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader', //url-loader依赖file-loader,使用了url-loader后file-loader可以不用
options: {
limit: 8192, //url-loader能将小于8k图片编译成base64,大的采用file-loader处理
publicPath: './dist/images', //决定实际代码中的图片地址
outputPath: 'images', //决定文件本地输出地址
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}]
}
一定要注意webpack.config.js中publicPath路径,包含图片的样式打包后会放置在页面的style标签中,图片打包后会放置在dist/images目录下,根据页面和生成的图片的路径关系,所以publicPath为 './dist/images':
webpack.config.js:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: './js/bundle.js'
},
mode: 'development',
//1、所有的loader都要添加在module对象的rules中
//2、rules是一个数组,数组中的每一个对象就是一个loader
//3、loader特点:下载后无需引入,只需申明
module: {
rules: [{
test: /\.less$/, //匹配所有less文件
use: [
'style-loader', //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}, {
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}, {
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //按需引入需要使用polyfill
corejs: { version: 3 }, //解决不能找到core-js的问题
targets: { //解决兼容性处理哪些浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存
}
}
}, {
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
publicPath: './dist/images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}]
}
};
各loader版本:
{
"name": "webpack4",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"babel-loader": "^8.1.0",
"css-loader": "^4.3.0",
"file-loader": "^6.2.0",
"less": "^3.12.2",
"less-loader": "^7.0.1",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
}
}
index.js
import func1 from './moudle1'
import func2 from './moudle2'
import '../css/demo.less'
console.log(func1(1, 2));
console.log(func2(2, 3));
console.log("webpack!");
moudle1.js
const fun1 = (a, b) => {
console.log("a + b = ", a+b);
}
module.exports = fun1;
moudle2.js
const fun2 = (a, b) => {
console.log("a + b = ", a+b);
}
module.exports = fun2;
demo.less
.demo1{
width: 500px;
height: 500px;
background: #FF0000 url("../images/download.png");
}
.demo2{
width: 200px;
height: 200px;
background: #000000;
}
index.html
Document
概述:html中的图片url-loader没法处理,它只能处理js中引入的图片/样式中的图片,不能处理html中的img标签,需要引入html-loader处理。
添加图片:在src/index.html添加两个img标签。
安装loader:
npm i [email protected] -D
配置loader:
module: {
rules: [{
test: /\.(html)$/,
use: {
loader: 'html-loader' // html-loader找到图片后自动交给url-loader处理
}
}]
}
完整代码:
webpack.config.js:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: './js/bundle.js'
},
mode: 'development',
//1、所有的loader都要添加在module对象的rules中
//2、rules是一个数组,数组中的每一个对象就是一个loader
//3、loader特点:下载后无需引入,只需申明
module: {
rules: [{
test: /\.less$/, //匹配所有less文件
use: [
'style-loader', //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}, {
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}, {
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
publicPath: './images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}, {
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
}]
},
plugins: [new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
})]
};
一定要注意url-loader中的publicPath。
index.html:
Document
demo.less:
.demo1{
width: 200px;
height: 200px;
background-image: url("../images/react.png");
background-size: cover;
}
.demo2{
width: 200px;
height: 200px;
background-image: url("../images/vue.jpg");
background-size: cover;
}
package.json:
{
"name": "webpack4",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"babel-loader": "^8.1.0",
"css-loader": "^4.3.0",
"file-loader": "^6.2.0",
"html-loader": "^1.1.0",
"html-webpack-plugin": "^3.2.0",
"less": "^3.12.2",
"less-loader": "^7.0.1",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
},
"dependencies": {}
}
概述:html文件webpack不能解析,需要借助插件编译解析。
添加html文件:
安装插件Plugins
npm i [email protected] -D
在webpack.config.js中引入插件(插件都需手动引入,而loader会自动加载):
const HtmlWebpackPlugin = require('html-webpack-plugin');
配置插件:
plugins: [new HtmlWebpackPlugin({
template: './src/index.html', //以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认。路径相对于npm命令执行所在目录。
filename: 'index.html' // 打包后的index.html文件默认位于dist目录下
})]
运行指令:
webpack
完整代码:
src/index.html:
Document
src/js/index.js:
import func1 from './moudle1'
import func2 from './moudle2'
import '../css/demo.less'
const word = "webpack!";
console.log("webpack!");
console.log(func1(1, 2));
func2().then(data=>{
console.log(data);
}).catch(error=>{
console.log(error);
})
删除
import '@babel/polyfill'
webpack.config.js:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: './js/bundle.js'
},
mode: 'development',
//1、所有的loader都要添加在module对象的rules中
//2、rules是一个数组,数组中的每一个对象就是一个loader
//3、loader特点:下载后无需引入,只需申明
module: {
rules: [{
test: /\.less$/, //匹配所有less文件
use: [
'style-loader', //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}, {
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}, {
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //按需引入需要使用polyfill
corejs: { version: 3 }, //解决不能找到core-js的问题
targets: { //解决兼容性处理哪些浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存
}
}
}, {
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
publicPath: './images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}]
},
plugins: [new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
})]
};
概述:其它资源,比如图标,webpack不能解析,需要借助loader编译解析。
安装loader:
npm i [email protected] -D
配置loader:
{
test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'media', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}
src/index.html中添加字体标签:
Document
添加字体样式文件src/css/iconfont.less:
@font-face {
font-family: "iconfont"; /* Project id */
src: url('../media/iconfont.ttf?t=1621867822279') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-caiwuguanli:before {
content: "\e609";
}
.icon-baojiaguanli:before {
content: "\e60a";
}
.icon-baoguanzhidantaitouguanli:before {
content: "\e60b";
}
.icon-caigoudingdan:before {
content: "\e60c";
}
.icon-cangchuguanli:before {
content: "\e60d";
}
.icon-caigoulujing:before {
content: "\e60e";
}
index.js中引入iconfont.less文件:
import func1 from './moudle1'
import func2 from './moudle2'
import '../css/demo.less'
import '../css/iconfont.less'
const word = "webpack!";
console.log("webpack!");
console.log(func1(1, 2));
func2().then(data=>{
console.log(data);
}).catch(error=>{
console.log(error);
})
运行指令:
webpack
文件夹结构:
iconfont.less(注意引用的字体路径):
@font-face {
font-family: "iconfont"; /* Project id */
src: url('../media/iconfont.ttf?t=1621867822279') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-caiwuguanli:before {
content: "\e609";
}
.icon-baojiaguanli:before {
content: "\e60a";
}
.icon-baoguanzhidantaitouguanli:before {
content: "\e60b";
}
.icon-caigoudingdan:before {
content: "\e60c";
}
.icon-cangchuguanli:before {
content: "\e60d";
}
.icon-caigoulujing:before {
content: "\e60e";
}
index.html:
Document
webpack.config.js:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: './js/bundle.js'
},
mode: 'development',
//1、所有的loader都要添加在module对象的rules中
//2、rules是一个数组,数组中的每一个对象就是一个loader
//3、loader特点:下载后无需引入,只需申明
module: {
rules: [{
test: /\.less$/, //匹配所有less文件
use: [
'style-loader', //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}, {
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}, {
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
//publicPath: '../dist/images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}, {
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
}, {
test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'media', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}]
},
plugins: [new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
})]
};
package.json:
{
"name": "webpack4",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"babel-loader": "^8.1.0",
"css-loader": "^4.3.0",
"file-loader": "^6.2.0",
"html-loader": "^1.1.0",
"html-webpack-plugin": "^3.2.0",
"less": "^3.12.2",
"less-loader": "^7.0.1",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10"
},
"dependencies": {}
}
由于代码可能有CommonJS等非浏览器支持的语法,每次都必须打包才行运行,虽然借助Webstorm等工具可以构建服务器环境,但实际上不能时时监控刷新。IDE提供的服务器之间访问的是打包后的文件,是否监听时时刷新看个人习惯。
以上:如果要方便的话,开发者需求的想法是,开发时方便调试,最后再打包。所以,官方提供了Webpack-dev-Server工具来解决这个问题,支持特性:
注:
此处是自动刷新整个页面 ,如果想做到局部刷新,则请浏览:二十二、HMR 热替换
1、安装loader:
npm i [email protected] -D
详情见:官网->指南->开发环境->使用webpack-dev-server
2、修改webpack配置对象:
devServer: {
open: true,
compress: true,
port: 3000,
stats: 'minimal'//迷你型服务启动信息
}
webpack.config.js:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: './js/bundle.js' // 直接在根目录下生成js文件夹及bundle.js文件
},
mode: 'development',
//1、所有的loader都要添加在module对象的rules中
//2、rules是一个数组,数组中的每一个对象就是一个loader
//3、loader特点:下载后无需引入,只需申明
module: {
rules: [{
test: /\.less$/, //匹配所有less文件
use: [
'style-loader', //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}, {
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}, {
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
//publicPath: '../dist/images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}, {
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
}, {
test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'media', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}]
},
plugins: [new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
})],
devServer: {
open: true,
compress: true,
port: 8080,
stats: 'minimal',//迷你型服务启动信息
},
};
3、修改url-loader部分配置:
4、修改package.json中scripts指令:
"start": "webpack-dev-server --open chrome --port 3000"
5、./index.html:
Document
1
6、运行指令:
npm start
经过以上设置,处理的html是根目录下的index.html,打包后的js位于设置的根目录下的js文件夹下。
本地我们可以删除dist目录,还原打包之前再启动devServer测试效果。此时我们可以发现并不需要打包到本地,它是自动打包到内存让你时时预览调试的。也就是说:调试阶段,可以用devServer,完成了,再最终打包到本地即可。
多页面配置
如果我们想生成多个.html 文件,比如 index.html 和 main.html,此时,我们需要修改一下入口文件和出口文件:
//入口文件
entry: {
//把需要加载的 js 以键值对方
index : './src/js/index.js',
main : './src/js/main.js'
},
或
//入口文件,也支持 ES6 的箭头函数
entry: () => ({
index : './src/js/index.js',
main : './src/js/main.js'
}),
出口文件,需要按照入口文件的名称进行打包,否则只会打包一个。
//出口文件
output: {
//文件名
filename : 'js/[name].js',
}),
最后,我们要使用 HtmlWebpackPlugin 插件来设置自己想要的打包方案:
//插件
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html", //默认值
filename: "index.html", //默认值
chunks: ['index', 'main']
}),
new HtmlWebpackPlugin({
template: "./src/main.html",
filename: "main.html",
chunks: ['main']
}),
],
基本的 ESLint 实现,需要一下安装以下模块:
首先,先安装 eslint,然后安装配置信息:
npm i [email protected] -D //安装 eslint
.\node_modules\.bin\eslint --init //安装配置信息
PS:期间会让你选择配置信息情况,根据你实际情况选择即可,生成:.eslintrc.json;
PS:网上也会别人生成的配置信息可以拿来用,也可以去官网 eslint.cn/demo 生成信息
再次,我们安装 eslint-loader 模块:
npm i [email protected] -D
最后,我们来配置 webpack.config.js:
{
test : /.js$/,
loader: 'eslint-loader',
//编译前执行
enforce: 'pre',
//不检查的目录
exclude: /node_modules/
},
防止错误飘红太多,干扰演示,我们注释掉大部分代码,写上示例:
var foo = bar;
测试打包和预览提示校验。
注意插件和loader的版本:
{
"name": "webpack4",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --config ./config/webpack.prod.config.js",
"dev": "webpack-dev-server --open chrome --port 8080 --config ./config/webpack.dev.config.js",
"start": "webpack-dev-server --open chrome --port 8080 --config ./config/webpack.dev.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.11.5",
"autoprefixer": "^9.8.6",
"axios": "^0.22.0",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^4.0.0",
"core-js": "^3.13.0",
"css-loader": "^4.3.0",
"eslint": "^7.2.0",
"eslint-loader": "^4.0.2",
"file-loader": "^6.2.0",
"html-loader": "^1.1.0",
"html-webpack-plugin": "^3.2.0",
"less": "^3.12.2",
"less-loader": "^7.0.1",
"mini-css-extract-plugin": "^1.6.0",
"optimize-css-assets-webpack-plugin": "^6.0.0",
"postcss-flexbugs-fixes": "^4.2.1",
"postcss-loader": "^3.0.0",
"postcss-normalize": "^8.0.1",
"postcss-preset-env": "^6.7.0",
"style-loader": "^2.0.0",
"url-loader": "^4.1.1",
"vue-loader": "^15.9.8",
"vue-template-compiler": "^2.6.14",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"vue": "^2.6.14"
}
}
cnpm i [email protected] -D
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
new MiniCssExtractPlugin({
filename: 'css/[name].css'
})
{
test: /\.less$/, //匹配所有less文件
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}
package.json
"scripts": {
"build": "webpack",
"build": "webpack --config ./config/webpack.prod.js",
"dev": "webpack-dev-server --open chrome --port 8080 --config ./config/webpack.dev.js"
},
npm run dev
完整代码:
src/index.html:
Document
config/webpack.dev.js:
const path = require('path')
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: './js/bundle.js'
},
module: {
rules: [
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
'css-loader',
'less-loader'
]
},
{
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //按需引入需要使用polyfill
corejs: { version: 3 }, //解决不能找到core-js的问题
targets: { //解决兼容性处理哪些浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存,只编译未编译代码,可减少编译时间
}
}
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
limit: 8192,
//publicPath: '../images',
outputPath: 'images',
name: '[hash:5].[ext]'
}
}
},
{
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
},
{
test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4)$/,
use: [{
loader: 'file-loader',
options: {
//publicPath: '../media',
outputPath: 'media',
name: '[hash:5].[ext]'
}
}]
}
]
},
plugins: [new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}
}), new MiniCssExtractPlugin({
filename: './css/[name].css'
})],
devServer: {
open: true,
compress: true,
port: 8080,
hot: true
}
}
一定要注意:这里使用url-loader生成的背景图片是在css文件中引入,所有这里查找图片是从build/css目录去build/images目录查找:
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, //url-loader能将小于8k图片编译成base64,file-loader不具此功能
//publicPath: '../images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}
config/webpack.prod.js:
const path = require('path')
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: './src/js/index.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: './js/bundle.js'
},
module: {
rules: [
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
'css-loader',
'less-loader'
]
},
{
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //按需引入需要使用polyfill
corejs: { version: 3 }, //解决不能找到core-js的问题
targets: { //解决兼容性处理哪些浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存,只编译未编译代码,可减少编译时间
}
}
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
limit: 8192,
//publicPath: '../images',
outputPath: 'images',
name: '[hash:5].[ext]'
}
}
},
{
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
},
{
test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4)$/,
use: [{
loader: 'file-loader',
options: {
//publicPath: '../media',
outputPath: 'media',
name: '[hash:5].[ext]'
}
}]
}
]
},
plugins: [new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}
}), new MiniCssExtractPlugin({
filename: './css/[name].css'
})]
}
方法一:
cnpm i [email protected] [email protected] [email protected] [email protected] [email protected] -D
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
require('postcss-normalize')()
],
sourceMap: true,
},
}
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, '../build'), // 由当前文件所在位置和要生成的build位置关系决定
filename: './js/bundle.js',
publicPath: '/'
},
mode: 'production',
devtool: 'cheap-module-source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //按需引入需要使用polyfill
corejs: { version: 3 }, //解决不能找到core-js的问题
targets: { //解决兼容性处理哪些浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存,只编译未编译代码,可减少编译时间
}
}
},
{
test: /\.less$/, //匹配所有less文件
use: [
MiniCssExtractPlugin.loader, //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
require('postcss-normalize')()
],
sourceMap: true,
},
},
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}, {
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, //url-loader能将小于8k图片编译成base64,file-loader不具此功能
//publicPath: '../images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}, {
test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'media', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}, {
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
}
]
},
plugins: [new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}
}), new MiniCssExtractPlugin({
filename: 'css/[name].css'
}), new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: [
'default',
{
discardComments: {
removeAll: true
},
},
]
},
cssProcessorOptions: {
map: {
inline: false,
annotation: true
}
}
})]
};
#Browsers that we support
last 1 version
> 1%
IE 10 # sorry
方法二:
npm i [email protected] -D
{
test: /\.css$/,
//执行顺序是从右往左边
use : [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath : '../'
}
},
{
loader: "css-loader",
options: {
importLoaders : 1 //由于采用了@import,被导入的css无法解析,需要设置importLoaders=1即可
}
},
'postcss-loader'
]
}
npm i [email protected] -D
这个插件会在需要兼容性的样式中加上CSS前缀,比如:-ms、-webkit等。在根目录创建postcss.config.js用来配置兼容的浏览器,当postcss-loader被调用时postcss.config.js文件就会执行。
postcss.config.js
/*
postcss配置文件
*/
const AutoPrefixer = require('autoprefixer');
module.exports = {
plugins : [
new AutoPrefixer({
overrideBrowserslist : [
'> 0.15% in CN'
//'ie >= 8'
]
})
]
};
在index.css中添加css样式:
display: flex;
transform: rotateY(130deg);
编译后看编译完成的css文件中是否有兼容性代码。
npm i [email protected] -D
index.css中添加如下样式:
:root{
--green:green;
};
h1{
color:var(--green);
}
postcss.config.js修改如下:
//请注意:如果使用postcss-preset-env,就删除autoprefixer
//因为post-preset-env集成了autoprefixer,不需要再引入设置
// const AutoPrefixer = require('autoprefixer');
const PostPresetEnv = require('postcss-preset-env');
module.exports = {
plugins : [
new PostPresetEnv({
browsers : [
'> 0.15% in CN'
//'ie >= 8'
]
})
]
};
编译后看编译完成的css文件中是否有兼容性代码。
Scss
和 Less 一样,Scss 也是 Sass 的一种使用较多的语法;
cnpm install sass sass-loader node-sass -D
具体配置基本和 Less 一样,先创建.scss 文件,并引入:
{
test: /\.scss$/,
//从右向左执行
use : [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
},
TypeScript
越来越流行的 TypeScript,JavaScript 的一个超集。
cnpm i typescript ts-loader -D
{
test: /\.ts$/,
use : 'ts-loader',
}
编写一个.ts 文件,然后通过 import 导入到 index.js。
//type.ts
export const output = (content : string) => {
return content
}
//import ts
import { output } from './type.ts'
console.log(output('Mr.Lee'))
如果要省略掉 import 中文件后缀,需要配置:
module.exports = {
resolve: {
extensions: ['.ts', '.js']
}
}
PS:需要创建 tsconfig.json 文件。
为何要压缩代码?什么情况下要压缩?
答:在生产环境下打包时节约资源。
既然在生产环境,那首先要把打包的配置更改为生产环境:
mode: "production"
调节为生产环境打包,就会自动将 js 代码进行打包,不需要单独设置。
压缩css
npm i [email protected] -D
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: [
'default',
{
discardComments: {
removeAll: true
},
},
]
},
cssProcessorOptions: {
map: {
inline: false,
annotation: true
}
}
})
npm run build
serve -s build
webpack.prod.js:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, '../build'), // 由当前文件所在位置和要生成的build位置关系决定
filename: './js/bundle.js',
publicPath: '/'
},
mode: 'production',
devtool: 'cheap-module-source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //按需引入需要使用polyfill
corejs: { version: 3 }, //解决不能找到core-js的问题
targets: { //解决兼容性处理哪些浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存,只编译未编译代码,可减少编译时间
}
}
},
{
test: /\.less$/, //匹配所有less文件
use: [
MiniCssExtractPlugin.loader, //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}, {
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, //url-loader能将小于8k图片编译成base64,file-loader不具此功能
publicPath: '../images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}, {
test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'media', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}, {
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
}
]
},
plugins: [new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
}), new MiniCssExtractPlugin({
filename: 'css/[name].css'
}), new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: [
'default',
{
discardComments: {
removeAll: true
},
},
]
},
cssProcessorOptions: {
map: {
inline: false,
annotation: true
}
}
})]
};
压缩html
修改前面安装的html-webpack-plugin插件配置:
new HtmlWebpackPlugin({
template: './src/index.html', //以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源)
minify: {
removeComments: true, // 是否移除注释 默认 false
collapseWhitespace: true, // 是否去除空格,默认 false
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}
})
JS中,在 import 文件时如果不限定后缀会出现无法载入的情况,我们可以使用Resolve 模块中的extensions 来进行解析:
//模块解析
resolve: {
//导入文件查找的限定后缀,默认.js 和.json
extensions: ['.ts', '.js', '.json' ]
},
PS:导入语句时如果检测不到指定的会报错。
alias 配置可以用别名的方式,将导入路径映射成一个新的路径:
//设置一个别名路径(绝对路径)
alias: {
css : path.resolve(__dirname, './src/css')
}
require('css/base.css');
modules 配置可以指定 webpack 的解析模块目录:
//找到解析模块目录,如果当前找不到就不断往上一层找
modules: ['node_modules']
//也可以设置指定目录直接查找,检查查找次数
modules: [path.resolve(__dirname, '../node_modules')]
PS:自然,也可以设置第二参数,防止第一参数找不到报错。
上述配置最终效果:
resolve: {
//导入语句省略后缀
extensions: ['.ts', '.js', '.json'],
//导入路径的别名
alias: {
css: path.resolve(__dirname, './src/css')
},
//解析模块目录
// modules: [path.resolve(__dirname, '../node_modules'), 'node_modules']
},
Source-Map 可以将编译、打包、压缩后的代码映射到源代码上,你打包或运行的代码是编译后的,报错后devtool映射能指向你源代码的位置上,它会生成一个.map 文件。
配置方式:
devtool: 'source-map'
根据不同的方式,有下面几种类型:
在开发环境和生产环境,我们该如何选择?开发要求速度快,调试方便推荐:
1、watch 监听
每次打包,都比较烦,耗时耗力,有一种解决方案:watch 文件监听。这种解决方案,就是你打包时,就挂着监听你原始文件的变化,从而自动更新。
//文件监听,默认 false
watch: true,
//开启 watch,下面才有意义
watchOptions: {
//不监听解析模块目录
ignored: /node_modules/,
//防止更新频率太快,默认 300 毫秒,意味监听到变化后 500 毫秒再编译
aggregateTimeout: 500,
//轮询间隔时间,1 秒,询问系统指定文件是否变化了
poll: 1000
},
2、clean 清理
每次打包之前都要手动清空设置的打包目录,因为不清空的话,改了配置目录就会多出废目录或文件。所以,使用 clean-webpack-plugin 插件,可以解决这个问题。
npm i clean-webpack-plugin -D
//获取 clean 清理插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
//插件
plugins: [
new CleanWebpackPlugin()
]
页面调试有一个问题,就是当我们编辑了 css 或 js它会自动刷新。但如果有大量的 css 或 js,一个小修改就要全部刷新影响开发性能。而 HMR 热替换就是解决这个问题,当 css 或 js 修改时只刷新修改的部分。对于html 文件,它就一个文件,不需要热替换。开启 HMR 热替换,可以在启动服务时加上--hot,或者在 devServer 配置:
devServer: {
hot : true
}
对于 css 的热替换,需要使用 style-loader:
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
当开启了 HMR 热替换之后,发现 html 文件修改后无法自动更新了,此时我们需要在入口文件加入这个 html 文件即可:
entry: [
'./src/js/index.js',
'./src/index.html'
],
对于 js 的热替换,只要在入口文件对加载的其它 js 文件进行设置即可:
import name from './module'
console.log(name);
if (module.hot) {
module.hot.accept('./module', () => {
console.log(name);
})
}
这里提供两个远程 json 文件,会返回一些数据用于测试跨域问题:
https://cdn.liyanhui.com/data.json (可跨域,设置过)
https://cdn.ycku.com/data.json (不可跨域,默认)
安装 axios用于 ajax 测试:
npm install axios
编写代码,测试数据:
import axios from 'axios'
axios.get('https://cdn.liyanhui.com/data.json').then(res => {
console.log(res.data)
})
如果把地址中的 liyanhui 换成 ycku 的话,会出现跨域的问题。
通过 devServer 设置代理模式,来解决跨域问题:
devServer: {
//设置代理
proxy: {
//匹配前缀为/api
'/api': {
//目标域名 ip
target: 'https://cdn.ycku.com',
//改变源
changeOrigin: true,
//重写 url, 去掉 /api
pathRewrite: {
'^/api': ''
}
}
}
}
axios.get('/api/data.json').then(res => { ... }).catch(error => {})
安装vue及相关插件
cnpm i [email protected] -S
cnpm i [email protected] [email protected] -D
webpack.config.js中解构VueLoaderPlugin:
const { VueLoaderPlugin } = require("vue-loader");
webpack.config.js中加入vue-loader:
{
test: /\.vue$/, //匹配vue文件
use: 'vue-loader'
}
及VueLoaderPlugin插件:
plugins: [new VueLoaderPlugin()]
完整的webpack.config.js:
/**
* 此文件是webpack配置文件,用于指定webpack去执行哪些任务
*/
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { VueLoaderPlugin } = require("vue-loader");
const path = require('path');
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, 'dist'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: './js/bundle.js'
},
mode: 'development',
//1、所有的loader都要添加在module对象的rules中
//2、rules是一个数组,数组中的每一个对象就是一个loader
//3、loader特点:下载后无需引入,只需申明
module: {
rules: [{
test: /\.vue$/, //匹配所有less文件
use: 'vue-loader'
}, {
test: /\.less$/, //匹配所有less文件
use: [
'style-loader', //3、用于在html文档中创建一个style标签,将样式“塞”进去
'css-loader', //2、将less编译后的css转换为CommonJs的一个模块
'less-loader' //1、将less编译成为css,但不生成单独的css文件,在内存中
]
}, {
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}, {
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //按需引入需要使用polyfill
corejs: { version: 3 }, //解决不能找到core-js的问题
targets: { //解决兼容性处理哪些浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存
}
}
}, {
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
publicPath: './images', //决定图片的url路径
outputPath: 'images', //决定文件本地输出路径
name: '[hash:5].[ext]' //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
}]
},
plugins: [new VueLoaderPlugin()]
};
新建vue相关文件:
src/ App.vue:
{{message}}
src/index.js:
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App)
}).$mount('#app')
dist/index.html:
Document
最后使用”npm run build“ 命令编译后打开”dist/index.html“页面即可查看最终效果。
当配置文件写的越发繁杂时,发现生产环境的配置和开发环境配置有冲突。此时,我们希望有两套配置文件,一套用于开发环境,一套用于生产环境。这里使用js合并插件webpack-merge来实现配置文件的分离保存。
1、创建文件夹config,将webpack.config.js复制两份:
./config/webpack.dev.config.js
./config/webpack.prod.config.js
2、将原先的webpack.config.js改为webpack.base.config.js,然后分离代码:
cnpm i webpack-merge -D
//合并js插件
const{ merge } = require('webpack-merge')
//基础配置
const base = require('./base.config')
//开发环境配置
module.exports = merge(base,{
...
})
webpack.base.config.js:
// 路径
const path = require("path");
// html插件
const HtmlWebpackPlugin = require("html-webpack-plugin");
// 提取css为单独文件插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
// 入口文件
entry: "./src/js/index.js", // 由cmd执行目录决定
// 出口文件
output: {
path: path.resolve(__dirname, "../dist"), // 由当前文件所在位置和要生成的dist位置关系决定
filename: "./js/bundle.js"
},
// 模块解析
resolve: {
// 导入语句省略后缀
extensions: [".ts", ".js", ".json", ".css", ".less", ".scss"],
// 导入路径的别名
alias: {
css: path.resolve(__dirname, "./src/css")
},
// 解析模块目录
modules: [path.resolve(__dirname, "../node_modules"), "node_modules"]
},
// 模块
module: {
rules: [
{
test: /\.less$/, // 匹配所有less文件
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../"
}
},
"css-loader", // 2、将less编译后的css转换为CommonJs的一个模块
"less-loader" // 1、将less编译成为css,但不生成单独的css文件,在内存中
]
},
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 按需引入需要使用polyfill
corejs: { version: 3 }, // 解决不能找到core-js的问题
targets: {
// 解决兼容性处理哪些浏览器
chrome: "58",
ie: "9"
}
}
]
],
cacheDirectory: false // 开启babel缓存,只编译未编译代码,可减少编译时间
}
}
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: "url-loader", //url-loader依赖file-loader,使用了url-loader后file-loader可以不用
options: {
limit: 8192, //url-loader能将小于8k图片编译成base64,大的采用file-loader处理
//publicPath: "./images", //决定图片的url路径,less处设置了,此处就不需要了,不然html中的图片路径会出错
outputPath: "./images", //决定文件本地输出路径
name: "[hash:5].[ext]" //修改文件名称,[hash:5]取hash值前5位,[ext]文件扩展名
}
}
]
},
{
test: /\.(html)$/,
use: {
loader: "html-loader" // html-loader找到图片后自动交给url-loader处理
}
}
]
},
//插件
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
minify: {
removeComments: true, // 是否移除注释 默认 false
collapseWhitespace: true, // 是否去除空格,默认 false
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true
}
}),
new MiniCssExtractPlugin({
filename: "css/[name].css"
})
]
};
webpack.dev.config.js
// 合并js插件
const { merge } = require("webpack-merge");
// 公共基础配置
const base = require("./webpack.base.config");
// 开发环境配置
module.exports = merge(base, {
// devServer
devServer: {
open: true,
compress: true,
port: 8080,
stats: "minimal", //迷你型服务启动信息
// 代理
proxy: {
"/api": {
target: "https://cdn.ycku.com",
changeOrigin: true,
pathRewrite: {
"^/api": ""
}
}
}
},
// devTool
devtool: "eval-source-map",
// 开发模式
mode: "development"
});
webpack.prod.config.js:
// 合并js插件
const { merge } = require("webpack-merge");
// 公共基础配置
const base = require("./webpack.base.config");
// css压缩插件
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
// 清理打包目录插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = merge(base, {
//devTool
devtool: "source-map",
//生产模式
mode: "production",
//监听
watch: true,
//监听选项,当true时才有效
watchOptions: {
//不监听解析模块目录
ignored: /node_modules/,
//更新频率
aggregateTimeout: 500,
//轮询
poll: 1000
},
plugins: [
new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: [
"default",
{
discardComments: {
removeAll: true
}
}
]
},
cssProcessorOptions: {
map: {
inline: false,
annotation: true
}
}
}),
new CleanWebpackPlugin()
]
});
修改package.json的指令:
"dev": "webpack-dev-server --open chrome --port 3000 --config ./config/webpack.dev.config.js",
"start": "webpack-dev-server --open chrome --port 3000 --config ./config/webpack.dev.config.js",
"build": "webpack --config ./config/webpack.prod.config.js"
npm start
npm run dev
npm run build
生产环境代码需要部署到服务器上才能运行,serve这个库能够快速帮我们搭建一个静态资源服务器:
npm i serve -g
serve -s build -p 5000
path:仅告诉Webpack打包结果存储位置,必须是绝对路径。
outputPath:仅告诉各插件所生成文件的存放位置,该位置以path设置路径为基础,比如:output输出的js、url-loader解析的图片、HtmlWebpackPlugin生成的html文件都会存放在以path为基础的目录下。
publicPath:并不会对生成文件的路径造成影响,主要是在生产模式下,对你的页面里面引入的资源的路径做对应的补全,常见的就是css文件里面引入的图片、html文件里的url值补全。
请注意观察如下webpack.base.config.js文件中publicPath、outputPath及单独css文件夹设置:
项目路径
webpack.base.config.js:
const path = require('path')
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') //压缩 css
module.exports = {
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, '../dist'), // 由当前文件所在位置和要生成的dist位置关系决定
filename: 'js/bundle.js'
},
resolve: {
//导入语句省略后缀
extensions: ['.ts', '.js', '.json'],
//导入路径的别名
alias: {
css: path.resolve(__dirname, './src/css')
},
//解析模块目录
// modules: [path.resolve(__dirname, '../node_modules'), 'node_modules']
},
module: {
rules: [
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
'css-loader',
'less-loader'
]
},
{
test: /\.m?js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
"presets": [
["@babel/preset-env", {
useBuiltIns: "usage", //按需引入需要使用polyfill
corejs: { version: 3 }, //解决不能找到core-js的问题
targets: { //解决兼容性处理哪些浏览器
"chrome": "58",
"ie": "9"
}
}]
],
"cacheDirectory": false // 开启babel缓存,只编译未编译代码,可减少编译时间
}
}
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
limit: 8192,
outputPath: 'images',
name: '[hash:5].[ext]'
}
}
},
{
test: /\.(html)$/,
use: {
loader: 'html-loader'
}
},
{
test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4)$/,
use: [{
loader: 'file-loader',
options: {
outputPath: 'media',
name: '[hash:5].[ext]'
}
}]
}
]
},
plugins: [new HtmlWebpackPlugin({
template: "./src/index.html", // 以当前文件为模板创建新的html(1、结构和原来一样;2、会自动引入打包的资源),默认 ,路径由cmd执行目录决定
filename: "index.html", // 打包后的index.html文件默认位于dist目录下
minify: {
removeComments: true, //去掉注释
collapseWhitespace: true, //去掉空格
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
}
}), new MiniCssExtractPlugin({
filename: 'css/[name].css'
}), new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: [
'default',
{
discardComments: {
removeAll: true
},
},
]
},
cssProcessorOptions: {
map: {
inline: false,
annotation: true
}
}
})]
}
entry: './src/js/index.js', // 由cmd执行目录决定
output: {
path: path.resolve(__dirname, '../dist'), // 由当前文件(webpack.config.js)所在位置和要生成的dist位置关系决定
filename: 'js/bundle.js'
}
1、明确生成的dist目录结构,比如./dist/images、./dist/css、./dist/js、./dist/index.html,根据此目录结构来确定配置文件中配置项publicPath的路径。
如果是开发模式,则是./images、./css、./js、./index.html结构。
https://gitee.com/duansamve/webpack4-to-cli.githttps://gitee.com/duansamve/webpack4-to-cli.git