項目中使用webpack基本的配置

什麼是 webpack

webpack 可以看做是模塊打包機:它做的事情是,分析你的項目結構,找到 JavaScript 模塊以及其他的一些瀏覽器不能直接運行的擴展語言(ScssTypeScript 等),並將其轉換和打包爲合適的格式供瀏覽器使用

使用 webpack 前的準備

  1. npm init :創建一個 package.json 文件。它是標準的 npm 說明文件,包括當前項目的依賴模塊、自定義的腳本任務等

  2. cnpm install webpack --save-dev :安裝 webpack

  3. 文件目錄的構建方面:一般由兩個目錄構成:app(存放原始數據和 JS 模塊),public(存放供瀏覽器讀取的文件,即 webpack 打包生成的文件,和 html 源代碼)

  4. 創建根目錄下 webpack.config.js 文件,這是 webpack 的配置文件,基本的配置如下:

module.exports = {
    entry:  __dirname + "/app/main.js", // 已多次提及的唯一入口文件
    output: {
        path: __dirname + "/public", // 打包後的文件存放的地方
        filename: "bundle.js" // 打包後輸出文件的文件名
    }
};

‘__dirname’是 node.js 中的全局變量,它指向當前執行腳本所在的目錄

package.json 方面的配置:(配置好後,直接可以在命令行:npm start 即可進行打包編譯,需要注意的是,除了 "start" 之外,所有的自定義命令都需要通過 npm run 命令名稱 的形式進行)

"scripts": {
    "start": "webpack"
}

webpack 提供了一種對應編譯文件和源文件的方法,使得編譯後的代碼可讀性更高,更容易調試。

module.exports = {
    // 小到中型的項目中,eval-source-map 是一個很好的選擇
    devtool: 'eval-source-map', // 注意:只應該在開發階段使用它
    entry:  __dirname + "/app/main.js",
    output: {
        path: __dirname + "/public",
        filename: "bundle.js"
    }
};

正式書寫代碼時,通過 module.exports 的方式進行模塊的導出,通過 require 的方式進行模塊的導入

同時建立多個入口文件:

module.exports = {
    // 可以同時定義多個入口文件
    entry: {
        'index':  __dirname + '/app/main.js',
        'indexT': __dirname + '/app/main2.js'
    },
    output: {
        path: __dirname + '/build',
        filename: '[name]-[hash].js' // 定義多個出口文件時的命名
    },
}

使用 webpack 構建本地服務器

cnpm install webpack-dev-server --save-dev :安裝 webpack-dev-server

webpack.config.js 中進行配置

module.exports = {
  devtool: 'eval-source-map',

  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  },

  devServer: {
    contentBase: "./public", // 本地服務器所加載的頁面所在的目錄
    historyApiFallback: true, // 不跳轉
    inline: true // 實時刷新
  } 
};

之後,在 package.json 中的 scripts 對象添加命令,方便開啓本地服務器:

"server": "webpack-dev-server --open"

此時,通過在終端輸入:npm run server 就可以本地的 8080 端口查看結果

Loaders

通過使用不同的 loaderwebpack 有能力調用外部的腳本或者工具,實現對不同格式的文件的處理

如分析轉換 scsscss,把 ES6ES7 轉爲現代瀏覽器兼容的 JS 文件等等

Loaders 需要單獨安裝並且需要在 webpack.config.js 中的 modules 關鍵字下進行配置,配置包括以下方面:
1. test :一個用以匹配 loaders 所處理文件的擴展的正則表達式(必須!)
2. loaderloader 的名稱(必須!)
3. include / exclude :手動添加必須處理的文件(文件夾)或屏蔽不需要處理的文件(文件夾)(可選)
4. query :爲 loaders 提供額外的設置選項(可選)

Babel

Babel :其實是一個編譯 JavaScript 的平臺,它可以編譯 ES6ES7,基於 JavaScript 的擴展語言:ReactJSXTypeScript 等等

Babel 是幾個模塊化的包,其核心功能位於稱爲 babel-corenpm 包中,對於每個我們需要的功能或擴展,都需要單獨安裝響應的包,如:
- 解析 ES6babel-env-preset
- 解析 JSXbabel-preset-react

安裝他們:cnpm install babel-core babel-loader babel-preset-env babel-preset-react --save-dev
cnpm install react react-dom --save

webpack.config.js 中配置 Babel

module: {
    rules: [
        {
            test: /(\.jsx|\.js)$/,
            use: {
                loader: "babel-loader",
                options: {
                    presets: [
                        "env", "react"
                    ]
                }
            },
            exclude: /node_modules/
        }
    ]
}

配置完成後,就可以使用 ES6 以及 JSX 語法了

關於 Babel 的配置

babel 具有非常多的配置選項,可以將它的配置單獨放在 .babelrc 的配置文件中(webpack 會自動調用 .babelrc 裏的 babel 配置選項)

module: {
    rules: [
        {
            test: /(\.jsx|\.js)$/,
            use: {
                loader: "babel-loader"
                // 以下放到 .babelrc 中
                // options: {
                //     presets: [
                //         "env", "react"
                //     ]
                // }
            },
            exclude: /node_modules/
        }
    ]
}

.babelrc 中:

{
  "presets": ["react", "env"]
}

一切皆模塊

webpack 的特殊優點是,它把所有的文件都當做模塊處理,JavaScriptCSSfonts、圖片等等,通過合適的 loader 都可以被處理

1. CSS 的處理

  1. css-loader :能夠使用類似 @importurl(...) 的方法實現 require() 的功能
  2. style-load :將所有計算後的樣式加入到頁面中

兩者組合在一起能夠把樣式表嵌入到 webpack 打包後的 JS 文件中

安裝他們:cnpm install style-loader css-loader --save-dev

在 webpack.config.js 中配置使用:

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

注意這裏對同一個文件引入多個 loader 的方法

之後,只需將對應的 CSS 文件,通過 require 導入到入口文件 main.js 中就可以使用共同打包

2. CSS module

CSS modules 意在把 JS 的模塊化思想帶入 CSS 中,通過 CSS 模塊,所有的類名,動畫名默認都只作用於當前模塊,這樣可以有效的避免全局污染,配置如下:(在 webpack.config.js 中進行配置)

{
    test: /\.css$/,
    use: [
        {
            loader: "style-loader"
        }, {
            loader: "css-loader",
            options: {
                modules: true, // 指定啓用css modules
                localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的類名格式
            }
        }
    ]
}
// 使用cssModule添加類名的方法
<div className={styles.root}>

3. CSS 預處理器

對於 Sass、Less 之類的預處理器可以在 webpack 使用相關的 loaders 進行配置:
1. Less Loader
2. Sass Loader
3. Stylus Loader

不過其實也存在一個 CSS 的處理平臺 -PostCSS,它的其中一個功能是爲 CSS 代碼自動添加使用不同瀏覽器的 CSS 前綴

安裝他們:cnpm install postcss-loader autoprefixer --save-dev

其中,autoprefixer 是自動添加前綴的插件。之後再 webpack 配置文件中添加 postcss-loader:

{
    test: /\.css$/,
    use: [
        {
            loader: "style-loader"
        }, {
            loader: "css-loader",
            options: {
                modules: true
            }
        }, {
           loader: "postcss-loader" // 添加 postcss-loader
       }
    ]
}

4. 對圖片的打包

圖片需要使用 url-loader 來加載,安裝:cnpm install url-loader --save-dev

使用:

{
    test: /(\.png|\.jpg)$/,
    // 小於8kb的圖片不會被處理
    use: 'url-loader?limit=8192&name=img/[hash:8].[name].[ext]'
}

插件(Plugins)

插件是用來擴展 webpack 功能的,他們會在整個構建過程中生效,執行相關的任務

Loaders 和 Plugins 的區別:
- loaders 是在打包構建過程中用來處理源文件的(JSX,Scss,Less…),一次處理一個
- 插件並不直接操作單個文件,它直接對整個構建過程起作用

1. 使用插件的方法

使用哪個插件,就通過 npm 來進行安裝,之後再 webpack.confign.js 中的 plugins 關鍵字部分添加該插件的一個實例

2. 常用的插件之:HtmlWebpackPlugin

該插件的作用:依據一個簡單的 html 模板,生成一個自動引用打包後的 JS 文件的新的 index.html,這在每次生成的 JS 文件名稱中帶有 hash 值時非常有用(因爲每次名稱不同)

安裝他們:cnpm install html-webpack-plugin --save-dev

之後,需要對項目進行一些更改:

  1. 刪除 public 文件夾,利用此插件 html 文件會自動生成,前面操作的 JS 文件也會自動關聯到生成的新 html 文件中

  2. 在 app 目錄下,創建的 html 模板以這種格式創建:名稱.tmpl.html,插件會根據這個模板生成最終的 html 頁面,並會進行自動的依賴

  3. 更新 webpack 的配置文件,新建一個 build 文件夾用來存放生成的文件

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: __dirname + '/app/main.js', // 入口文件
    output: {
        path: __dirname + '/build', // 出口文件所在文件夾
        filename: 'bundle.js' // 打包後的文件
    },
    // 啓動服務器:webpack-dev-server --open
    devServer: {
        contentBase: './public',//本地服務器所加載的頁面所在的目錄
        historyApiFallback: true,//不跳轉
        inline: true//實時刷新
    },
    // 關於 Babel 的配置,可以單獨在 .babelrc 中進行配置
    module: {
        rules: [
            // Babel 的一些簡單配置
            // 下載的依賴包:babel-core babel-loader babel-preset-env babel-preset-react react react-dom
            // 配置好後就可以使用 react 語法了
            {
                test: /(\.jsx|\.js)$/, // 處理的文件
                use: {
                    loader: 'babel-loader', // 使用的 loader
                    // 在 .babelrc 中進行配置
                    // options: {
                    //     presets: [
                    //         'env', 'react'
                    //     ]
                    // }
                },
                // 不需要處理的文件夾
                exclude: /node_modules/
            },
            // 安裝 postcss-loader 和 autoprefixer
            // PostCSS 代碼自動添加使用不同瀏覽器的 CSS 前綴
            // autoprefixer 自動添加前綴的插件
            {
                test: /\.css$/,
                use: [
                    {
                        loader: 'style-loader'
                    }, {
                        loader: 'css-loader',
                        // css模塊:所有的類名,動畫名都只作用於當前模塊,避免全局污染
                        options: {
                            modules: true, // 指定啓用css modules
                            // 指定css的類名格式
                            // localIdentName: '[name]__[local]--[hash:base64:5]'
                        }
                    }, {
                        // 需要新建 postcss.config.js 文件進行其他配置
                        loader: 'postcss-loader'
                    }
                ]
            }
        ]
    },
    plugins: [
        // 添加版權的插件
        new webpack.BannerPlugin('版權所有,翻版必究'),
        //new 一個這個插件的實例,並傳入相關的參數
        new HtmlWebpackPlugin({
            template: __dirname + '/app/index.tmpl.html'
        })
    ]
};

之後,正常的在終端執行:npm start 就可以進行新一輪的打包編譯了

3. 常用的插件之:Hot Module Replacement

Hot Module ReplacementHMR)插件允許在修改組件代碼後,自動刷新實時預覽修改後的效果

它是 webpack 裏的一個插件

如何配置:
1. 在 webpack.config.js 中添加 HMR 插件
2. 在 webpack Dev Server 中添加 “hot” 參數
3. 配置結束後,在 JS 模塊中執行一個 webpack 提供的 API 才能實現熱加載

思路:
1. Babelwebpack 是兩個獨立的工具
2. 兩者可以一起工作的同時,都可以通過插件擴展功能
3. HMR 是一個 webpack 插件,想讓他工作,還需要對模塊進行額外的配置
4. Babel 中有一個 react-transform-hmr 插件,可以讓 HMR 正常工作,而且不產生對模塊的額外配置影響

在 webpack.config.js 中的配置:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: __dirname + '/app/main.js', // 入口文件
    output: {
        path: __dirname + '/build', // 出口文件所在文件夾
        filename: 'bundle.js' // 打包後的文件
    },
    // 啓動服務器:webpack-dev-server --open
    devServer: {
        contentBase: './public', // 本地服務器所加載的頁面所在的目錄
        historyApiFallback: true, // 不跳轉
        inline: true, // 實時刷新
        hot: true // 配合 HMR 實現熱加載
    },
    plugins: [
        // 熱加載插件,還需要在 .babelrc 中的 "env" 進行配置
        new webpack.HotModuleReplacementPlugin()
    ]
};

安裝: cnpm install babel-plugin-react-transform react-transform-hmr --save-dev

在 Babel 中的配置:

{
    "presets": ["react", "env"],
    "env": {
        "development": {
            "plugins": [["react-transform", {
                "transforms": [{
                    "transform": "react-transform-hmr",

                    "imports": ["react"],

                    "locals": ["module"]
                }]
            }]]
        }
    }
}

配置完成之後,就可以在使用 React 時,進行熱加載模塊了

產品階段的構建

產品階段:主要是對打包的文件進行額外處理,如壓縮、優化、緩存,分離 CSSJS

創建一個 webapck.production.config.js 文件:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: __dirname + '/app/main.js', //已多次提及的唯一入口文件
    output: {
        path: __dirname + '/build',
        filename: 'bundle.js'
    },
    devtool: 'null', //注意修改了這裏,這能大大壓縮我們的打包代碼
    devServer: {
        contentBase: './public', //本地服務器所加載的頁面所在的目錄
        historyApiFallback: true, //不跳轉
        inline: true,
        hot: true
    },
    module: {
        rules: [{
            test: /(\.jsx|\.js)$/,
            use: {
                loader: 'babel-loader'
            },
            exclude: /node_modules/
        }, {
            test: /\.css$/,
            use: ExtractTextPlugin.extract({
                fallback: 'style-loader',
                use: [{
                    loader: 'css-loader',
                    options: {
                        modules: true
                    }
                }, {
                    loader: 'postcss-loader'
                }],
            })
        }]
    },
    plugins: [
        new webpack.BannerPlugin('朋友們注意版權哦~~'),
        new HtmlWebpackPlugin({
            template: __dirname + '/app/index.tmpl.html' //new 一個這個插件的實例,並傳入相關的參數
        }),
        new webpack.HotModuleReplacementPlugin() //熱加載插件
    ],
};

package.json 文件也需要配置:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack",
    "server": "webpack-dev-server --open",
    "build": "set NODE_ENV=production && webpack --config ./webpack.production.config.js --progress"
  },

優化插件

webpack 提供了一些優化插件,產品發佈階段所需的功能:

  1. OccurenceOrderPlugin :爲組件分配 ID,通過分析和優先考慮使用最多的模塊,並未他們分配最小 ID
  2. UglifyJsPlugin :壓縮 JS 代碼
  3. ExtractTextPlugin :分離 CSSJS 文件

上面的插件中,OccurenceOrderPluginUglifyJsPlugin 是內置插件,需要下載的只有:ExtractTextPlugin

cnpm install extract-text-webpack-plugin --save-dev

之後再 webpack.production.config.js 引用他們:

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: __dirname + '/app/main.js', //已多次提及的唯一入口文件
    output: {
        path: __dirname + '/build',
        filename: 'bundle.js'
    },
    devtool: 'null', //注意修改了這裏,這能大大壓縮我們的打包代碼
    devServer: {
        contentBase: './public', //本地服務器所加載的頁面所在的目錄
        historyApiFallback: true, //不跳轉
        inline: true,
        hot: true
    },
    module: {
        rules: [{
            test: /(\.jsx|\.js)$/,
            use: {
                loader: 'babel-loader'
            },
            exclude: /node_modules/
        }, {
            test: /\.css$/,
            // 分離 CSS,成爲一個單獨的文件
            use: ExtractTextPlugin.extract({
                fallback: 'style-loader',
                use: [
                    'css-loader',
                    'postcss-loader'
                ]
            })
        }]
    },
    plugins: [
        new webpack.BannerPlugin('朋友們注意版權哦~~'),
        new HtmlWebpackPlugin({
            template: __dirname + '/app/index.tmpl.html', //new 一個這個插件的實例,並傳入相關的參數
             // 壓縮HTML文件
            minify: {
                removeComments: true, // 移除HTML中的註釋
                collapseWhitespace: true // 刪除空白符與換行符
            }
        }),
        // 爲組件分配 ID,通過這個插件可以優先考慮使用最多的模塊,分配給他們最小的 ID
        new webpack.optimize.OccurrenceOrderPlugin(),
        // 壓縮 JS 文件
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            except: ['$super', '$', 'exports', 'require']    //排除關鍵字
        }),
        // 分離 CSS 和 JS 文件
        new ExtractTextPlugin('style.css')
    ],
};

之後再終端執行:npm run build 就可以進行產品階段的打包了

緩存

使用這種方式:

output: {
    path: __dirname + "/build",
    filename: "bundle-[hash].js"  // 添加 hash 值
},

添加 hash 之後,導致改變文件內容後的重新打包,文件名不同而文件越來越多,可以使用:clean-webpack-plugin 來進行清理

安裝他們:cnpm install clean-webpack-plugin --save-dev

在配置文件中進行響應的配置即可:

const CleanWebpackPlugin = require("clean-webpack-plugin");

    plugins: [
        ...// 這裏是之前配置的其它各種插件
        new CleanWebpackPlugin('build/*.*', {
            root: __dirname,
            verbose: true,
            dry: false
        })
    ]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章