webpack4入門

前提

  • 已安裝node(版本號(hào)>4.0,已自帶NPM)
  • mac機(jī)器
  • 有一個(gè)空目錄

要實(shí)現(xiàn)的功能

  • JSX語法,ES6語法,LESS語法編寫的模塊轉(zhuǎn)化為瀏覽器可執(zhí)行的模塊
  • 代碼的混淆壓縮
  • 多頁面多入口
  • 提取公共文件

無webpack.config.js配置打包

  1. 快速構(gòu)建package.json文件。
    npm init -y

  2. 安裝webpack4及其命令行接口
    npm i webpack webpack-cli --save-dev

  3. package.json文件增加build參數(shù)

"scripts": {
  "build": "webpack"
}
  1. 創(chuàng)建./src/index.js文件
    增加內(nèi)容
console.log(`這是入口文件`);
  1. 終端執(zhí)行npm run build
    目錄下多了一個(gè)./dist/main.js。
    這個(gè)文件是webpack對(duì)./src/index.js的打包結(jié)果。

productiondevelopment模式

  1. 修改package.json文件的scripts字段
"scripts": {
  "dev": "webpack --mode development",
  "build": "webpack --mode production"
}
  1. 分別執(zhí)行npm run devnpm run build
    你會(huì)看到./dist/main.js不同的變化。
    production模式下,默認(rèn)對(duì)打包的進(jìn)行minification(文件壓縮),Tree Shaking(只導(dǎo)入有用代碼),scope hoisting(作用域提升)等等操作。
    總之是讓打包文件更小。
    development模式下,對(duì)打包文件不壓縮,同時(shí)打包速度更快。

如果沒指定任何模式,默認(rèn)是production模式。

ES6和React

  1. 安裝對(duì)應(yīng)依賴包
    npm i babel-core babel-loader babel-preset-env react react-dom babel-preset-react --save-dev

  2. 新建.babelrc文件,進(jìn)行相關(guān)配置

{
  "presets": ["env", "react"]
}
  1. 新建webpack.config.js文件,進(jìn)行相關(guān)配置
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
};
  1. 新增./src/app.js以及修改./src/index.js
    ./src/app.js內(nèi)容如下:
import React from "react";
import ReactDOM from "react-dom";
const App = () => {
  return (
    <div>
      <p>React here!</p>
    </div>
  );
};
export default App;
ReactDOM.render(<App />, document.getElementById("app"));

./src/index.js內(nèi)容如下:

import App from "./App";
  1. 終端執(zhí)行npm run build

使用html-webpack-plugin插件對(duì)html進(jìn)行打包

新建./src/index.html文件,內(nèi)容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>webpack4入門</title>
</head>
<body>
    <div id="app">
    </div>
</body>
</html>

安裝依賴包。

npm i html-webpack-plugin html-loader --save-dev

修改webpack.config.js配置。

const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: "html-loader",
            options: { minimize: true }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebPackPlugin({
      template: "./src/index.html",
      filename: "./index.html"
    })
  ]
};

終端執(zhí)行npm run build命令。
你會(huì)看到項(xiàng)目多了個(gè)./dist/index.html文件。

使用webpack-dev-server插件

安裝依賴包。
npm i webpack-dev-server --save-dev

修改package.json文件。

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

修改webpack.config.js文件,新增devServer配置。

devServer: {
    contentBase: require('path').join(__dirname, "dist"),
    compress: true,
    port: 8033,
    host: "127.0.0.1",
}

終端執(zhí)行npm run start便可以啟動(dòng)webpack dev server。

使用Hot Module Replacement

Hot Module Replacement有針對(duì)React,Vue,Redux,Angular,樣式等等。
這里我們以React Hot Loader為例。

安裝依賴包。

npm i react-hot-loader --save-dev

修改.babelrc文件,新增plugins選項(xiàng)。

{
  "plugins": ["react-hot-loader/babel"]
}

修改webpack.config.js文件。

const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");  
const webpack = require('webpack'); // 新增
module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            },
            {
                test: /\.html$/,
                use: [
                    {
                        loader: "html-loader",
                        options: { minimize: true }
                    }
                ]
            }
        ]
    },
    devtool: 'inline-source-map',
    plugins: [
        new HtmlWebPackPlugin({
            template: "./src/index.html",
            filename: "./index.html"
        }),
        new webpack.NamedModulesPlugin(), // 新增
        new webpack.HotModuleReplacementPlugin() //新增
    ],
    devServer: {
        contentBase: path.join(__dirname, "dist"),
        compress: true,
        port: 8033,
        host: "127.0.0.1",
        hot: true // 新增
    }
};

修改./src/app.js文件內(nèi)容如下:

import React from "react";
import ReactDOM from "react-dom";
import { hot } from 'react-hot-loader' // 新增

const App = () => {
  return (
    <div>
      <p>這是一個(gè)測試文件!真得是動(dòng)態(tài)更新啊</p>
      <div>好棒棒啊</div>
    </div>
  );
};
export default hot(module)(App); // 修改
ReactDOM.render(<App />, document.getElementById("app"));

終端執(zhí)行npm run start便可以啟動(dòng)webpack dev server。
然后修改./src/app.js看下效果。

動(dòng)態(tài)加模塊

  • 動(dòng)態(tài)加載普通JS模塊
    修改.babelrc文件添加"syntax-dynamic-import"插件
{
    "presets": [
        "env",
        "react"
    ],
    "plugins": ["react-hot-loader/babel","syntax-dynamic-import"]
}

然后在業(yè)務(wù)代碼文件使用import語法即可

import('模塊路徑').then(mod => {
  someOperate(mod); //mod是module的簡寫,表示加載成功后的異步組件
});

如果沒有使用syntax-dynamic-import插件會(huì)導(dǎo)致構(gòu)建失敗,并提示:

Module build failed: SyntaxError: 'import' and 'export' may only appear at the top level
  • 動(dòng)態(tài)加載React模塊
    如同動(dòng)態(tài)加載普通JS模塊,修改.babelrc文件添加"syntax-dynamic-import"插件。
    然后安裝react-loadable這個(gè)NPM包
npm install react-loadable --save

接著如下方式引入React組件模塊即可。

import Loadable from 'react-loadable';

const LoadableBar = Loadable({
  loader: () => import('react組件模塊路徑'),
  loading() {
    return <div>Loading...</div>
  }
});

class MyComponent extends React.Component {
  render() {
    return <LoadableBar/>;
  }
}

多頁面多入口打包

修改webpack.config.js如下

...
entry: {
    // 把html 加入 entry。目的是修改html文件也能hot reload。
    // 不要在生產(chǎn)環(huán)境這么做。因?yàn)檫@會(huì)導(dǎo)致 chunk 文件包含了無用的 html 片段。
    page0: ['./src/pages/page0/index.js','./src/template/page0.html'],
    page1: './src/pages/page1/index.js',
},
plugins: [
    new HtmlWebPackPlugin({
        template: "./src/template/page0.html",
        filename: "./page0.html",
        chunksSortMode: 'none',
        chunks: ["page0"],
    }),
    new HtmlWebPackPlugin({
        template: "./src/template/page1.html",
        filename: "./page1.html",
        chunksSortMode: 'none',
        chunks: ["page1"],
    }),
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
],  
...

對(duì)應(yīng)文件存放目錄結(jié)構(gòu)修改如圖


文件存放目錄結(jié)構(gòu)

第三方庫和業(yè)務(wù)代碼分開打包

基本策略是:

  1. 提取樣式文件
  2. 分離公共文件(運(yùn)行時(shí),node_modules,業(yè)務(wù)的共同依賴)
  3. 懶加載大文件
    react-loadable
簡單分離公共文件和業(yè)務(wù)文件
optimization: {
    splitChunks: {
        cacheGroups: {
            commons: {
                name: 'common',
                priority: 10,
                chunks: 'initial'
            }
        }
    }
}
分離業(yè)務(wù)文件,node_modules,業(yè)務(wù)的共同依賴,webpack運(yùn)行時(shí)
runtimeChunk: {
    name: 'manifest'
},
optimization: {
    splitChunks: {
        cacheGroups: {
            vendors: {
                test: /[\\/]node_modules[\\/]/,
                name: "vendors",
                chunks: "all"
            },
            commons: {
                chunks: "all",
                name: 'commons',
                /**
                 * minSize 默認(rèn)為 30000
                 * 想要使代碼拆分真的按照我們的設(shè)置來
                 * 需要減小 minSize
                 */
                minSize: 0,
                // 至少為兩個(gè) chunks 的公用代碼
                minChunks: 2
            }
        }
    }
}

這里打包出來的文件有vendros.js(node_modules),commons.js(業(yè)務(wù)的共同依賴),manifest.js(webpack運(yùn)行時(shí)),業(yè)務(wù)文件

手動(dòng)指定業(yè)務(wù)的共同依賴
entry: {
    // html可實(shí)時(shí)刷新修改
    page0: ['./src/pages/page0/index.js', './src/template/page0.html'],
    page1: './src/pages/page1/index.js',
    page2: './src/pages/page2/index.js',
    pageCommon: ['./src/common/page0-1.js', './src/common/page0-2.js'],
},
optimization: {
    runtimeChunk: {
        name: 'manifest'
    },
    splitChunks: {
        cacheGroups: {
            vendors: {
                test: /[\\/]node_modules[\\/]/,
                name: "vendors",
                chunks: "all"
            },
        }
    }
},
plugins: [
    new HtmlWebPackPlugin({
        template: "./src/template/page0.html",
        filename: "./page0.html",
        chunksSortMode: 'none',
        chunks: ["page0", "pageCommon", "vendors","manifest"],
    }),
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
],

手動(dòng)指定共同依賴后,就不要再讓webpack自動(dòng)分析共同依賴,否則手動(dòng)的共同依賴打包出來不生效。

參考

https://www.valentinog.com/blog/webpack-4-tutorial/
https://github.com/fenivana/webpack-and-spa-guide
https://segmentfault.com/a/1190000014685887

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容