從0搭建自己的webpack開發(fā)環(huán)境(wepack4.0以上)

源碼地址:https://github.com/h2huanghui/WEBPACK-BASE

一葵蒂、概念

webpack 是一個(gè)現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包器(module bundler)。當(dāng) webpack 處理應(yīng)用程序時(shí)重虑,它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖(dependency graph)践付,其中包含應(yīng)用程序需要的每個(gè)模塊,然后將所有這些模塊打包成一個(gè)或多個(gè) bundle缺厉。


webpack.png

1. 使用Webpack作為前端構(gòu)建工具

  • 代碼轉(zhuǎn)換:TS->JS,SCSS->CSS
  • 文件優(yōu)化:壓縮JS永高、CSS(加前綴)隧土、HTML代碼,壓縮合并圖片
  • 代碼分割:提取多個(gè)頁面的公共代碼命爬、提取首屏不需要執(zhí)行部分的代碼讓其異步加載
  • 模塊合并:在采用模塊化的項(xiàng)目里會(huì)有很多個(gè)模塊和文件曹傀,需要構(gòu)建功能把模塊分類合并成一個(gè)文件
  • 自動(dòng)刷新:監(jiān)聽本地源代碼的變化,自動(dòng)重新構(gòu)建饲宛、刷新瀏覽器
  • 代碼校驗(yàn):在代碼被提交到倉庫前需要校驗(yàn)代碼是否符合規(guī)范皆愉,以及單元測試是否通過(eslint..)
  • 自動(dòng)發(fā)布:更新完代碼后,自動(dòng)構(gòu)建出線上發(fā)布代碼并傳輸給發(fā)布系統(tǒng)

2. webpack兩個(gè)核心

  • 模塊轉(zhuǎn)換器(loader):用于把模塊原內(nèi)容按照需求轉(zhuǎn)換成新內(nèi)容落萎,可以加載非JS模塊
  • 擴(kuò)展插件(plugin):在Webpack構(gòu)建流程中的特定時(shí)機(jī)注入擴(kuò)展邏輯來改變擴(kuò)展結(jié)果或做你想要做的事情(比如先刪除文件夾下的文件,再重新生成)

二亥啦、使用

1. 初始化package.json

npm init -y

2. 安裝webpack webpack-cli

webpack-cli:可以解析用戶傳入的參數(shù),把解析好的參數(shù)傳給webpack進(jìn)行打包(webpack4)
npm install webpack webpack-cli --save-dev 表示開發(fā)環(huán)境

3. 項(xiàng)目目錄下,建立src文件夾,src下新建a-module.js练链,index.js

webpack默認(rèn)支持模塊的寫法 commonjs 規(guī)范翔脱,es6(esmodule)

a-module.js代碼如下:

module.exports = 'come on,SmartHui'

index.js代碼如下:

let result = require('./a-module')
console.log(result)

node環(huán)境下可以運(yùn)行,但是瀏覽器是不支持這種語法的媒鼓,所以需要把模塊打包届吁,解析出瀏覽器可以識別的代碼

4. 利用webpack webpack-cli 零配置的方式來打包(默認(rèn)去找當(dāng)前文件夾src下的index.js)

npx webpack //npx是npm 5.2之后出來的,幫助執(zhí)行node_modules下的某個(gè)文件

執(zhí)行完之后绿鸣,可以看到生成了一個(gè)dist文件夾疚沐,下面有一個(gè)main.js文件(就是打包之后的結(jié)果,瀏覽器可以識別)

5. 驗(yàn)證打包后的main.js

dist文件夾下新建index.html潮模,引入main.js<script src="./main.js"></script>亮蛔,在瀏覽器中訪問index.html校读,即可看到控制臺輸出

6. 不建議直接使用npx webpack司倚,vscode可以看到警告

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option
to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

可以 npx webpack --mode development //傳參(webpack-cli會(huì)解析參數(shù))開發(fā)環(huán)境(development )打包出來的main.js是默認(rèn)不會(huì)被壓縮的,生產(chǎn)環(huán)境(production)打包出來的main.js是被壓縮的

7. 每次敲命令會(huì)很麻煩榆纽,把命令配置到package.json中,

  "scripts": {
    "dev":"webpack --mode development",
    "build":"webpack --mode production",
  },

運(yùn)行命令npm run dev,運(yùn)行命令時(shí)动遭,會(huì)把node_modules下的bin目錄放到全局上(就會(huì)有.bin下的命令芬探,執(zhí)行結(jié)束后銷毀)

8. 上述方法比較局限,自己建配置文件配置webpack.config.js(零配置限制:入口文件只能是src下的index.js,打包也是dist下面的main.js,不好改)

const path = require('path')
module.exports = {
    mode:'development', //當(dāng)前是開發(fā)模式
    //入口 出口
    entry:path.resolve(__dirname,'./src/index.js'), //寫路徑采用絕對路徑(_dirname指的是根目錄)厘惦,防止文件夾變動(dòng)后偷仿,需要重新更改路徑
    output: { //出口配置
        filename:'bundle.js',
        path:path.resolve(__dirname,'dist') //把當(dāng)前bundle放到dist文件夾下(沒有dist文件夾會(huì)自動(dòng)創(chuàng)建)
    }
}

可以看到dist文件夾下,生成了bundle.js宵蕉,并且可以看到文件以及大小

D:\frontEnd\WEBPACK-ALL\WEBPACK-BASE>npm run dev

> WEBPACK-BASE@1.0.0 dev D:\frontEnd\WEBPACK-ALL\WEBPACK-BASE
> webpack --mode development

Hash: 03d09b5e51a493b9408c
Version: webpack 4.41.2
Time: 109ms
Built at: 2019-11-06 11:07:46
    Asset      Size  Chunks             Chunk Names
bundle.js  4.17 KiB    main  [emitted]  main
Entrypoint main = bundle.js
[./src/a-module.js] 35 bytes {main} [built]
[./src/index.js] 55 bytes {main} [built]

9. webpack.config.js中傳入mode參數(shù)酝静,修改package.json,去除命令中參數(shù)中的傳遞

  "scripts": {
    "dev":"webpack",
    "build":"webpack"
  },

直接運(yùn)行npm run dev還是ok的

10. 通過vue-cli create-react-app源碼羡玛,有自己的webpack配置形入, 不會(huì)把所有的配置寫到一個(gè)文件里面,都是多個(gè)配置文件缝左。所以下面進(jìn)行配置文件的拆分

11. 修改package.json亿遂,給env自掛屬性(development production),這樣在配置文件中可以獲取到當(dāng)前是哪個(gè)環(huán)境

  "scripts": {
    "dev":"webpack --env.development",
    "build":"webpack --env.production"
  },

webpack.config.js不僅可以導(dǎo)出一個(gè)對象浓若,也可以導(dǎo)出一個(gè)函數(shù)

module.exports = (env) =>{
    console.log(env) //環(huán)境變量 {development:true}
}

npm run dev可以看到結(jié)果

{ development: true }
Hash: 6c637f5819123099586e
Version: webpack 4.41.2
Time: 131ms
Built at: 2019-11-06 11:31:52
  Asset        Size  Chunks             Chunk Names
main.js  1000 bytes       0  [emitted]  main
Entrypoint main = main.js
[0] ./src/index.js 55 bytes {0} [built]
[1] ./src/a-module.js 35 bytes {0} [built]

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

所以可以在代碼中判斷當(dāng)前是開發(fā)還是生產(chǎn)

12. 建立build文件夾,下面建立三個(gè)文件蛇数,分別為:webpack.base.js(基本挪钓、公共配置) webpack.dev.js(開發(fā)) webpack.prod.js(生產(chǎn)) 更加清晰,如下圖:

image.png

13. 默認(rèn)是找webpack.config.js,所以需要告知wepack去找對應(yīng)的配置文件

 "scripts": {
    "dev":"webpack --env.development --config ./build/webpack.base.js",
    "build":"webpack --env.production ./build/webpack.base.js"
  },

這里有兩種方式耳舅,如下碌上,我采用的是1

1.  webpack.base.js(傳入?yún)?shù)mode,再根據(jù)env.development去判斷合并webpack.dev.js還是合并webpack.prod.js并返回) 
2. 同樣也可以直接指定dev找webpack.dev.js build找webpack.prod.js  dev和prod引入base

運(yùn)行npm run dev,可以看到

{ development: true }

運(yùn)行npm run build浦徊,可以看到

{ production: true }

14. webpack合并npm i webpack-merge --D

15. webpack.base.js

const dev = require('./webpack.dev')
const prod = require('./webpack.prod')
const path = require('path')
const merge = require('webpack-merge')

module.exports = (env) => { //env是環(huán)境變量
    console.log(env)
    let isDev = env.development
    const base = {
        entry: path.resolve(__dirname, '../src/index.js'),
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname,'../dist')
        }
    }
    //函數(shù)返回配置文件,沒返回會(huì)采用默認(rèn)配置
    if (isDev) {
        return merge(base,dev)
    } else {
        return merge(base,prod)
    }
}

webpack.dev.js

module.exports = {
    mode:'development'
}

webpack.prod.js

module.exports = {
    mode:'production'
}

16. 如果是開發(fā)環(huán)境馏予,要使用webpack-dev-server npm i webpack-dev-server --save-dev

webpack-dev-server是在內(nèi)存中打包的,不會(huì)產(chǎn)生實(shí)體文件

修改package.json:

  • 增加dev:build,在開發(fā)環(huán)境看打包后的結(jié)果
  • 把webpack修改為webpack-dev-server盔性,就會(huì)啟動(dòng)一個(gè)服務(wù)
  "scripts": {
    "dev:build": "webpack --env.development --config ./build/webpack.base.js",
    "dev": "webpack-dev-server --env.development --config ./build/webpack.base.js",
    "build": "webpack --env.production --config ./build/webpack.base.js"
  },

如下:

i ?wds?: Project is running at http://localhost:8080/
i ?wds?: webpack output is served from /
i ?wds?: Content not from webpack is served from D:\frontEnd\WEBPACK-ALL\WEBPACK-BASE
i ?wdm?: Hash: 9a936290a170bf8cc970
Version: webpack 4.41.2

運(yùn)行npm run dev霞丧,可以看到,輸出的文件應(yīng)該在當(dāng)前根目錄,但是當(dāng)我們訪問http://localhost:8080/并沒有看到bundle.js

image.png

而直接訪問 [http://localhost:8080/bundle.js](http://localhost:8080/bundle.js),可以看到bundle.js
從而驗(yàn)證了webpack-dev-server是在內(nèi)存中打包的冕香,不會(huì)產(chǎn)生實(shí)體文件

bundle.png

17. 存在問題:端口號是寫死的

修改webpack.dev.js 增加devServer

const path = require('path')
module.exports = {
    mode: 'development',
    devServer: {
        port: 3000,
        compress: true,//gzip 可以提升返回頁面的速度
        contentBase: path.resolve(__dirname,'../dist') //webpack啟動(dòng)服務(wù)會(huì)在dist目錄下
    }
}

運(yùn)行npm run dev蛹尝,可以看到,運(yùn)行的是index.html(之前手動(dòng)在dist目錄下創(chuàng)建的),而且和我們打包生成的bundle.js并沒有什么關(guān)聯(lián)

image.png

18. 自動(dòng)生成html文件,并且引入打包后的js

新建public文件夾,新建 index.html文件 (作為模板)

index.html.png

19. 配置一個(gè)插件,在打包結(jié)束后,把當(dāng)前文件的資源 打包后的結(jié)果 引入進(jìn)來 并且產(chǎn)生到當(dāng)前dist目錄下npm i html-webpack-plugin --D

修改webpack.base.js悉尾,引入html-webpack-plugin插件突那,增加pulgins配置

const dev = require('./webpack.dev')
const prod = require('./webpack.prod')
const path = require('path')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = (env) => { //env是環(huán)境變量
    console.log(env)
    let isDev = env.development
    const base = {
        entry: path.resolve(__dirname, '../src/index.js'),
        output: {
            filename: 'bundle.js',
            path: path.resolve(__dirname,'../dist')
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: path.resolve(__dirname, '../public/index.html'),
                filename:'index.html'
            })
        ]
    }
    //函數(shù)返回配置文件,沒返回會(huì)采用默認(rèn)配置
    if (isDev) {
        return merge(base,dev) //循環(huán)后面的配置,定義到前面去
    } else {
        return merge(base,prod)
    }
}

運(yùn)行npm run dev,可以看到(打包在內(nèi)存中构眯,沒有產(chǎn)生實(shí)體文件愕难,所以看不到)

i ?wds?: Project is running at http://localhost:3001/
i ?wds?: webpack output is served from /
i ?wds?: Content not from webpack is served from D:\frontEnd\WEBPACK-ALL\WEBPACK-BASE\dist
i ?wdm?: Hash: 40f577fce1560dc91faf
Version: webpack 4.41.2

打開[http://localhost:3001/](http://localhost:3001/),可以看到,index.html中引入了bundle.js

image.png

如果要看的打包后的文件惫霸,運(yùn)行npm run build

dist.png

20. 優(yōu)化打包后的結(jié)果

修改webpack.base.jsplugins配置

    plugins: [
            new HtmlWebpackPlugin({
                template: path.resolve(__dirname, '../public/index.html'),
                filename: 'index.html',
                minify: !isDev && {
                    removeAttributeQuotes: true,//移除引號
                    collapseWhitespace:true //打包為一行
                }
            })
        ]

運(yùn)行npm run build务漩,可以看到實(shí)際結(jié)果

21. 每次打包需要手動(dòng)刪除dist文件夾下的內(nèi)容(原來dist下面有a.js和b.js,重新打包后文件還在它褪,需要手動(dòng)刪除)

npm i clean-webpack-plugin --D
修改webpack.prod.js生成環(huán)境每次都刪除重新生成

const { CleanWebpackPlugin } = require('clean-webpack-plugin') //默認(rèn)導(dǎo)出的是一個(gè)對象,對象有這個(gè)屬性
new CleanWebpackPlugin({
    cleanOnceBeforeBuildPatterns:['**/*'] //默認(rèn)所有目錄下的所有文件
})

所以可以直接寫成

new CleanWebpackPlugin()

補(bǔ)充插件用法:[https://www.npmjs.com/](https://www.npmjs.com/)

22. css文件問題

src文件夾下翘悉,新建index.css

body {
    background: #f0f0f0;
}

index.js中引入 index.css

import './index.css'

可以看到報(bào)錯(cuò)(需要一個(gè)合適的loader去處理這個(gè)文件類型)

ERROR in ./src/index.css 1:5
Module parse failed: Unexpected token (1:5)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> body {
|     background: #f0f0f0;
| }
 @ ./src/index.js 1:0-20

23. 解析CSS茫打,需要兩個(gè)loader(css-loader style-loader)

css-loader: 解析css語法

style-loader:會(huì)將解析的css,變成style標(biāo)簽插入到頁面中

npm i css-loader style-loader --D

loader執(zhí)行順序 默認(rèn)是從下往上妖混,從右往左(loader可以是'' {} []

字符串格式(從下往上)

     module: {
            rules: [
                {
                    test: /\.css$/,
                    use: 'style-loader'
                },
                {
                    test: /\.css$/,
                    use: 'css-loader'
                }
            ]
        },

數(shù)組格式(從右往左) --這種方式比較常用

    module: {
            rules: [
                {
                    test: /\.css$/,
                    use:['style-loader','css-loader']
                }
            ]
        },

運(yùn)行npm run dev老赤,如圖,可以看到生成了style標(biāo)簽

index.html.png

24. 預(yù)處理器

文件               需要的loader
.scss node-sass sass-loader
.less less less-loader
.stylus stylus stylus-loader

25. 解析scss

npm i node-sass sass-loader --D
node-sass 匹配到scss文件,用sass-loader調(diào)用node-sass解析sass文件

 { 
      test: /\.scss$/,
      use:['style-loader','css-loader','sass-loader']
}

26. 存在一個(gè)場景(有bug) index.js引入index.css,index.css中引入a.css,而a.css中又引入了a.scss

webpack首先找到index.js,然后發(fā)現(xiàn)這個(gè)文件里面引入了css文件,所以會(huì)調(diào)用css-loader來解析制市。但不會(huì)再去解析scss文件(可以看到整個(gè)scss文件直接被插入到style標(biāo)簽中了,而沒有解析去解析,而事實(shí)上,我們是希望去解析的)

index.js中引入index.css

import './index.css'

index.css中引入a.css

@import './a.css';
body {
    background: #f0f0f0;
}

a.css中引入a.scss

@import './a.scss'

a.scss

$background: black; 

div {
    width: 100px;
    height: 100px;
    background: $background;
}

運(yùn)行npm run dev,結(jié)果如下:

image.png

可以看到抬旺,a.scss中的內(nèi)容直接被插入到style標(biāo)簽中了,解析到 a.css就不會(huì)再去解析里面的引入的 a.scss了祥楣,但實(shí)際我們希望去解析的

解決方案:給css-loader傳參數(shù)

   {
    test: /\.css$/,
    use: ['style-loader', {
        loader: 'css-loader',
        options: { //給loader傳遞參數(shù),css文件引入了其他文件,你從當(dāng)前這個(gè)loader之后執(zhí)行這個(gè)文件(先調(diào)用sass-loader,再調(diào)用css-loader) 如果寫2 就是調(diào)用后面兩個(gè)(可以寫多,不可以寫少)
            importLoaders:1
        }
    },'sass-loader']
},

27. 打包c(diǎn)ss還需要處理樣式前綴(比如樣式 transform:rotate(45deg))

在瀏覽器版本比較低是,需要加上webkit前綴

解決方案 npm i postcss-loader --D

同樣也需要一個(gè)插件 (就像sass-loader會(huì)調(diào)用node-sass)

npm i autoprefixer --D

    {
        test: /\.css$/,
        use: ['style-loader', {
            loader: 'css-loader',
            options: { //給loader傳遞參數(shù),css文件引入了其他文件,你從當(dāng)前這個(gè)loader之后執(zhí)行這個(gè)文件(先調(diào)用sass-loader,再調(diào)用css-loader) 如果寫2 就是調(diào)用后面兩個(gè)(可以寫多,不可以寫少)
                importLoaders:2
            }
        },'postcss-loader','sass-loader']
    },

postcss-loader需要一個(gè)配置文件postcss.config.js

module.exports = {
    plugins: [
        require('autoprefixer')
    ]
}

28. 存在問題:打包后的bundle.js中并沒有加上前綴(目前瀏覽器默認(rèn)版本都比較高,加了有些浪費(fèi)性能)

image.png

解決方案 告訴當(dāng)前瀏覽器(參考[https://github.com/browserslist/browserslist](https://github.com/browserslist/browserslist) )

  • .browserslistrc
cover 95%
  • package.json
 "browserslist": [
    "defaults",
    "not ie < 9",
    "last 2 versions",
    "> 1%",
    "iOS 7",
    "last 3 iOS versions"
  ],

選擇其中一個(gè)即可开财,這里選擇的是方法1汉柒,運(yùn)行npm run dev:buildbundle.js如下:

image.png

29. 這種方法解析css的時(shí)候责鳍,不能渲染dom碾褂。但是我們希望css和js一同并行加載,所以我們需要抽離css文件历葛。

抽離css插件 npm i mini-css-extract-plugin --D

開發(fā)環(huán)境不用抽取,線上環(huán)境需要抽取

     {
                    test: /\.css$/,
                    use: [
                        isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
                        {
                            loader: 'css-loader',
                            options: {
                                importLoaders: 2
                            }
                        }, 'postcss-loader', 'sass-loader']
    },

30. 告訴webpack抽取出來的css叫什么

     plugins: [
            !isDev && new MiniCssExtractPlugin({
                filename:'css/main.css'
            }),
            new CleanWebpackPlugin(),
            new HtmlWebpackPlugin({
                template: path.resolve(__dirname, '../public/index.html'),
                filename: 'index.html',
                minify: !isDev && {
                    removeAttributeQuotes: true,//移除引號
                    collapseWhitespace: true //打包為一行
                }
            })
        ].filter(Boolean)

補(bǔ)充知識點(diǎn)

[].filer(Boolean)等價(jià)于 [簡寫模式]

[].filter((x)=>{
    return Boolean(x)
})

把plugins里面的每一項(xiàng)處理正塌,把結(jié)果為false的過濾掉

執(zhí)行npm run build,發(fā)現(xiàn)dist目錄下多了css/main.css

image.png

31. 存在問題:css文件未壓縮

  • webpack生產(chǎn)環(huán)境只會(huì)默認(rèn)壓縮jscss不會(huì)壓縮,需要另外配置 npm i optimize-css-assets-webpack-plugin --save-dev
  • 如果css手動(dòng)壓縮,那么js也需要手動(dòng)壓縮 npm i terser-webpack-plugin --save-dev
const TerserWebpackPlugin = require('terser-webpack-plugin')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
    mode: 'production',
    optimization: { //優(yōu)化項(xiàng)
        minimizer: [
            new TerserWebpackPlugin(), //css手動(dòng)壓縮的話 js也需要手動(dòng)壓縮
            new OptimizeCSSAssetsPlugin() //css壓縮
        ]
    }
}

運(yùn)行npm run build,可以看到cssjs均被壓縮

main.css

bundle.js

32. 圖片

src下放一張logo.jpg圖片

編輯 index.js代碼

//獲取當(dāng)前打包logo后的路徑
import logo from './logo.jpg'
console.log(logo)
let img = document.createElement('img')
img.src = logo
document.body.appendChild(img)

運(yùn)行npm run dev恤溶,報(bào)錯(cuò)不認(rèn)識圖片

error

需要安裝file-loader(默認(rèn)功能拷貝乓诽,拷貝到dist目錄下,并且返回圖片)npm i file-loader -D

     {
            test: /.jpe?g|png|gif$/,
            use:'file-loader'
     }

運(yùn)行npm run build咒程,結(jié)果如下:

image.png

34. 小圖片轉(zhuǎn)成base64(編碼比以前大,不用發(fā)送http請求)

npm i url-loader -D

       {
                    //圖片轉(zhuǎn)換
                    test: /\.(jpe?g|png|gif)$/,
                    use: {
                        loader: 'url-loader',
                        //如果小于100k鸠天,會(huì)使用url-loader
                        //如果大于100k,會(huì)使用file-loader
                        options: { 
                            name:'image/[contentHash].[ext]', // 打包后的圖片目錄(當(dāng)前contentHash-圖片打包后的hash ext-當(dāng)前后綴)
                            limit: 100*1024
                        }//file-loader 默認(rèn)的功能是拷貝的作用
                        //希望當(dāng)前較小的圖片可以轉(zhuǎn)化成base64 比以前大 好處就是不用http請求
                    }
                  
        }

運(yùn)行npm run build,結(jié)果如下孵坚,可以對比看到粮宛,打包后的差別

  • 使用 url-loader,打包后無img卖宠,并且bundle.js文件大小變大了
url-loader

file-loader

35. 圖標(biāo)

   { //圖標(biāo)轉(zhuǎn)換
                    test: /\.(woff|ttf|eot|svg)$/,
                    use:'file-loader'
   },

36. js轉(zhuǎn)換

npm i @babel/core @babel/preset-env babel-loader -D

  • babel/core: 核心模塊
  • babel/preset-env: 插件集合(所有將es6->es5的插件)
  • babel-loader: webpack使用的loader

關(guān)系:默認(rèn)會(huì)調(diào)用babel/core會(huì)轉(zhuǎn)化代碼 轉(zhuǎn)化的時(shí)候需要@babel/presets-env 將es6轉(zhuǎn)換成es5

@是指作用域巍杈,npm之后把所有babel相關(guān)的都放在一個(gè)目錄下,如圖:

image.png

修改index.js

//es6->es5
const fn = () => {
    
}

fn()

配置webpack.base.js扛伍,把具體的配置寫在options

 {//解析js文件 默認(rèn)會(huì)用調(diào)用@babel/core
                    test: /\.js$/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            
                        }
                    }
  }

如果options很多的話不方面,所以建一個(gè)配置文件.babelrc

       {
                   test: /\.js$/,
                   use:  'babel-loader'
       },

插件的集合
.babelrc

{
//preset從下往上執(zhí)行
    "presets": [
        "@babel/preset-env"
    ],
//plugins從上往下執(zhí)行
  "plugins":[
  ]
}

執(zhí)行npm run dev:build筷畦,如圖,可以看到代碼成功轉(zhuǎn)換

image.png

37. js草案語法

class A {
    a = 1 //實(shí)例上的屬性,并且是私有的
}

等同于

class A{
    constructor() {
        this.a = 1
    }
}

運(yùn)行npm run dev:build刺洒,報(bào)錯(cuò)如圖

image.png

安裝報(bào)錯(cuò)中所需要的插件 npm i @babel/plugin-proposal-class-properties --save-dev
修改.babelrc

  • presets:插件集合
  • plugin: 單個(gè)插件
{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins":[
        ["@babel/plugin-proposal-class-properties", {
            "loose": true
        }]
    ]
}

執(zhí)行npm run dev:build

image.png

修改.babelrc,"loose":false

image.png

一般情況是用"loose":true鳖宾,因?yàn)檫@樣可以用裝飾器

38. es7 裝飾器

修改 index.js,target代表的就是A

@log
class A {
    a = 1 //實(shí)例上的屬性,并且是私有的
}
function log(target) {
   console.log(target)
}

執(zhí)行npm run dev,報(bào)錯(cuò)

image.png

訪問[https://babeljs.io/](https://babeljs.io/)逆航,搜索decorators
https://babeljs.io/docs/en/babel-plugin-proposal-decorators鼎文,根據(jù)文檔配置即可

首先,npm install --save-dev @babel/plugin-proposal-decorators

其次因俐,修改.babelrc

{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins":[
        ["@babel/plugin-proposal-decorators", { 
            "legacy": true 
        }],
        ["@babel/plugin-proposal-class-properties", {
            "loose": true
        }]
    ]
}

執(zhí)行npm run dev:build拇惋,如圖:

image.png

可以看到,A作為target傳入log函數(shù)

直接在node環(huán)境運(yùn)行抹剩,可以看到打印出來的target

image.png

39. api自動(dòng)轉(zhuǎn)換

修改index.js

[1, 2, 3].includes(1);

執(zhí)行npm run dev:build

image.png

可以看到撑帖,并未進(jìn)行轉(zhuǎn)化,這是因?yàn)槟J(rèn)不能轉(zhuǎn)換高級語法,實(shí)例上的語法以及promise澳眷,所以我們需要自己進(jìn)行手動(dòng)配置

修改.babelrc

{
    "presets": [
        ["@babel/preset-env",{
            "useBuiltIns": "usage" //使用的api 會(huì)自動(dòng)轉(zhuǎn)化,并且是按需加載
        }]
    ],
    "plugins":[
        ["@babel/plugin-proposal-decorators", { 
            "legacy": true 
        }],
        ["@babel/plugin-proposal-class-properties", {
            "loose": true
        }]
    ]
}

執(zhí)行npm run dev:build,報(bào)錯(cuò)了

image.png

原因就是胡嘿,遇到includes,不知道是引入string.includes還是array.includes
按照報(bào)錯(cuò)的提示钳踊,我們安裝code.js npm install --save-dev core-js@2(這里我們用2)

  • code.js類似于babel-polyfill

修改.babelrc

{
    "presets": [
        ["@babel/preset-env",{
            "useBuiltIns": "usage",
            "corejs": 2
        }]
    ],
    "plugins":[
        //解析裝飾器
        ["@babel/plugin-proposal-decorators", { 
            "legacy": true 
        }],
        //解析類的屬性
        ["@babel/plugin-proposal-class-properties", {
            "loose": true
        }]
    ]
}

運(yùn)行npm run dev:build,成功編譯

image.png

40. babel7新特性:解決重復(fù)引入_classCallCheck

修改index.js

import './a'
class A {

}

a.js中也有一個(gè)class

class B {

}

執(zhí)行npm run dev:build

image.png

image.png

可以看到衷敌,引入了兩次_classCallCheck(代碼冗余)

解決辦法npm install --save-dev @babel/plugin-transform-runtime 節(jié)約代碼

https://babeljs.io/docs/en/babel-plugin-transform-runtime#docsNav

參考文檔勿侯,還需要安裝npm install --save @babel/runtime(線上需要使用)

修改.babelrc

{
    "presets": [
        ["@babel/preset-env",{
            "useBuiltIns": "usage",
            "corejs": 2
        }]
    ],
    "plugins":[
        //解析裝飾器
        ["@babel/plugin-proposal-decorators", { 
            "legacy": true 
        }],
        //解析類的屬性
        ["@babel/plugin-proposal-class-properties", {
            "loose": true
        }],
        ["@babel/plugin-transform-runtime"]
    ]
}

執(zhí)行npm run dev:build

image.png

可以看到,a.js和index.js中,都使用的一種方法引入_classCallCheck

41. 如何編譯react

安裝npm i react react-dom --save
安裝npm i @babel/preset-react --save-dev

修改index.js

import React from 'react'
import ReactDOM from 'react-dom'

ReactDOM.render(<div>hello</div>,document.getElementById('root'))

修改.babelrc

{
    "presets": [
        ["@babel/preset-env",{
            "useBuiltIns": "usage",
            "corejs": 2
        }],
        "@babel/preset-react"
    ],
    "plugins":[
        //解析裝飾器
        ["@babel/plugin-proposal-decorators", { 
            "legacy": true 
        }],
        //解析類的屬性
        ["@babel/plugin-proposal-class-properties", {
            "loose": true
        }],
        ["@babel/plugin-transform-runtime"]
    ]
}

運(yùn)行npm run dev,可以看到成功了

image.png

42. ts配置

新建index1.jsx

import React from 'react'
import ReactDOM from 'react-dom'

//ts校驗(yàn)類型
interface IProps {
    num: number
}
let initState = { count: 0 }
type State = Readonly<typeof initState>
class Counter extends React.Component<IProps,State> {
    state: State = initState
    render() {
        return(
            <div>
                {this.state.count}
                <button onClick={this.handleClick}>點(diǎn)擊</button>
            </div>
        )
    }
    handleClick = () => {
        this.setState({
            count:this.state.count + 1
        })
    }
}

ReactDOM.render(<Counter />,document.getElementById('root'))

使用ts有兩種方案:

  • 使用ts-loader逢享,需要配合typescript庫使用
  • babel7發(fā)明一個(gè)包罐监,專門解析ts @babel/preset-typescript
    npm i @babel/preset-typescript --save-dev

修改webpack.base.js,入口文件應(yīng)該是index.jsx

entry: path.resolve(__dirname, '../src/index.jsx')

并且瞒爬,增加解析ts文件的配置


image.png

然后弓柱,修改.babelrc,先ts->js->react->es5

image.png

運(yùn)行npm run dev,編譯成功

image.png

43.解決代碼報(bào)錯(cuò)

image.png

用ts去校驗(yàn)代碼,是否符合規(guī)范侧但,是否是ts語法

首先矢空,安裝npm i typescript //并不是用來解析語法,而是用來校驗(yàn)代碼

然后禀横,本地執(zhí)行npx typescript --init,可以看到本地生成了一個(gè)文件 tsconfig.json

image.png
error1.png

可以看到代碼報(bào)錯(cuò)屁药,react并不是ts版本

根據(jù)提示安裝npm i @types/react @types/react-dom --save

安裝成功后,可以看到報(bào)錯(cuò)(error1)消失

error2.png

但是柏锄,可以看到代碼還有報(bào)錯(cuò)酿箭,不認(rèn)識JSX,修改tsconfig.json

tsconfig.json

可以看到報(bào)錯(cuò)(error2)消失

error3

使用Count應(yīng)該傳num屬性

修改index.tsx

ReactDOM.render(<Counter num={1} />,document.getElementById('root'))

44. vue配置

新建index.ts

import Vue from 'vue'

let vm = new Vue({
    el: '#root',
    render: h => h('h1', {}, 'hello vue')
})

修改webpack.base.js入口

entry: path.resolve(__dirname, '../src/index.ts')

執(zhí)行npm run dev

index.ts

新建App.vue

<template>
    <div>
        Welcome
    </div>
</template>

修改index.ts

import Vue from 'vue'
import App from './App.vue'

let vm = new Vue({
    el: '#root',
    render: h => h(App)
})

可以看到報(bào)錯(cuò)


image.png

解決方法:新建vue-shims.d.ts,也是任何.vue文件,都看成一個(gè)Vue類型(名稱隨便趾娃,后綴名一定要是.d.ts)

declare module '*.vue' {
    import Vue from 'vue'
    export default Vue
}

解析vue缭嫡,需要安裝npm i vue-loader vue-template-compiler --save-dev

修改webpack.base.js

image.png

還需要引入一個(gè)插件

const VueLoaderPlugin = require('vue-loader/lib/plugin')
   plugins: [
            !isDev && new MiniCssExtractPlugin({
                filename:'css/main.css'
            }),
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin({
                template: path.resolve(__dirname, '../public/index.html'),
                filename: 'index.html',
                minify: !isDev && {
                    removeAttributeQuotes: true,//移除引號
                    collapseWhitespace: true //打包為一行
                }
            })
        ].filter(Boolean)

運(yùn)行npm run dev,成功

image.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抬闷,一起剝皮案震驚了整個(gè)濱河市妇蛀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌笤成,老刑警劉巖评架,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異炕泳,居然都是意外死亡纵诞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門培遵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來浙芙,“玉大人,你說我怎么就攤上這事荤懂。” “怎么了塘砸?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵节仿,是天一觀的道長。 經(jīng)常有香客問我掉蔬,道長廊宪,這世上最難降的妖魔是什么矾瘾? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮箭启,結(jié)果婚禮上壕翩,老公的妹妹穿的比我還像新娘。我一直安慰自己傅寡,他們只是感情好放妈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著荐操,像睡著了一般芜抒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上托启,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天宅倒,我揣著相機(jī)與錄音,去河邊找鬼屯耸。 笑死拐迁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疗绣。 我是一名探鬼主播线召,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼持痰!你這毒婦竟也來了灶搜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤工窍,失蹤者是張志新(化名)和其女友劉穎割卖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體患雏,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹏溯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淹仑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丙挽。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖匀借,靈堂內(nèi)的尸體忽然破棺而出颜阐,到底是詐尸還是另有隱情,我是刑警寧澤吓肋,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布凳怨,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肤舞。R本人自食惡果不足惜紫新,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望李剖。 院中可真熱鬧芒率,春花似錦、人聲如沸篙顺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慰安。三九已至腋寨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間化焕,已是汗流浹背萄窜。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撒桨,地道東北人查刻。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像凤类,于是被迫代替她去往敵國和親穗泵。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 目錄第1章 webpack簡介 11.1 webpack是什么谜疤? 11.2 官網(wǎng)地址 21.3 為什么使用 web...
    lemonzoey閱讀 1,731評論 0 1
  • 前言 本文主要從webpack4.x入手佃延,會(huì)對平時(shí)常用的Webpack配置一一講解,各個(gè)功能點(diǎn)都有對應(yīng)的詳細(xì)例子夷磕,...
    BetterChen閱讀 1,943評論 0 3
  • 最近感覺自己越來越像一個(gè)API調(diào)用程序員履肃,很多基礎(chǔ)的原理以及項(xiàng)目構(gòu)建都沒實(shí)際操作過,所以這里動(dòng)手自己去搭建了一個(gè)v...
    Aoyi_G閱讀 1,494評論 0 2
  • 你等我,一年為限如果我盡力绵跷,請讓我看到你沖我招手微笑 你曾路過我灑滿陽光的窗 窗下我的書桌樹影婆娑 灰塵在童年里舞...
    微雨硯閱讀 1,046評論 10 15
  • 其實(shí)呢膘螟,這一周呢,進(jìn)度不是很快碾局,我就是通過讀前世今生荆残,想到了很多,我更多側(cè)重于想我今生是有什么樣的功課來到這個(gè)世上...
    心慧愛閱讀 264評論 0 1