1.创建webpack环境:这里是局部安装,只限于本项目。
(1)mkdir studyReact
(2)cd studyReact
(3)npm init
package name:webpack-get-started
license:MIT
生成package.json
(4)npm install webpack webpack-cli -D
(5)如果想要在项目中使用npm run build命令,
①配置
"scripts":{
"build":"webpack --mode production"
}
②新建src目录,在目录下新建index.js
③执行npm run build会在根目录下生成dist目录,目录中有main.js文件
注:如果使用的是"webpack --mode development"打包之后的代码不会被压缩
2.配置更多webpack,需要在根目录新建webpack.config.js文件(不要问为什么取这个名字,现在知道这个名字就行啦,会自动读取内容配置webpack)
const path = require('path');
module.exports = {
entry: './src/index.js', // 文件入口
output: { // 文件出口
path: path.resolve(__dirname,'dist2'), // 文件出口目录路径
filename:'index.js', // 文件出口文件名
}
}
①配置多文件入口
entry: {
main:'./src/main.js',
index: './src/index.js',
}
结果:会在dist目录下生成main.js和index.js文件
注意:如果多入口单出口就会报错,所以此时的output应该配置为
output: { // 文件出口
path: path.resolve(__dirname,'dist2'), // 文件出口目录路径
filename:'[name].js', // 文件出口文件名
}
或者
output: { // 文件出口
path: path.resolve(__dirname,'dist2'), // 文件出口目录路径
}
②为filename添加hash值
output: { // 文件出口
path: path.resolve(__dirname,'dist2'), // 文件出口目录路径
filename:'[name].[hash].js', // 文件出口文件名
}
结果:会在dist2目录下生成类似于 home.0f83e169b1d1e4e2260b.js文件
弊端:此hash值会作用于整个webpack,一个文件的修改会让整个目录下的hash值修改。
如果要让每个文件的hash值不一样,使用chunkHash
注意:
output: { // 文件出口
path: path.resolve(__dirname,'dist2'), // 文件出口目录路径
filename:'[name].[hash:6].js', // 文件出口文件名
}
结果:hash值会被截断
③指定webpack.config.js目录
在package.json中配置
"scripts": {
"build":"webpack --mode production --config scripts/webpack.config.prod.js",
},
2.配置一个基础开发环境
①让webpack自身生成html文件,无需手动生成
第一步:npm install --save-dev html-webpack-plugin
第二步:配置webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js', // 文件入口
output: { // 文件出口
path: path.resolve(__dirname,'dist'), // 文件出口目录路径
filename:"[name].[hash:8].js", // 文件出口文件名
},
plugins:[
new HtmlWebpackPlugin()
]
}
执行 npm run build会在dist目录下生成index.html文件
注意:如果要指定index.html文件应该怎么办?
第一步:在根目录下创建index.html文件
注意:html文件的title标签内容应该修改为
<title><%= htmlWebpackPlugin.options.title %></title>
这样title才会是HtmlWebpackPlugin中配置的title
第二步:配置
plugins:[
new HtmlWebpackPlugin({
title:'webpack',
template:'./src/index.html',
filename:'index.html',
minify:{ // 压缩html文件
removeAttributeQuotes: true, // 删除双引号
collapseInlineTagWhitespace: true, //压缩变成一行
},
hash: true, // 引用js文件添加hash值
})
]
②让webpack编译css文件
第一步:npm install --save-dev css-loader
npm install style-loader -D
第二步:配置webpack.config.js
module:{
rules:[
{
test:/\.css$/,
use:[
'style-loader', // 主要解析@import语法
'css-loader' // 把css插入到head标签中
]
}
]
},
结果:执行npm run build会生成.html和.js文件
问:如何生成独立的css文件,让html文件link引入
第一步:npm install --save-dev mini-css-extract-plugin
第二步:
const MinCssExtractPlugin = require('mini-css-extract-plugin'); // 生成独立的css文件
plugins:[
new HtmlWebpackPlugin({
title:'webpack',
template:'index.html'
}),
new MinCssExtractPlugin({
filename:'[name].css'
}),
]
修改
rules:[
{
test:/\.css$/,
use:[
'style-loader',
'css-loader'
]
}
]
为:
rules:[
{
test:/\.css$/,
use:[
MinCssExtractPlugin.loader,
'css-loader'
]
}
]
问:如果让写在html文件中的样式起作用怎么办?
module:{
rules:[
{
test:/\.css$/,
use:[
{ // 主要解析@import语法
loader:'style-loader',
options:{
insert:'top' // 插入到header标签中的最上面
}
},
'css-loader' // 把css插入到head标签中
]
}
]
},
③启动一个开发服务器,同时实现热加载
npm install webpack-dev-server --save-dev
在package.json中添加
"scripts": {
"build": "webpack --mode production",
"dev": "webpack-dev-server --mode development",
},
执行npm run dev
在浏览器中输入http://localhost:8080/ 访问
问:如何配置端口相关的信息?
在webpack.config.js中配置
devServer:{
port: 3000, // 端口
open: true, // 自动打开浏览器
progress: true, // 显示进度
contentBase: './dist', // 打包之后的只是文件夹,这个属性帮助找到index.html文件
compress: true,
}
3.配置css预处理(less scss)
①如何处理less
第一步:npm install less-loader less --save-dev
第二步:在webpack.config.js中配置
rules:[
{
test:/\.css$/,
use:[
MinCssExtractPlugin.loader,
'css-loader'
]
},
{
test:/\.less$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
}
],
问:如果css需要使用某些特定的前缀怎么办,如::placeholder{color: red;}
第一步:npm install postcss-loader autoprefixer -D
[npm i -D postcss-load-config
npm install cosmiconfig] 我的电脑需要安装这两个
第二步:配置webpack.config.js
rules:[
{
test:/\.css$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
]
},
{
test:/\.less$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader:'less-loader',
options:{
}
},
]
}
],
第三步:在根目录下新建postcss.config.js
内容为:
module.exports={
plugins:[
require('autoprefixer')
]
}
第四步,在package.json中配置
"browserslist": [
"cover 99.5%"
]
②如何处理scss?
第一步:npm install node-sass sass-loader --save-dev
第二步:在webpack.config.js中配置
rules:[
{
test:/\.css$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
]
},
{
test:/\.less$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader:'less-loader',
options:{
}
},
]
},
{
test:/\.scss$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader:'sass-loader',
options:{
}
},
]
}
],
③如何压缩css文件
第一步:npm install optimize-css-assets-webpack-plugin --save-dev
npm install uglifyjs-webpack-plugin --save-dev
第二步:配置webpack.config.js
module.exports = {
optimization:{ // 优化项
minimizer:[
new UglifyjsWebpackPlugin( // 压缩js
{
cache: true,
parallel: true,
sourceMap: true
}
),
new OptimizeCssAssetsWebpackPlugin() // 压缩css
]
}
}
4.处理图片文件
第一步:npm install file-loader --save-dev
npm install url-loader --save-dev
第二步:在webpack.config.js中配置
rules:[
{
test:/\.css$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
]
},
{
test:/\.less$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader:'less-loader',
options:{
}
},
]
},
{
test:/\.scss$/,
use:[
MinCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
{
loader:'sass-loader',
options:{
}
},
]
},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
options:{
name:'static/images/[name].[ext]',
publicPath:'/',
}
},
或者:
{
loader: 'url-loader',
options:{
limit:512,
name:'static/images/[name].[ext]',
publicPath:'/',
}
},
],
},
],
问:如果要在index.html文件中引入图片怎么办?
第一步:npm install html-withimg-loader --save-dev
第二步:在webpack.config.js中配置
{
test: /\.(png|jpe?g|gif)$/i,
use:{
loader:'file-loader',
options: {
esModule: false, //非常重要
},
}
},
{
test: /\.html$/,
use:{
loader:'html-withimg-loader'
},
}
5.处理静态文件,如字体图标,无需编译直接复制即可
第一步:npm install copy-webpack-plugin --save-dev
第二步:
const CopyPlugin = require('copy-webpack-plugin');
在webpack.config.js中配置
plugins:[
new CopyPlugin([
{
from: path.resolve(process.cwd(),'src/static/'),
to: path.resolve(process.cwd(),'dist/static/')
}
]),
],
6.处理js文件
第一步:npm install -D babel-loader @babel/core @babel/preset-env
npm install @babel/plugin-proposal-class-properties -D //可以解析类语法
npm install @babel/plugin-transform-runtime -D //可以解析部分es7语法,如es7
npm install @babel/runtime --save-dev
第二步:在webpack.config.js中添加一条rules
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
include: path.resolve(__dirname, 'src'), // 只编译src目录下的js文件
use: {
loader: 'babel-loader',
options:{
presets:[
'@babel/preset-env'
],
plugins:[
'@babel/plugin-proposal-class-properties'
]
}
}
}
注意:可以根据不同的环境配置不同的webpack
在package.json中配置
"scripts": {
"build": "webpack --mode production --config webpack.config.prod.js", // 生产环境
"dev": "webpack-dev-server --mode development --config webpack.config.dev.js" // 开发环境
},
问:如何加上语法校验(即eslint)
第一步:npm install eslint eslint-loader -D
第二步:下载eslinttrc.json(下载地址:https://eslint.org/demo)
第三步:修改文件名eslinttrc.json为.eslinttrc.json,放在根目录下
第四步:配置webpack.config.js
{
test:/\.js$/,
use:{
loader:'eslint-loader',
options:{
enforce:'pre', //保证在编译js之前执行
}
}
}
6.全局变量引用问题,以jQuery为例,如何将 暴 露 给 全 局 , 使 用 w i n d o w . 暴露给全局,使用window. 暴露给全局,使用window.
第一步:npm install jquery
第二步:在js文件中
import $ from 'expose-loader?$!jquery';
console.log(window.$);
第三步:npm install expose-loader
问:在js文件中写成这样很丑怎么办?可以简写成import $ from 'jquery';吗?
可以在webpack.config.js中配置
rules:[
{
test:require.resolve('jquery'),
use:'expose-loader?$'
}
]
然后js中引用变为
import $ from 'jquery';
console.log(window.$);
问:可以直接简写成$吗?不用引入直接console.log($)
第一步:注释上步配置
{
test:require.resolve('jquery'),
use:'expose-loader?$'
},
第二步:
在webpack.config.js中配置
const webpack = require('webpack');
new webpack.ProvidePlugin({ // 在每个模块中都注入$
$:'jquery'
})
问:还有什么不用配置的方法可以使用console.log($)吗?
前提:注释掉上步配置
第一步:在index.html中引入<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
第二步:在index.js中写入
import $ from 'jquery';
console.log($);
第三步:在webpack.config.js中配置
module.exports = {
externals:{ // 这样在index.js文件中引入jQuery就不会被打包
jquery:'$'
},
}
问:loader有哪些分类?
(1)内联loader,如expose-loader
(2)pre loader,在普通loader前面执行
(3)normal loader,普通loader
(4)post loader,在普通loader后面执行
7.如何配置多页面应用?
其他设置都不变,修改的内容如下:
module.exports = {
entry: { // 配置多页应用
other: './src/other.js',
index: './src/index.js',
},
output: { // 文件出口
path: path.resolve(__dirname,'dist'), // 文件出口目录路径
filename:'[name].[hash].js', // 文件出口文件名
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
minify:{ // 压缩html文件
removeAttributeQuotes: true, // 删除双引号
collapseInlineTagWhitespace: true, //压缩变成一行
},
hash: true, // 引用js文件添加hash值
chunks:['index'] // 代表只加载index.js
}),
new HtmlWebpackPlugin({
template:'./src/other.html',
filename:'other.html',
minify:{ // 压缩html文件
removeAttributeQuotes: true, // 删除双引号
collapseInlineTagWhitespace: true, //压缩变成一行
},
hash: true, // 引用js文件添加hash值
chunks:['other']
}),
],
}
8.如果文件有代码报错,如何快速定位到报错的位置?
四种方式:
在webpack.config.js中配置:
1) devtool:'source-map':会单独生成一个sourcemap文件,会显示出来报错的行和列
2) devtool:'eval-source-map':不会单独生成一个sourcemap文件,但是可以显示行和列
3) devtool:'cheap-module-source-map':不会产生列,但是可以单独生成一个sourcemap文件
4) devtool:'cheap-module-eval-source-map':不会产生列,也不会生成sourcemap文件,它会集成在打包之后的文件中
9.实时打包
在webpack.config.js文件中配置
module.exports = {
watch:true,
watchOptions:{
poll: 1000, // 每秒询问1000次
aggreateTimeout: 500, // 防抖 改动代码的500毫秒内不打包
ignored: /node_modules/
}
}
10.如何每次打包生成最新的dist文件目录?即没有缓存
第一步:npm install clean-webpack-plugin -D
第二步:在webpack.config.js中配置
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
plugins:[
new CleanWebpackPlugin(), // 默认清除的是output文件夹
]
10.webpack解决请求跨域问题(例:webpack端口为8080请求node服务端口3000)
devServer:{
proxy:{
'/api':{
target:'http://localhost:3000', // 配置代理,以api开头的请求全部转换为http://localhost:3000
pathRewrite:{'/api':''},
}
}
},
问:如果只想单纯的模拟数据怎么办?
devServer:{
before(app){
app.get('/api/user',(req,res)=>{
res.json({name:'wq',age:20});
})
}
}
问:可不可以不使用转发,在后端服务启动webpack端口?
第一步:npm install webpack-dev-middleware -D
第二步:在server.js中写入
// 模拟服务端
let express = require('express');
let webpack = require('webpack');
let app = express();
// 中间件
let middle = require('webpack-dev-middleware');
let config = require('./webpack.config.js');
let compiler = webpack(config);
app.use(middle(compiler));
app.get('/user',(req,res)=>{
res.json({name:'wq',age:20});
})
app.listen(3000);
第三步:执行node server.js,在浏览器中输入http://localhost:3000
11.resolve属性的配置(待更新。。。)
resolve:{
extensions:['*', '.js', '.jsx'], // 在引入文件的时候如果不写后缀,默认去找js结尾再去找css结尾的文件
// 配置路径别名
alias:{
components: path.join(__dirname, 'src/components'), // 在引入时无需写全路径
},
},
12.定义环境变量
new webpack.DefinePlugin({
DEV:JSON.stringify('dev')
})
13.区分不同的环境(配置开发环境和生产环境的webpack)
第一步:npm install webpack-merge -D
第二步:在根目录下新建webpack.dev.js和webpack.prod.js两个文件
let {smart} = require('webpack-merge');
let base = require('./webpack.base.js');
module.exports = smart(base,{
mode:'production',
optimization:{ // 优化项
minimizer:[
new UglifyjsWebpackPlugin( // 压缩js
{
cache: true,
parallel: true,
sourceMap: true
}
),
new OptimizeCssAssetsWebpackPlugin() // 压缩css
]
},
})
第三步:修改webpack.config.js文件名为webpack.base.js
第四步:修改package.json文件
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "webpack-dev-server --config webpack.config.js"
},
14.使用多线程打包
第一步:npm install happypack
第二步:配置webpack.config.js
rules:[
{
test:/\.js$/,
exclude: /node_modules/,
include: path.resolve(__dirname, 'src'), // 只编译src目录下的js文件
use: 'HappyPack/loader?id=js'
},
]
plugins:[
new HappyPack({
id:'js',
use:[
{
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
'@babel/preset-react'
],
plugins:[
'@babel/plugin-proposal-class-properties',
'@babel/plugin-transform-runtime'
]
}
}
]
})
]
15.在多入口文件中打包时提取抽离公共代码
optimization:{ // 优化项
splitChunks:{ // 分割公共代码
cacheGroups:{ // 缓存组
common:{ // 公共的模块
chunks:'initial',
minSize:0,
minChunks:2, // 公用超过两次
},
vender:{
priority:1, //增加权重
test:/node_modules/,
chunks:'initial',
minSize:0,
minChunks:2, // 公用超过两次
}
}
}
},
16.webpack的懒加载与热更新
1)懒加载
onClick = ()=>{
console.log('点击');
import('static/test.json').then(data =>{
console.log('data',data.default);
})
}
2)热更新
配置webpack.config.js
devServer:{
hot:true, // 启用热更新
}
plugins:[
new webpack.NamedModulesPlugin(), // 打印更新的模块路径
new webpack.HotModuleReplacementPlugin(), // 热更新
]
17.PWA:渐进式网络开发应用程序(离线可访问)
前提:npm install workbox-webpack-plugin
第一步:配置webpack.config.js
// PWA:离线加载应用
new WorkboxWebpackPlugin.GenerateSW({
// 1.帮助serviceworker快速启动 2.删除旧的servicework
clientsClaim: true,
skipWaiting:true
})
第二步:在入口文件配置(一般是index.js)
// 注册servicework
if ('serviceWorker' in navigator) {
window.addEventListener('load',()=>{
// /service-worker.js文件会自动生成,不用管它
navigator.serviceWorker.register('/service-worker.js')
.then(()=>{
console.log('sw注册成功')
})
.catch(()=>{
console.log('sw注册失败')
})
})
}
18.externals:用于排除一些引入的模块,不进行打包,引用外部的模块。
externals: {
vue: 'vue'
}
/--------------------------------------------------------------------------------------------------/
注:关于源码课程 https://www.bilibili.com/video/av51693431?p=28