深入學習webpack 4.x核心用法及其源碼(二)

上一小節我簡單介紹了 webpack 的一些用法,它的核心用法我還沒有介紹,webpack 默認只會對 js 的一些代碼進行打包,不可以對 css 樣式進行打包,或把二進制圖片打包成 data URL,熱更新

Loader

介紹

loader 用於對模塊的源代碼進行轉換。例如:typescript 轉換成 js,less 轉換爲 css 等。

使用

webpack 4.x 有三種使用 loader 的方式:

  • 配置(推薦) :在 webpack.config.js 文件中指定 loader。
  • 內聯 :在每個 import 語句中顯式指定 loader。
  • CLI :在 shell 命令中指定它們。

注:下面我會以配置的方式爲例子,如果想了解其他兩種方式的用法可以看一下官方的文檔:https://www.webpackjs.com/concepts/loaders/

const path = require('path');

module.exports = {
    mode: 'development',
    entry: './src/index.js',
    module: {
        rules: [{
            test: /\.jpg$/,
            use: {
                loader: 'file-loader'
            }
        }]
    },
    output: {
        filename: 'main.js',
        path: path.join(__dirname, 'dist'),
    }
}

和上一章的代碼相比,我只添加了 module 這一項,那這個 module 是什麼意思呢?

module 中可以配置一些 loaderplugins 中,可以理解成 當 webpack 4.x 不知道如何打包文件時,它會在 module 配置的 規則 和 插件中尋找解決方法

loader 寫在 rules 中,rules 是一個數組,其中的每一個對象基本是需要一個 testusetest 是一個正則表達式,用來匹配文件後綴名。 use 中就填寫你要使用到的 loader 名稱。

file-loader 是一個處理二進制文件,默認情況下,生成的文件的文件名就是文件內容的 MD5 哈希值並會保留所引用資源的原始擴展名。如果你不滿足於默認的文件名,你可以通過 options 中的 name 進行佔位符配置文件名,這是鏈接:https://www.webpackjs.com/loaders/file-loader/。如果你對打包生成的文件路徑不滿,可以通過 outputpath 進行配置。

file-loader 類似的 loader 是 url-loader ,它可以將 二進制圖片 直接轉換爲 base64 , 這個雖然可以帶來請求的減少,但同時也會增加打包文件的體積。尤其是一個很大很大的圖片的時候,這個問題尤其突出。所以最好是對文件的大小進行限制,通過 option 中的 limit (單位:byte) ,例如 limit: 2048 表示 小於 2kb 則按照 url-loader 打包,超出了就會按照 file-loader 來打包。可以參見:https://www.webpackjs.com/loaders/url-loader/

打包CSS樣式表

打包 CSS 樣式表需要安裝 style-loadercss-loader

npm i style-loader css-loader -D

webpack.config.js 文件的代碼如下:

    .
    .
    .

    module: {
        rules: [
            .
            .
            .

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

            .
            .
            .
        ]
    }

    .
    .
    .
}

注意:這兩個的順序必須是 style-loader 在前, css-loader 在後,不可顛倒

  • css-loader :用來解析樣式表中用到的外部引用,例如:@importurl()
  • style-loader : 就是將 css-loader 分享出的樣式掛載到頭部(header區域)

css-loader 有很多其他的特性,例如二次加載,模塊化css

    .
    .
    .

    {
        test: /\.css$/,
        use: [
            'style-loader',
            {
                loader: 'css-loader',
                importLoaders: 2,
                modules: true,
            }
        ],
    }

    .
    .
    .

其中 modules 表示啓動 css 模塊化,importLoaders 表示二次加載,那這個二次加載什麼意思呢?可以理解成當確保無論這麼加載都會將按照配置的loader順序加載一遍,不會缺省loader,

less、scss 的使用

使用 less 和 sass 很簡單,這裏我以 less-loader 爲例:

先安裝:

npm i less-loader less -D

webpack.config.js

    .
    .
    .

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

    .
    .
    .

less-loader 的作用就是幫助我們把它翻譯成我們看得懂的 css 樣式表

學習 less-loader 配置,參見:https://www.webpackjs.com/loaders/less-loader/

學習 sass-loader 配置,參見:https://www.webpackjs.com/loaders/sass-loader/

給樣式加上廠商前綴

給樣式加上廠商前綴需要使用 postcss-loader

安裝:

npm i -D postcss-loader

使用它需要創建一個 postcss.config.js 的配置文件,配置參見:https://www.webpackjs.com/loaders/postcss-loader/

我先安裝一個 autoprefixer 的插件

npm i -D autoprefixer

postcss.config.js:

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

webpack.config.js:

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

打包字體圖片

使用字體圖片只需使用 file-loader 就行了

    {
        test: /\.(eot|ttf|svg)$/,
        use: ['file-loader'],
    },

插件

介紹

它很像 vue,react 的生命週期函數,可以在 webpack 運行到某個時刻的時候,幫你做一些事情

使用

下面我以 htmlWebapckPlugin 作爲例子:

安裝

npm i html-webpack-plugin -D

使用

module.exports = {
    mode: 'development',
    entry: './src/index.js',
    // 
    plugins: [new HtmlWebpackPlugin({
        template: 'src/template.html',
    })],
    // 可以使用模板進行打包
    output: {
        filename: 'main.js',
        path: path.join(__dirname, 'dist'),
    }
}

htmlWebpackPlugin 會在打包結束後,自動生成一個html文件,並把打包生成的js自動引入到這個html文件中,使用模板可以安裝你的方式進行打包

devtool

介紹

主要是當我們源代碼錯誤時,可以根據控制檯輸出的錯誤信息來定位我們到底是哪裏出錯了。這個功能很有用

可以參考:https://www.webpackjs.com/configuration/devtool/ 的表格,哪裏有很多配置項。

默認是 devtool: 'none',當我們在生產時一般我們使用 cheap-module-eval-source-map,線上的時候一般使用 cheap-module-source-map

雖然有很多配置項,但我們還是可以總結出一些規律:

  • souce-map :生成一個 .map.js 的映射文件
  • inline :把 .map.js 的內容打包合併到我們輸出文件中
  • cheap : 表示只提示哪一行出錯,不精確到哪一個字符,只提示業務中出現錯誤的代碼,不提示用到的第三方的錯誤的代碼
  • module :會提示第三方的錯誤代碼
  • eval :會用到 eval() 這種方式打包

自動監聽並保存代碼

兩種方式都要使用 package.js 文件的 script:

第一種(webpack)

  "scripts": {
    "build": "webpack --watch"
  },

不能使用ajax

第二種(使用 webpack-dev-server 推薦)

不僅可以自動打包,還可以自動刷新瀏覽器

webpack.config.js :

module.exports = {
    mode: 'development',
    devtool: 'cheap-module-eval-source-map',
    entry: {
        main: './src/index.js',
    },
    devServer: {
        contentBase: './dist',
        open: true,
        proxy: {
            'api' :  'http://localhost:3000'
        }
    },

    .
    .
    .
}

其中:

  • contentBase :表示開啓服務器的路徑,默認自動打開 index.html
  • open :開啓服務器時,自動打開瀏覽器
  • proxy :跨域代理

配置了這些還需要在 package.json 中使用 script 添加一項:

  "scripts": {
    "start": "webpack-dev-server"
  },

其實我們可以不配置上面的東西,僅僅借用 script 就可以實現,這種方式更簡單:

  "scripts": {
    "dev": "webpack-dev-server --open --port 3000 --contentBase dist"
  },

爲什麼我們一定要使用服務器的方式打開文件呢?現在的項目中都會跨域使用ajax發起跨域請求。如果以 file: 的方式打開的文件是不可以發出ajax請求的,會報錯。

開啓熱更新

webpack.config.js :

module.exports = {
    .
    .
    .

    devServer: {
        contentBase: './dist',
        open: true,
        hot: true,
        hotOnly: true,
    },

    .
    .
    .
}

使用 BABLE 寫 ES6

介紹

babel 可以將 ES6 的語法轉換成 ES5 的語法

安裝

第一種:polyfill 打包業務中使用

會污染全局作用域

npm install --save-dev babel-loader @babel/core
npm install @babel/preset-env --save-dev
npm install --save @babel/polyfill

@babel/core 是一個 babel 的核心庫,就是用於語法轉換的

第二種:transform-runtime 打包庫文件中使用

以閉包的形式保護了作用域

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
npm install --save @babel/runtime-corejs2

使用

webpack.config.js:

第一種:polyfill 打包業務中使用

const path = require('path');

module.exports = {
    //...
    module: {
        rules: [
            { 
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" ,
                options: {
                    "presets": [["@babel/preset-env",{
                        useBuiltIns: 'usage'
                    }]]
                },
            },
        ]
    },
    //...
}

配置完後,還要在輸入的主文件中的第一行導入 import "@babel/polyfill",如果配置了 useBuiltIns: 'usage'@babel/polyfill 會自動導入,所以可以不用導入

第二種:transform-runtime 打包庫文件中使用

const path = require('path');

module.exports = {
    //...
    module: {
        rules: [
            { 
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" ,
                options: {
                    "plugins": [
                        [
                          "@babel/plugin-transform-runtime",
                          {
                            "corejs": 2,
                            "helpers": true,
                            "regenerator": true,
                            "useESModules": false,
                          }
                        ]
                      ]
                },
            },
        ]
    },
    //...
}

如果你感覺 option 中的代碼比較長,可以創建一個 .babelrc 的文件,將 option 中的代碼複製到 .babelrc 中就行了,不能有註釋

發佈了44 篇原創文章 · 獲贊 17 · 訪問量 4217
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章