webpack入門筆記

webpack的正確安裝

  1. mkdir webpack-demojavascript

  2. cd webpack-democss

  3. npm inithtml

    // package.json
    {
      +"private":true// 表明該文件不會被髮布到npm倉庫上去
      -"main":"index.js",//由於只是本身使用,因此不須要向外暴露入口文件
    }
    複製代碼
  4. npm install webpack webpack-cli -Djava

    在項目內安裝webpack而不是在全局安裝webpack,能夠保證不一樣項目依賴不一樣版本的webpack而不會出錯node

  5. 此時終端輸入webpack ,會提示找不到webpack ,這是由於node會去全局的目錄尋找webpackwebpack

    咱們可使用npx webpack,npx會幫助咱們在當前文件夾內尋找相應的安裝包css3

webpack配置

在沒有寫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
  }
}
複製代碼

執行打包命令後,終端輸出內容的含義

image-20191125170150927

Hash: 本次打包對應的惟一一個hash值

Version: 本次打包對應的webpack的版本號

Time: 打包的時間

Asset: 打包出的文件名

Size: 打包後的文件大小

Chunks: 存放文件的ID值,若是bundle.js 跟a文件有關聯,則會在此處記錄bundle文件和a文件的ID值

Chunk Name: 存放文件自己與關聯文件的名字

Entrypoint: 入口文件是哪個

列舉打包的源文件

webpack打包圖片

//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打包後的輸出目錄

屏幕快照 2019-11-25 下午5.03.21的副本 下午5.07.58

屏幕快照 2019-11-25 下午5.15.33

咱們會發現,頁面仍然是正常展現圖片的,但file-loader打包後,圖片的一個單獨的文件放在輸出目錄中,而url-loader打包後,則是將圖片變爲base64格式存放在bundle.js文件中

url-loader的優勢:減小了加載圖片的網絡請求,缺點,圖片過大時,會影響js文件的加載速度

解決,設置一個圖片大小的閥值 limit

options:{
  name:'[name].[ext]',
  outputPath:'images/',
  limit:2048 //單位字節
}
複製代碼

當圖片大小大於2048字節時,就會輸出爲單獨的文件,小於2048字節時,就會以base64格式存放在bundle.js中

loader打包靜態樣式

//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中

image-20191125171715079

打包scss文件

npm install style-loader css-loader sass-loader node-sass

module.exports = {
  module:{
    rules:[
      {
        test:/.scss$/,
        use:['style-loader','css-loader','sass-loader'],
      }
    ]
  }
}
複製代碼

注意loader是從下到上,從右到左到順序,便是有順序的

自動添加css3的前綴

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

css打包的模塊化

/*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)
複製代碼

使用plugins打包更加便捷

自動生成html文件

每次打包文件,咱們都須要在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運行到某個時刻的時候,幫你作一些事情

在從新打包時,將dist目錄先刪除,再打包

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()
  ]
}
複製代碼

Entry與Output的基本配置

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')
  }
}
複製代碼

sourceMap

有時代碼寫錯了,控制檯報錯,會指出打包後的文件的哪一行代碼錯誤,但咱們想知道的是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'
}
複製代碼

使用WebpackDevServer提高開發效率

每次改完代碼,都要打包後,再去刷新瀏覽器,這樣比較麻煩

咱們但願能夠改完代碼後,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

image-20191125155004853

這時,咱們去將index.css文件中的color變爲blue時

屏幕快照 2019-11-25 下午3.50.59

瀏覽器會自動刷新,致使以前的狀態消失,這不是咱們要的,因此須要熱模塊更新

//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',
  }
}
複製代碼

image-20191125160500343

咱們把數字點擊到6,而後去修改b.js的代碼,歡迎改成再見

image-20191125163705806

瀏覽器會從新刷新,以前的全部狀態所有沒有了。想要只刷改變的那一部分,應該這樣寫

//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

相關文章
相關標籤/搜索