webpack4+react多頁應(yīng)用

前言

上篇內(nèi)容從零開始搭建webpack4的react項(xiàng)目,這里只說多頁相關(guān)的配置。上篇文章地址:webpack4+react從零開始搭建項(xiàng)目

先看下多頁的文件目錄結(jié)構(gòu):


image.png

這里我們有一個(gè)公用的html模板,app1和app2的兩個(gè)多頁文件。

webpack.config.js配置主要更改兩個(gè)部分:
一、entry里面是鍵值對結(jié)構(gòu):

module.exports = (env, argv) => {
    return {
        entry: {
          app1: './src/app1/index.js',
          app2: './src/app2/index.js'
        }
    }
}

看過我上篇的同學(xué)肯定會問,上篇不是數(shù)組嘛,還能加babel-polyfill,所以也可以是這種配置:

module.exports = (env, argv) => {
    return {
        entry: {
          entry: {
            app1: ["babel-polyfill", './src/app1/index.js'],
            app2: ["babel-polyfill", './src/app2/index.js']
        }
    }
}

二、plugins里的new HtmlWebpackPlugin變成數(shù)組形式:

module.exports = (env, argv) => {
  return {
    plugins: [
      // ...
      new HtmlWebpackPlugin({
        chunks:['app1'], //添加引入的js,也就是entry中的key
        filename:'app1.html', // 輸出頁面,如http://localhost:3000/app1.html就能看到第一個(gè)模板
        hash:true,
        title:'第一個(gè)頁面',
        template: './public/index.html' //模板地址
      }),
      new HtmlWebpackPlugin({
          chunks:['app2'], //添加引入的js,也就是entry中的key
          filename:'app2.html', // 輸出頁面
          hash:true,
          title:'第二個(gè)頁面',
          template: './public/index.html' //模板地址
      })
    ]
  }
}

簡單配置完畢,如果想動態(tài)配置,可以這么改,直接貼出所有配置,主要是這兩個(gè)函數(shù):,我覺得怎么封裝好理解是自己的事情,建議大家最好自己封裝一套,最重要的方法就一個(gè)glob.sync('src/**/index.js')獲取src下第一層級文件夾下的index.js。

const webpack = require('webpack');//引入webpack
const path = require('path');//引入nodejs路徑模塊,處理路徑用的
const glob = require('glob');//glob,這個(gè)是一個(gè)全局的模塊,動態(tài)配置多頁面會用得著
const HtmlWebpackPlugin = require('html-webpack-plugin'); //這個(gè)是通過html模板生成html頁面的插件,動態(tài)配置多頁面用得著
const CleanWebpackPlugin = require('clean-webpack-plugin'); // 清除打包的源文件,再打包,避免文件重復(fù)
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//分離css,webpack4推薦的分離css的插件
const autoprefixer = require('autoprefixer');//給css自動加瀏覽器兼容性前綴的插件
const os = require('os');//這個(gè)nodejs模塊,會幫助我們獲取本機(jī)ip
const portfinder = require('portfinder');//這個(gè)幫助我們尋找可用的端口,如果默認(rèn)端口被占用了的話
const fs = require('fs');//處理文件用的

//動態(tài)加時(shí)間戳,發(fā)布不需要刷新瀏覽器
function stamp(){
  var date = new Date();
  date = Date.parse(date);
  return date;
}

//端口占用動態(tài)+1
var ports = fs.readFileSync('./port.json', 'utf8');
ports = JSON.parse(ports);
portfinder.basePort = "3000";
portfinder.getPort(function(err, port) {
    ports.data.port = port;
    ports = JSON.stringify(ports,null,4);
    fs.writeFileSync('./port.json',ports);
});

//獲取本機(jī)ip
function getIPAdress(){  
  const interfaces = os.networkInterfaces();  
  for(let devName in interfaces){  
      const iface = interfaces[devName];  
      for(let i=0;i<iface.length;i++){  
          const alias = iface[i];  
          if(alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal){  
              return alias.address;  
          }  
      }  
  }  
} 

module.exports = (env, argv) => {
  const devMode = argv.mode !== 'production'

  const webpackConfig = {
    entry: {},
    output:{
      path:path.resolve(__dirname, './dist/'),
      filename:`[name]-${stamp()}.js`
    },
    //設(shè)置開發(fā)者工具的端口號,不設(shè)置則默認(rèn)為3000端口
    devServer: {
      port: ports.data.port, //端口號
      overlay: true, // 開啟錯(cuò)誤調(diào)試,
      hot: true,  //是否開啟hot-module-replacement
      https: false, // 如果需要用https請開啟,如http2
      compress:false, //是否啟用 gzip 壓縮。boolean 為類型,默認(rèn)為 false
      open: false, // 啟動且第一次構(gòu)建完時(shí)自動用你系統(tǒng)上默認(rèn)的瀏覽器去打開要開發(fā)的網(wǎng)頁。
      stats: "errors-only", // 只展示錯(cuò)誤信息,避免大量無用日志
      host: getIPAdress()  //獲取本機(jī)器ip
    },
    module:{
      rules:[
        {
          test:/\.(js|jsx)$/,
          exclude:/node_modules/,
          use: {
            loader: "babel-loader"
          }
        },
        {
          test: /\.html$/,
          use: [{
              loader: "html-loader",
              options: {
                  minimize: true
              }
          }]
      },
      {
          test: /\.css$/,
          use: [
              devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
              'css-loader',
              {
                    loader: "postcss-loader",
                    options: {
                          plugins: [
                              require("autoprefixer") /*在這里添加*/
                          ]
                    }
              }
          ]
      },
      {
          test: /\.less$/,
          use: [
              devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
              'css-loader',
              'less-loader',
              {
                  loader: "postcss-loader",
                  options: {
                      plugins: [
                          require("autoprefixer") /*在這里添加*/
                      ]
                  }
              }
          ]
      },
      {
          test: /\.(png|svg|jpg|gif)$/,
          use: [
              'file-loader'
          ]
      }
        
      ]
    },
    plugins: [
      new CleanWebpackPlugin(
        ['dist'],  
        {
          root: __dirname,              
          verbose: true,              
          dry:   false              
        }
      ),
      new MiniCssExtractPlugin({
        filename: "[name].css",
        chunkFilename: "[id].css"
      })
    ]
  }

  // 獲取指定路徑下的入口文件
  function getEntries(globPath) {
    const files = glob.sync(globPath),
    entries = {};
    files.forEach(function(filepath) {
      const split = filepath.split('/');
      const name = split[split.length - 2];
      entries[name] = './' + filepath;
    });
    return entries;
  }
      
  const entries = getEntries('src/**/index.js');
  
  Object.keys(entries).forEach(function(name) {
    webpackConfig.entry[name] = entries[name]; // entry拼接對象鍵值對
    const plugin = new HtmlWebpackPlugin({
      filename: name + '.html',
      template: './public/index.html',
      inject: true,
      chunks: [name]
    });
    webpackConfig.plugins.push(plugin); //new HtmlWebpackPlugin數(shù)組 
  })

  return webpackConfig
};

這里多了三個(gè)方法:
1、動態(tài)加時(shí)間戳 stamp(),如果我們發(fā)布不打tag,那么瀏覽器就有緩存,每次發(fā)布,就需要強(qiáng)刷頁面,很可能被提成bug,這里可以添加時(shí)間戳,然后在output方法里面加入即可

output:{
      path:path.resolve(__dirname, './dist/'),
      filename:`[name]-${stamp()}.js`
    }

2、獲取本機(jī)ip,我們之前看頁面是localhost,如果想分享,就需要ipconfig,我們自動獲取,方便了一些。
第一步根目錄創(chuàng)建port.json

{
    "data": {
        "port": 3000
    }
}

第二步在webpack.config.js寫好方法:

var ports = fs.readFileSync('./port.json', 'utf8');
ports = JSON.parse(ports);
portfinder.basePort = "3000";
portfinder.getPort(function(err, port) {
    ports.data.port = port;
    ports = JSON.stringify(ports,null,4);
    fs.writeFileSync('./port.json',ports);
});

第三步webpack.config.js配置devServer

devServer: {
      port: ports.data.port, //端口號

3、獲取本機(jī)ipgetIPAdress,配置devServer

devServer: {
  host: getIPAdress()  //獲取本機(jī)器ip
}

github地址:https://github.com/muyu-zhilu/webpack-react-multipage

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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