webpack4-基礎配置

beth_miao發表於2019-02-14

webpack的安裝

安裝本地的webpack

yarn add webpack webpack-cli -D
複製程式碼

零配置執行

npx webpack         
npx webpack --mode production   // 預設為生產環境 會進行壓縮打包
npx webpack --mode development
複製程式碼

webpack_require 相當於是webpack自己實現的一套模組化的機制

手動配置

預設配置檔名稱為 webpack.config.js

module.exports = {
    mode: 'development',  // 模式 預設兩種 production development
    entry: './src/index.js',  // 入口
    output: {
        filename: 'bundle.[hash:8].js',         // 出口 [hash:8]顯示8位hash值
        path: path.resolve(__dirname, 'build')    // path必須是一個絕對路徑 path.resolve幫我們把相對路徑解析成絕對路徑
    },
}
複製程式碼

在webpack-cli/bin/config-yargs中可以看到有這樣一行 defaultDescription: "webpack.config.js or webpackfile.js" 即配置檔名稱為webpack.config.js or webpackfile.js 當然我們也可以手動指定配置檔案的名稱

npx webpack --config filename
複製程式碼

也可以通過在package.json中的script裡配置

"scripts":{
    "build": "webpack --config webpack.config.js"   //  webpack.config.js可改為自定義檔名
},
複製程式碼
npm run build
複製程式碼

如果一定要手動傳參也可以通過多加兩個-

"scripts":{
    "build": "webpack"   //  webpack.config.js可改為自定義檔名
},
複製程式碼
npm run build -- --config webpack.config.js
複製程式碼

到目前為止,我們的配置依然很弱,只能打包js檔案,接下來我們繼續新增更多的配置

下面我們希望能夠通過http://localhost 這樣的方式來啟動一個服務, 我們可以通過webpack內建的一個服務 webpack-dev-server (內部是通過express實現的)

yarn add webpack-dev-server -D
複製程式碼

現在我們可以通過

npx webpack-dev-server
複製程式碼

當然也同樣可以通過package.json設定

"scripts": {
        "dev": "webpack-dev-server",
        "build": "webpack --config webpack.config.js"
    },
複製程式碼

然後執行

npm run dev
複製程式碼

同時我們可以給在webpack.config.js中對webpack-dev-server進行配置

devServer: {    // 開發伺服器的配置
        port: '3000',
        progress: true,
        contentBase: './build',    
        open: true
    },
複製程式碼

html外掛

期望:動態生成build/index.html, 並把打包後的檔案引入到index.html

在src目錄下建index.html,這時我們需要使用外掛HtmlWebpackPlugin,plugin的用法大都相同,HtmlWebpackPlugin是一個類,new一下就可以了

plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',     //  template檔案
            filename: 'index.html',            // 生成的template檔名稱 預設為index.html
            hash: true,                       // 在生成的html中新增引用hash
            minify: {
                removeAttributeQuotes: true,  // 去除雙引號
                collapseWhitespace: true,     // 去除空行
            }
        }),
    ],
複製程式碼

到這裡可以看到我們既可以通過在配置output的時候通過filename: bundle.[hash:8].js 來給生成檔案新增hash,也可以通過HtmlWebpackPlugin的配置hash來實現,兩者新增hash的方式分別為 bundle.12345678.js和 bundle?12345678

而通過filename: bundle.[hash:8].js這種方式實現,我們還需要再做一步,就是在每次重新打包的時候把舊的檔案刪除 // todo

樣式處理

我們知道,webpack預設只支援js模組,那麼我們怎麼處理css/less/scss等模組呢?這時候就需要loader上場了

You may need an appropriate loader to handle this file type.
複製程式碼
module: {           // 模組
        rules: [    // 規則
            // css-loader 主要用來解析@import這種語法 
            // style-loader 把樣式插入頁面
            // loader特點,功能單一 多個loader可以協作
            // 一個loader可以使用字串,多個可以使用陣列, 需要傳入引數時可以使用物件方式
            // loader的順序,預設為從右向左, 從下到上執行  webpack選擇了compose方式
            // {                    
            //     test: '/\.css$/', use: [
            //         { loader: 'css-loader', options: {} }        // 物件方式
            //     ]
            // },
            { test: /\.css$/, use: ['style-loader', 'css-loader'] },
        ]
    },
複製程式碼

less、sass檔案同理, 以scss檔案為例:

{
    test: /\.css$/, use: [
        { loader: 'style-loader', options: { insertAt: 'top' } },        // 物件方式  insertAt插入位置
        { loader: 'css-loader', options: {} },
    ]
},
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
複製程式碼

css抽離

webpack4中,css抽離需要外掛 mini-css-extract-plugin (注意不再是extract-text-webpack-plugin)

new miniCssExtractPlugin({
    filename: 'main.css',   // 抽離出的css的檔名
}),
複製程式碼

同時在module.rules中做如下修改以避免重複插入:

- // { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
+ { test: /\.scss$/, use: [miniCssExtractPlugin.loader, 'css-loader', 'sass-loader'] },
複製程式碼

自動新增字首

我們可以使用postcss-loader autoprefixer來實現

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

+ { test: /\.scss$/, use: [miniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'] },
複製程式碼

在根目錄下新建postcss.config.js

module.exports = {
    plugins: [
        require('autoprefixer'),    // 自動新增字首
    ]
}
複製程式碼

壓縮

此時我們設定mode為production,發現js和html都已經是壓縮過的了,可是css檔案卻沒有。我們這裡引入另外一個外掛:optimize-css-assets-webpack-plugin來優化css資源

let OptimizeCss = require('optimize-css-assets-webpack-plugin');
plugins: [       
        ...,                        
        new OptimizeCss(),
]
複製程式碼

當然我們也可以通過uglifyjs-webpack-plugin來壓縮我們的js檔案

let UglifyjsPlugin = require('uglifyjs-webpack-plugin');
plugins: [       
        ...,                        
        new UglifyjsPlugin(),
]
複製程式碼

es6

我們希望打包後的檔案可以把es6語法轉為es5,可以通過babel-loader幫我們實現

// src/a.js
console.log('this is a');

const fn = () => {
    console.log('fn');
}
複製程式碼

安裝babel依賴模組

yarn add babel-loader @babel/core @babel/preset-env -D
複製程式碼
{
    test: /\.js|jsx$/, use:
    {
        loader: 'babel-loader', options: {
            presets: ['@babel/preset-env']
        }
    }
},
複製程式碼

es7

現在寫es6的語法沒有問題了,但是我們有可能用到es7的語法, 比如類的寫法,這時候我們還需要藉助一個外掛:@babel/plugin-proposal-class-properties 又比如裝飾器的寫法,我們可以藉助@babel/plugin-proposal-decorators來實現

{
    test: /\.js|jsx$/, use:
    {
        loader: 'babel-loader', options: {
            presets: ['@babel/preset-env'],
            plugins: [
                ["@babel/plugin-proposal-decorators", { "legacy": true }],  // 支援es7的裝飾器的寫法 要放在前面
                '@babel/plugin-proposal-class-properties',       // 支援es7的類的寫法 
            ]
        }
    }
},
複製程式碼

這裡需要注意的是@babel/plugin-proposal-decorators要放在@babel/plugin-proposal-class-properties前面。

es6新的API

babel只會幫我們把es6新的語法轉成es5,但是對於新的API如:promise, generater 等我們還需要藉助一個包 @babel-polyfill(但是比較大) 同時我們可以藉助一個外掛--@babel/plugin-transform-runtime 做了一定優化,如程式碼抽離

js語法校驗 eslint

yarn add eslint eslint-loader
複製程式碼
{
    test: /\.js|jsx$/,
    use: {
        loader: 'eslint-loader',
        options: {
            enforce: 'pre', // pre post 
        }
    }
},
複製程式碼

接下來就可以使用自己配置好的.eslintrc.json檔案(放在根目錄下),當然我們也可以到eslint官網,手動進行配置,然後下載eslintrc.json,只要加個.就行了。

全域性變數的引入

  1. 簡單粗暴
    import $ from 'jquery';
    console.log($)  
    console.log(window.$) // undefined
複製程式碼
  1. 內聯loader expose-loader 暴露到全域性的loader,用法如下:
import $ from 'expose-loader?$!jquery';
console.log($)  
console.log(window.$) // undefined
複製程式碼
  1. webpack expose-loader 只能通過window訪問
{
    test: require.resolve('jquery'),
    use: 'expose-loader?$'
},

// index.js
console.log(window.$)  
複製程式碼
  1. webpack內建外掛
let webpack = require('webpack');

new webpack.ProvidePlugin({     // 在每個模組中都注入$
    $: 'jquery',
}),

// index.js
console.log($);         // 都可以訪問
console.log(window.$)  
複製程式碼
  1. cdn引入+webpack
externals: {    // 外部引入,不需要打包
    jquery: '$',
},

// index.js
import $ from 'jquery';     // 雖然引入但是不會再打包
console.log($);
複製程式碼

圖片處理

我們使用圖片的場景有兩種:

  1. 在js中建立圖片來引用
  2. 再css中使用,background
  3. img標籤的使用
// index.js
let img = new Image();
img.src = require('./logo.png');
document.body.appendChild(img);
複製程式碼

這時我們需要藉助 file-loader 了

{
    test: /\.png|jpg|gif|jpeg$/,
    loader: 'file-loader',
    options: {

    }
},
複製程式碼
// index.js
import logo from './logo.png';  // 返回一個新的檔案 好處是可以重新命名圖片

let img = new Image();
img.src = logo;
document.body.appendChild(img);

// a.css
body{
    color: yellow;
    background: url('./logo.png') no-repeat;
}

複製程式碼

ok,發現前兩種都沒有什麼問題,可是第三種直接寫在html中的卻不行

<body>
    <img src='./logo.png' alt=""/>
    <!-- 模版 -->
</body>
複製程式碼

處理直接寫在html裡的圖片,還需要用到另一個loader:

{
    test: /\.html/,
    use: 'html-withimg-loader'
},
複製程式碼

重新啟動就好了。

檔案打包分類

如果想要做更多的限制呢,比如說對打包圖片大小的限制打包成base64以減少http請求(base64會比原始檔大1/3左右),我們可以使用 url-loader

{
    test: /\.png|jpg|gif|jpeg$/,
    loader: 'url-loader',
    options: {
        limit: 4 * 1024,        // 圖片大小限制值
        outputPath: '/img/',     // 輸出目錄
        publicPath: 'http://58.com'     // 新增打包後的圖片域名
    }
},
複製程式碼

打包多頁面應用

基本配置如下:

let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: {
        home: './src/index.js',
        other: './src/other.js',
    },
    output: {
        filename: '[name].js',               // name為變數,根據entry的命名生成對應打包後的檔名稱
        path: path.resolve(__dirname, 'dist'),
    },
    plugins: [
        new HtmlWebpackPlugin({             // 這裡需要new多個HtmlWebpackPlugin
            template: './src/index.html',
            filename: 'home.html',
            chunks: ['home']                // html依賴,決定了打包後的哪些檔案插入該模版中, 可以寫多個,且有順序
        }),
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'other.html',
            chunks: ['other', 'home']
        }),
    ],
}
複製程式碼

配置source-map

// devtool: 'source-map',    // 增加對映檔案 會單獨生成一個sourcemap檔案,出錯了會標示當前出錯的列和行 特點 大 全
    devtool: 'eval-map',
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'home.html',
        }),
    ],
複製程式碼

watch用法

output: {
        filename: '[name].js',               // name為變數,根據entry的命名生成對應打包後的檔名稱
        path: path.resolve(__dirname, 'dist'),
    },
    watch: true,    // 實時編譯打包
    watchOptions: { // 監控選項
        poll: 1000, // 每秒訪問多少次
        aggregateTimeout: 500, // 防抖
        ignored: /node_modules/
    },
複製程式碼

外掛使用

  • CleanWebpackPlugin 每次打包刪除dist
  • CopyWebpackPlugin // copy檔案目錄
  • BannerPlugin // 給打包後的檔案新增頭註釋
plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'home.html',
        }),
        new CleanWebpackPlugin('./dist'),   // 傳入要刪除的目錄 也可傳陣列
        new CopyWebpackPlugin([{ from: './src/static', to: './dist' }]),   //需要拷貝的目錄 必須是arr
        new webpack.BannerPlugin('make 2019 by beth.miao'),
    ],
複製程式碼

webpack跨域問題 配置代理 proxy

proxy: {
            '/api': {
                target: 'http://localhost:3001',
                pathRewrite: { '/api': '' }
            }
        }
複製程式碼

resolve 屬性的配置

resolve: {  // 解析第三方包 common
        modules: [path.resolve('node_modules')],
        // mainFields: ['style', 'main'],
        // mainFiles: '',
        alias: {
            bootstrap: 'bootstrap/dist/css/bootstrap.css',
        },
        extensions: ['.js', '.css', '.json', 'vue'],    // 引入路徑字尾名處理
    },
複製程式碼

相關文章