2-1 loader
2-2使用loader打包静态文件
2-3 css模块化
2-4htmlWebpackPlugin
2-5 cleanWepackPlugin
2-6 entry和output
2-7 sourcemap
2-8 webpackDevServer
2-9 Hot Module Replacement
2-10 ES6语法转化
2-1loader
webpack只能默认处理js打包,打包其他的文件需要对应的loader(模块转换器),比如打包图片使用file-loader。//webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.jpg$/,
use: {
loader: 'file-loader',
options: {}
}
}]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}
2-2使用loader打包静态文件
[file-loader链接](https://www.webpackjs.com/loaders/file-loader/) ```javascript //webpack.config.js const path = require('path')module.exports = {
mode: ‘development’,
entry: {
main: ‘./src/index.js’
},
module: {
rules: [{
test: /(.jpg|png|gif)$/,
use: {
loader: ‘file-loader’,
//placehodles占位符
options: {’[name]_[hash].[ext]’},
outputpath: 'images/
}
}]
},
output: {
filename: ‘bundle.js’,
path: path.resolve(__dirname, ‘dist’)
}
}
## 样式文件打包
[loaders](https://www.webpackjs.com/loaders/)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200920234402735.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDQ5OTQ2NQ==,size_16,color_FFFFFF,t_70#pic_center)
css-loader:分析css文件之间的依赖。
style-loader:把css内容挂载到html的head上。
scss-loader node-sass:把scss文件转css
postcss-loader: 自动加厂商前缀,使用c3时需要
npm i autoprefixer -D
```javascript
//postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
const path = require('path')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader', 'postcss-loader']
}]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}
2-3 css模块化
css模块化的原因
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
createAvatar.js
import avatar from './avatar.jpg'
function createAvatar () {
var img = new Image();
img.src = avatar;
img.classList.add('avatar');
var root = document.getElementById('root');
root.append(img)
}
export default createAvatar;
//在这个文件中实例化了img标签
//index.js
var avatar = require('./avatar.jpg');
import './index.scss'
import createAvatar from './createAvatar';
**//执行createAvatar时会生成img标签,此时引入的index.scss会同时作用。
//所以相当于全局引用了,会污染代码,出现样式冲突问题,所以引入cssmodule**
createAvatar()
var img = new Image();
img.src = avatar.default;
img.classList.add('avatar');
var root = document.getElementById('root');
root.append(img);
//执行createAvatar时会生成img标签,此时引入的index.scss会同时作用。
//所以相当于全局引用了,会污染代码,出现样式冲突问题,所以引入cssmodule
css模块化的代码实现
const path = require('path')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//在引入css文件前先走下面连个loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}
上面在css-loader中加入了modules: true
var avatar = require('./avatar.jpg');
//1.引入index.css
import style from './index.scss';
import createAvatar from './createAvatar';
createAvatar()
var img = new Image();
img.src = avatar.default;
//2. style.avatar
img.classList.add(style.avatar);
var root = document.getElementById('root');
root.append(img);
2-4 htmlWebpackPlugin
- 作用
在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中。
const path = require('path')
// 引入HtmlWebpackPlugin
const 引入HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//在引入css文件前先走下面连个loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
// 以src下的index.html为模板构建
template: 'src/index.html'
})
]
}
------plugins 可以在webpack运行的某个时刻的时候,帮你做一些事情------
2-5 cleanWepackPlugin
- 作用
能在打包的时候不用每次手动清除之前的打包遗留,让插件帮助我们完成,但是这不是webpack官方推荐的插件。
const path = require('path')
// 引入HtmlWebpackPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//在引入css文件前先走下面连个loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
// 以src下的index.html为模板构建
template: 'src/index.html'
}),
// 使用此插件在我们打包前清除dist目录
new CleanWebpackPlugin()
]
}
2-6 entry和output
const path = require('path')
// 引入HtmlWebpackPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js',
sub: './src/index.js'
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//在引入css文件前先走下面连个loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
// 以src下的index.html为模板构建
template: 'src/index.html'
}),
// 使用此插件在我们打包前清除dist目录
new CleanWebpackPlugin()
],
output: {
// filename: 'bundle.js',
//配置cdn
publicPath: 'http://cdn.com.cn',
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
在打包多个文件的时候,由于entry可以有多个但是output只有一个,所以,在打包多个的时候output要使用占位符进行打包,与打包出来的文件一一对应,由于配置了htmlWebpackPlugin,打包好的js文件会直接在index.html被引用。
publicPath配置:可以使html引用的js文件加上cdn前缀。
2-7 sourcemap
演示没有sourcemap的情况
conle.log('hello world');
故意写错代码
const path = require('path')
// 引入HtmlWebpackPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
mode: 'development',
// 开发模式默认配置了sourcemap,现在手动关闭
devtool: 'none',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//在引入css文件前先走下面连个loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
// 以src下的index.html为模板构建
template: 'src/index.html'
}),
// 使用此插件在我们打包前清除dist目录
new CleanWebpackPlugin()
],
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
开发模式默认配置了sourcemap,现在通过devtool: 'none’手动关闭
结果:在浏览器中查看错误的时候能看到打包后的文件里的错误,我们希望能够知道源代码里错误的位置。
sourcemap
- 是一个映射关系,他知道dist目录下错误代码的位置对应了源代码的位置。
把配置文件改为devtool: 'soruce-map’即可。
此选项有很多配置,可参考devtool
最佳实践:
开发环境: cheap-module-eval-source-map
生成环境: cheap-module-source-map
2-8 webpackDevServer
在改了src目录下的源码码是dist目录能够自动打包,省去手动打包。实现这个有三种做法:
1.webpack --watch
{
"name": "webpackDemo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"bundle": "webpack",
"watch": "webpack --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^8.6.5",
"clean-webpack-plugin": "^3.0.0",
"file-loader": "^6.1.0",
"html-webpack-plugin": "^4.5.0",
"postcss-loader": "^4.0.2",
"style-loader": "^1.2.1",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"css-loader": "^4.3.0",
"node-sass": "^4.14.1",
"sass-loader": "^10.0.2"
}
}
npm run watch修改源代码后会自动打包。
2.webpackDevServer
第一种还不够好,我们希望自动打包完后能自动打开浏览器,开启服务器。
const path = require('path')
// 引入HtmlWebpackPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
devServer: {
contentBase: './dist',
open: true
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//在引入css文件前先走下面连个loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
// 以src下的index.html为模板构建
template: 'src/index.html'
}),
// 使用此插件在我们打包前清除dist目录
// new CleanWebpackPlugin()
],
output: {
// filename: 'bundle.js',
// publicPath: 'http://cdn.com.cn',
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
然后再在package.json中配置命令start: “webpack-dev-server”,npm start打包即可。
devServer: {
// 打包放置
contentBase: './dist',
// 自动打开
open: true
}
devserver配置项
3.手动创建文件
// package.json
"middleware": "node server.js"
需要用到服务器,故需安装express,中间件使用用到 webpack-dev-middleware
npm install express webpack-dev-middleware -D
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleWare = require('webpack-dev-middleware');
const config = require('./webpack.config');
// 进行代码编译,即webpack传入配置文件会返回一个编译器,编译一次重新打包一次
const complier = webpack(config);
const app = express();
app.use(webpackDevMiddleWare(complier, {
publicPath: config.output.publicPath
}))
app.listen(3000, () => {
console.log('server is running')
})
2-9Hot Module Replacement
// index.js
import './style.css'
var btn = document.createElement('button');
btn.innerHTML = '新增'
document.body.appendChild(btn)
btn.onclick = function () {
var div = document.createElement('div')
div.innerHTML = 'item'
document.body.appendChild(div)
}
在index.js中创建元素和点击事件,点击新增生成item,引用style.css.
// style.css
div:nth-of-type(odd) {
background: blue;
}
// webpack.config.js还是开启了devServer
const path = require('path')
// 引入HtmlWebpackPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
devServer: {
contentBase: './dist',
open: true
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//在引入css文件前先走下面连个loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
},{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
// 以src下的index.html为模板构建
template: 'src/index.html'
}),
// 使用此插件在我们打包前清除dist目录
// new CleanWebpackPlugin()
],
output: {
// filename: 'bundle.js',
// publicPath: 'http://cdn.com.cn',
publicPath: '/',
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
效果:在每次更改css里的代码后,浏览器就会重新刷新,我们已经点击生成的item也会丢失,我们希望只是在更改样式代码的时候浏览器只是更新样式,这就是热更新。
此时用到了HotModuleReplacementPlugin(),由于此插件是webpack内置的,需要先引入webpack,再在plugin里实例化此插件即可。(比对上面两个文件)
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const webpack = require('webpack')
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
devServer: {
contentBase: './dist',
open: true,
port: 8080,
hot: true,
hotOnly: true
},
module: {
rules: [{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
//placehodles占位符
options: {
// name: '[path][name].[ext]'
// outputPath: 'images/'
}
}
}, {
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
//在引入css文件前先走下面连个loader
importLoaders: 2,
modules: true
}
},
'sass-loader',
'postcss-loader'
]
},{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
}]
},
plugins: [
new HtmlWebpackPlugin({
// 以src下的index.html为模板构建
template: 'src/index.html'
}),
// 使用此插件在我们打包前清除dist目录
// new CleanWebpackPlugin()
new webpack.HotModuleReplacementPlugin()
],
output: {
// filename: 'bundle.js',
// publicPath: 'http://cdn.com.cn',
publicPath: '/',
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
}
Hot Module Replacement的另一种使用(热更新模块)
引出:
// src/counter.js
function counter () {
var div = document.createElement('div');
div.setAttribute('id', 'counter');
div.innerHTML = 1;
div.onclick = function () {
div.innerHTML = parseInt(div.innerHTML, 10) + 1
}
document.body.appendChild(div);
}
export default counter;
//src/number.js
function number () {
var div = document.createElement('div');
div.setAttribute('id', 'number');
div.innerHTML = 2000;
document.body.appendChild(div);
}
export default number;
同时,我们在上一个webpack.config.js上暂时关闭hot,与hotOnly
// hot: true,
// hotOnly: true
效果是我们点击使1增加时,然后去改动number.js的2000,会自动打包,而我们的1增加后的值也会刷新重置了,而我们想要的效果是改动number.js的代码只改动number.js的。
对比:
把上面的hot和hotOnly打开,即打开热更新,在修改了number.js的2000会重新打包,但浏览器上的值没有变化(刷新会重置),这时候我们需要用代码。
// index.js
import counter from './counter'
import number from './number'
counter()
number()
if (module.hot) {
module.hot.accept('./number', () => {
//即number文件发生变动时重新执行一次number
document.body.removeChild(document.getElementById('number'))
number();
})
}
这样的话就实现了我们的效果
其实cssloader和vue-loader等 底层也是实现了,所以不用手动实现。
2-10 ES6语法转化(Babel)
babel中文网
在这个链接里面首页的设置里面进去点击webpack,就会有配置介绍。
npm install --save-dev babel-loader @babel/core
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
// index.js
const arr = [
new Promise(() => {}),
new Promise(() => {})
];
arr.map((item) => {
console.log(item)
})
npm install @babel/preset-env --save-dev
只安装babel-loader不会转化代码,此loader只是打通了webpack与loader通讯而已,故还需要安装@babel/preset-env。
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
npx webpack
这样只翻译了一部分例如const=> var,我们还需要借助babel pollyfill工具帮助我们对变量或函数在低版本浏览器的补充
babel pollyfill
npm install --save @babel/polyfill
// index.js
import "@babel/polyfill"
const arr = [
new Promise(() => {}),
new Promise(() => {})
];
arr.map((item) => {
console.log(item)
})
按需填充
上面的配置会把所有的填充上去,为了减少体积,我们可以按需填充。
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [["@babel/preset-env",{
// 按需填充参数配置
useBuiltIns: 'usage'
}]]
}
}
还可以配置target等属性
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [["@babel/preset-env",{
targets: {
chrome: "67"
},
useBuiltIns: 'usage'
}]]
}
}
如果打包是一个库时,需要换一种配置,使用:
transform-runtime
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
// presets: [["@babel/preset-env",{
// targets: {
// chrome: "67"
// },
// useBuiltIns: 'usage'
// }]]
"plugins": [["@babel/plugin-transform-runtime",{
"corejs": false,
"helpers": true,
"regenerator": true,
"useESModules": false,
}]]
}
},
为了减少webpack.config.js的代码,可以把babel的配置放到.babelrc上
把上面的options放到.babelrc即可
// webpack.config.js
rules: [{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}
// .babelrc
{
"plugins": [["@babel/plugin-transform-runtime",{
"corejs": false,
"helpers": true,
"regenerator": true,
"useESModules": false,
}]]
}