mkdir webpack-demo
javascript
cd webpack-demo
css
npm init
html
// package.json
{
+"private":true// 表明该文件不会被发布到npm仓库上去
-"main":"index.js",//由于只是本身使用,因此不须要向外暴露入口文件
}
复制代码
npm install webpack webpack-cli -D
java
在项目内安装webpack而不是在全局安装webpack,能够保证不一样项目依赖不一样版本的webpack而不会出错node
此时终端输入webpack
,会提示找不到webpack ,这是由于node会去全局的目录寻找webpackwebpack
咱们可使用npx webpack
,npx会帮助咱们在当前文件夹内寻找相应的安装包css3
在没有写webpack的配置文件时,执行npx webpack index.js
,webpack会根据默认配置帮咱们进行打包web
但当咱们新建一个webpack.config.js
文件时,webpack则会根据咱们写的配置文件进行打包npm
//webpack.config.js
const path. = require('path');
module.exports = {
mode:'production',//打包的模式。生产环境下会压缩代码,development则不糊压缩
entry:'./index.js',// 入口文件
output:{
filename:'bundle.js',//打包后的文件名
path:path.resolve(__dirname,'bundle')// 打包后的 文件目录
}
}
复制代码
指定webpack以哪一个配置文件来打包json
npx webpack --config 文件名.js
简化打包的命令行指令
//package.json
{
"scripts":{
"bundle":"webpack"//以后执行命令行npm run bundle === npx webpack
}
}
复制代码
Hash: 本次打包对应的惟一一个hash值
Version: 本次打包对应的webpack的版本号
Time: 打包的时间
Asset: 打包出的文件名
Size: 打包后的文件大小
Chunks: 存放文件的ID值,若是bundle.js 跟a文件有关联,则会在此处记录bundle文件和a文件的ID值
Chunk Name: 存放文件自己与关联文件的名字
Entrypoint: 入口文件是哪个
列举打包的源文件
//index.js
import avatar from './avatar.jpg'
console.log(avatar)//avatar132425454.jpg
复制代码
webpack默认是能够打包j s文件的,但对于怎么打包图片确实不知道的,因此咱们须要在配置文件中告诉webpack怎么去打包图片,这就须要用到loader,loader就是一个打包的方案
npm install file-loader
//webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\.jpg$/,
use:{
loader:'file-loader'
}
}
]
}
}
复制代码
打包完后,会发现图片的名字改变了,若是想让图片的名字不改变,咱们能够给file-loader添加参数
// webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\.(jpg|png|gif)$/ //对以jpg,png,gif结尾的文件进行打包
use:{
loader:'file-loader',
options:{
name:'[name]_[hash].[ext]',
//[name]是源文件的名字,[hash]是哈希值,不须要能够删除,[ext]是源文件的后缀名
outputPath:'images/' //打包到哪一个目录文件下
}
}
}
]
}
}
复制代码
与file-loader类似的还有url-loader
npm install url-loader -D
//webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\.(jpg|png|gif)$/
use:{
loader:'url-loader',
options:{
name:'[name].[ext]',
outputPath:'images/'
}
}
}
]
}
}
复制代码
对比file-loader和url-loader打包后的输出目录
咱们会发现,页面仍然是正常展现图片的,但file-loader打包后,图片的一个单独的文件放在输出目录中,而url-loader打包后,则是将图片变为base64格式存放在bundle.js文件中
url-loader的优势:减小了加载图片的网络请求,缺点,图片过大时,会影响js文件的加载速度
解决,设置一个图片大小的阀值 limit
options:{
name:'[name].[ext]',
outputPath:'images/',
limit:2048 //单位字节
}
复制代码
当图片大小大于2048字节时,就会输出为单独的文件,小于2048字节时,就会以base64格式存放在bundle.js中
//index.js
import './index.css'
复制代码
当咱们在js文件中引入c s s文件时,webpack打包时会提示错误,这时候就须要loader来帮忙了
npm install style-loader css-loader -D
//webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
}
}
复制代码
那css-loader和style-loader的做用分别是什么呢
css-loader负责处理css文件之间的关系
/*a.css*/
body{
background-color:blue
}
复制代码
/*b.css*/
import './a.css'
复制代码
//index.js
import './b.css'
复制代码
style-loader则是将解析完毕的css挂载到header中
npm install style-loader css-loader sass-loader node-sass
module.exports = {
module:{
rules:[
{
test:/.scss$/,
use:['style-loader','css-loader','sass-loader'],
}
]
}
}
复制代码
注意loader是从下到上,从右到左到顺序,便是有顺序的
npm install postcss-loader autoprefixer -D
在根目录下新建文件postcss.config.js
//postcss.config.js
module.exports = {
plugins:[
require('autoprefixer')
]
}
复制代码
//webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\scss$/,
use:['style-loader','css-loader','sass-loader','postcss-loader']
}
]
}
}
复制代码
module.exports = {
module:{
rules:[
'style-loader',
{
loader:'css-loader',
options:{
importLoaders:2
}
},
'sass-loader',
'postcss-loader'
]
}
}
复制代码
importLoaders:2指引入的sass文件也要去执行posts-loader和sass-loader
/*index.scss*/
import './a.scss'
body{
#root{
color:red;
}
}
复制代码
/*a.scss*/
...
复制代码
//index.js
import './index.scss'
复制代码
webpack去解析index.scss时会通过postcss-loader,sass-loader,css-loader,接着会去解析引入的a.scss,若是咱们但愿引入的的a.scss也要通过postcss-loader,sass-loader时,就要在cs s-loader的options参数中加上importloaders:2
/*a.scss*/
body{
.title{
color:red
}
}
复制代码
// index.js
import './a.scss'
复制代码
当我全局引入a.scss文件时,就会使得全局的title类名的元素文字颜色都变为红色。
因而咱们要引入一个css模块化概念
//webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\.scss$/,
use:[
'style-loader',
{
loader:'css-loader',
options:{
importLoaders:2,
modules:true,// 变为模块化打包
}
},
'sass-loader',
'postcss-loader'
]
}
]
}
}
复制代码
//index.js
import style from './a.scss'
var span = document.createElement('span')
span.innerText='你好'
span.classList.add(style.title)//样式只会影响这个元素,而其余类名为title元素则不会受影响
var root = document.getElementById('root')
root.append(span)
复制代码
每次打包文件,咱们都须要在dist文件夹中新建一个html文件,而后引入打包后的j s文件,这是很是麻烦的
如今咱们推荐使用
html-webpack-plugin
使得打包更便捷
npm install -D htm-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
plugins:[
new HtmlWebpaclPlugin()
]
}
复制代码
htmlwebpackplugin会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中
打包后,咱们会发现webpack自动生成的html文件缺乏一个id为root的div
若是咱们但愿webpack打包后自动生成一个id为root的div,咱们能够给HtmlWebpackPlugin一个模版
//webpack.config.js
module.exports = {
plugins:[
new HtmlWebpackPlugin({
template:'src/index.html'//模版文件
})
]
}
复制代码
plugin能够在webpack运行到某个时刻的时候,帮你作一些事情
npm install -D clean-webpack-plugin
//webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
plugins:[
new HtmlWebpackPlugin({
template:'src/index.html'
}),
new CleanWebpackPlugin()
]
}
复制代码
module.exports = {
entry:{
key1:path1,
key2:path2
}
output:{
filename:xxx.js
path:path.resolve(__dirname,'dist')
}
}
复制代码
key1与key2,表明打包输出的文件名,path1与path2表明要打包文件的路径
filename也表明打包输出的文件名,单filename与key冲突时,会报错,当有两个key,而filename只有一个时,也会报错,建议修改以下
module.exports = {
entry:{
main:'./src/main.js',
other:'./scr/other.js'
},
output:{
filename:'[name].js'//用[name]做为占位符,这样打包输出的文件名就会是entry中的key值
path:path.resolve(__dirname,'dist')
}
}
复制代码
有时代码写错了,控制台报错,会指出打包后的文件的哪一行代码错误,但咱们想知道的是src目录下的哪一个文件的哪行代码错误。这时候就须要
sourceMap
module.exports = {
devtool:'source-map'
}
复制代码
sourceMap其实就是一个映射关系
devtool | build | rebuild | production | quality |
---|---|---|---|---|
(none) | fastest | fastest | yes | bundled code |
eval | fastest | fastest | no | generated code |
cheap-eval-source-map | fast | faster | no | transformed code (lines only) |
cheap-module-eval-source-map | slow | faster | no | original source (lines only) |
eval-source-map | slowest | fast | no | original source |
cheap-source-map | fast | slow | yes | transformed code (lines only) |
cheap-module-source-map | slow | slower | yes | original source (lines only) |
inline-cheap-source-map | fast | slow | no | transformed code (lines only) |
inline-cheap-module-source-map | slow | slower | no | original source (lines only) |
source-map | slowest | slowest | yes | original source |
inline-source-map | slowest | slowest | no | original source |
hidden-source-map | slowest | slowest | yes | original source |
nosources-source-map | slowest | slowest | yes | without source content |
开发环境建议这么配置
module.exports = {
devtool:'cheap-module-eval-source-map'
}
复制代码
生产环境
module.exports = {
devtool:'cheap-module-source-map'
}
复制代码
每次改完代码,都要打包后,再去刷新浏览器,这样比较麻烦
咱们但愿能够改完代码后,webpack自动打包,而后自动刷新浏览器
想实现这样的功能,有两个方法
1
{
"scripts":{
"watch":"webpack --watch"//webpack会去监听要打包的文件,当文件发生变化,就会自动去打包
}
}
复制代码
2
npm install -D webpack-dev-server
借助WebpackDevServer
来监听文件变化并打包,自动打开并刷新浏览器
//webpack.config.js
module.exports = {
devServer:{
contentBase:'./dist'//服务器的根路径就是在dist目录下,
open:true,//会自动打开浏览器,并去访问相应的服务器
proxy:{
'/api','http://localhost:3000'//支持跨域,当访问api时,会转发到localhost:3000
}
}
}
复制代码
{
"scripts":{
"start":'webpack-dev-server'
}
}
复制代码
使用webpack-dev-server 时。你会发现,如今没有dist目录了 ,这是由于webpack-dev-server将打包后后的文件放在了电脑的缓存中
当咱们改变样式代码时,浏览器会刷新,以前的状态就会消失,这不是咱们想要的,咱们但愿,咱们改变样式代码时,浏览器不会自动刷新
// index.js
import './index.css'
var btn = document.createElement('div')
btn.innerText = '点击我'
btn.onclick = ()=>{
var div = document.createElement('div')
div.classList.add('item')
div.innerText='item'
document.body.appendChild(div)
}
复制代码
.item:nth-of-type(odd){
color:red
}
复制代码
点击几回,就会出现多个item
这时,咱们去将index.css文件中的color变为blue时
浏览器会自动刷新,致使以前的状态消失,这不是咱们要的,因此须要热模块更新
//webpack.config.js
const webpack = require('webpack')
module.exports = {
devServer:{
contentBase:'./dist',
open:true,
port:8080,
hot:true,//热模块替换
hotOnly:true,//即便html不生效,浏览器也不自动刷新,能够不加
},
plugins:[
new webpack.HotModuleReplacementPlugin()
]
}
复制代码
js代码的热更新
//a.js
var num = 0;
function number(){
var btn = document.createElement('div')
btn.setAttribute('id','number')
btn.innerText = num;
btn.onclick = ()=>{
num++1;
btn.innerText = num
}
document.body.appendChild(btn)
}
export default number;
复制代码
//b.js
function show (){
var div = document.createElement('div')
div.innerText = '欢迎'
document.body.appendChild(div)
}
export default show
复制代码
//index.js
import number from './a'
import show from './b'
show()
number()
复制代码
//webpack.config.js
module.exports = {
devServer:{
hot:true,
contentBase:'./dist',
}
}
复制代码
咱们把数字点击到6,而后去修改b.js的代码,欢迎改成再见
浏览器会从新刷新,以前的全部状态所有没有了。想要只刷改变的那一部分,应该这样写
//index.js
import number from './a'
import show from './b'
show()
number()
if(module.hot){// 监测热更新,
module.hot.accept('./a',()=>{
//先删除以前的dom
ducument.body.removeChild(document.getElementById('number'))
//再从新执行一次
number()
})
}
复制代码
若是以为文章不错,请点个赞,有错漏处,还请各位看官指正
若是要转载,请注明出处
做者:胡志武
时间:2019/11/25