使用bundle-loader非同步載入react-router

caozheng550發表於2019-02-16

主要技術棧

React,
React-redux,
React-router,
Typescript,
antd,
Immutable,

需求

因為專案是一個SPA頁面,隨著專案的不斷迭代,入口檔案逐漸增大(app.js),所以想減少入口檔案的體積。

方案

方案一:

  • webpack(require.ensure)+ react-router

因為使用require.ensure需要足夠深的檔案層級並且在對應檔案需要定義index.ts檔案作為require.ensure入口,書寫起來比較麻煩,而且相對於工作量來說也是大有增加(具體的實現方案網上也比較多),故沒有選擇。

方案二:

  • webpack(bundle-loader)+ react-router(lazyLoadComponent)

優勢:
1、不用過多的檔案層級,保持檔案的prue。
2、不用自己定義require.ensure

安裝bundle-loader

npm install bundle-loader --save-dev

webpack中載入loader(這裡使用的是webpack2)

export default {
    entry: entries,
    output: {
        path: __dirname,
        filename: `${dist}/js/[name].js`, // 這裡的dist是我定義的變數
        publicPath: `https://127.0.0.1/`, // 這裡很關鍵=>單獨拿出來解釋
    },
    resolve: {
        extensions: [
            `.js`,
            `.jsx`,
            `.ts`,
            `.tsx`,
            `.css`,
            `.less`,
            `.json`,
            `.gif`,
            `.html`,
            `.png`,
            `.webp`,
            `.jpg`,
        ],
    },
    module: {
        rules: [
            {
                test: /.jsx?$/,
                loader: `babel-loader`,
            },
            {
                test: /.(tsx|ts)/,
                exclude: [
                    path.resolve(__dirname, "src/pages/")
                ],
                loader: `ts-loader`,
            },
            {
                test: /src\pages(\.*).(tsx|ts)/,
                use: [
                    `bundle-loader?lazy`,
                    `ts-loader`,
                ],
            },
            {
                test: /.(less)?$/,
                use: [
                    `style-loader`,
                    `css-loader`,
                    `less-loader`,
                    
                ],
                // loader: `style!css!less`
            },
            {
                test: /.css$/,
                loader: extractCSS.extract({
                    fallbackLoader: `style-loader`,
                    loader: `css-loader`,
                }),
            },
            {
                test: /.(jpg|png|gif|jpeg)?$/,
                loader: `url-loader?limit=20480&name=${dist}/images/[name].[hash:8].[ext]`,
            },
            {
                test: /.(eot|woff(2)?|ttf|svg)?(@.+)*$/,
                loader: `url-loader?limit=20480&name=${dist}/other/[name].[hash:8].[ext]`,
            }
        ],
    },
    plugins: [
        

        /**
         * DllReferencePlugin
         */
        new DllReferencePlugin({
            context: __dirname,
            manifest,
        }),

        /**
         * CommonsChunkPlugin
         */
        new CommonsChunkPlugin({
            name: `common`,
            filename: `${dist}/common.js`,
            minChunks: 2,
            chunks: entriesKey
        }),
    ],
    devtool: `cheap-module-source-map`,
    devServer: {
        port,
        https,
        contentBase: ROOTPATH,
        compress: true,
        inline: true,
        quiet: false,
        stats: { colors: true },
        watchOptions: {
            aggregateTimeout: 300,
            poll: true,
        },
        headers: {
            `Access-Control-Allow-Origin`: `*`,
        },
    }
};

配置詳解

            {
                test: /src\pages(\.*).(tsx|ts)/,
                use: [
                    `bundle-loader?lazy`,
                    `ts-loader`,
                ],
            },

test:是我寫的正則用來匹配我需要非同步載入的檔案,並且使用use中的bundle-loader->ts-loader。
(ps:在ts-loader編譯全域性檔案時,需要exclude[需要非同步載入的路徑])

route配置

// router.tsx

import * as EffectiveCustomer from `./pages/wuyoubao/customerManagement/effectiveCustomer`;
function lazyLoadComponent(lazyModule) {  
    return (location, cb) => {
        lazyModule(module => cb(null, module.default));
    }
}

<Router history={history}>
    <Route path="/admindev/basic/common" {...this.props} {...routerProps}>
        <IndexRoute getComponent={lazyLoadComponent(Index)}/>
        <Route path="/api/wuyoubao/effective" getComponent={lazyLoadComponent(EffectiveCustomer)}/>
    </Route>
</Router>

注意事項

因為router.tsx中引用的tsx全部是被bundle-loader編譯的,而bundle-loader對ES6特性支援不是很好,比如:

  • ES6可以解析

import { OrderInfoMessage } from `./fundConfirmCom/fundConfirmInfoOrder`;
console.log(OrderInfoMessage)
// 可以解析

但是這種方式bundle-loader解析不了,它所能解析的方式:

  • bundle-loader解析module

import { OrderInfoMessage } from `./fundConfirmCom/fundConfirmInfoOrder`;
console.log(OrderInfoMessage) // undefined
// bundle-loader可以識別的方式:
import * as OrderInfoMessage from `./fundConfirmCom/fundConfirmInfoOrder`;
console.log(OrderInfoMessage) // 可以解析

相關文章