【webpack系列】從零搭建 webpack4+react 腳手架(四)


經過三個章節的學習,你已經學會搭建了一個基於webpack4的react腳手架。如果要更改配置,比如,你希望把編譯后的js文件和css文件等單獨放dist下的static目錄下,你想想,是不是有點麻煩。你要去瀏覽webpack的配置文件,找到哪些配置項,然后去更改它,我們希望有個參數配置文件,只要更改參數配置,而無需更改webpack的配置文件。

1 添加參數配置文件
(1)在根目錄創建config文件夾,在config文件夾內新建一個index.js文件,文件內容如下:
    'use strict'

    const path = require('path')

    module.exports = {
        dev: {
            assetsSubDirectory: 'static',
            assetsPublicPath: '/',
        },
        build: {
            assetsRoot: path.resolve(__dirname, '../dist'),
            assetsSubDirectory: 'static',
            assetsPublicPath: '/',
        }
    }

我們定義了一部分配置參數,顧名思義,dev屬性下的參數配置是針對開發環境,build屬性下的參數配置是針對生產環境的。其中,assetsRoot是編譯后的文件存放根路徑,assetsSubDirectory是資源文件編譯后存放的文件夾名稱,assetsPublicPath是公共的路徑。

(2)修改webpack.base.conf.js,如下
    const path = require('path');
    const config=require('../config');
    const APP_PATH = path.resolve(__dirname, '../app');

    module.exports = {
        entry: {
            app: './app/index.js',
            framework: ['react', 'react-dom'],
        },
        output: {
            path: config.build.assetsRoot,
            filename: '[name].js',
            publicPath: process.env.NODE_ENV === 'production'
              ? config.build.assetsPublicPath
              : config.dev.assetsPublicPath
          },
        module: {
            rules: [
                {
                    test: /\.js?$/,
                    use: "babel-loader",
                    include: APP_PATH
                }
            ]
        }
    };

注意:我們在webpack.base.conf.js內配置了filename,那么dev環境下默認使用該配置,可以刪除webpack.dev.conf.js內關於output的配置。

(3)路徑生成方法:

路徑的配置需要由assetsPublicPath和assetsSubDirectory以及具體的子路徑組成,我們寫一個公共的方法來生成路徑。無論是開發環境還是生產環境,我們都可以復用該方法。我們在build文件夾下建立一個utils.js文件。內容如下:

    const path = require('path')
    const config = require('../config')

    exports.assetsPath = function (_path) {
        const assetsSubDirectory = process.env.NODE_ENV === 'production'
            ? config.build.assetsSubDirectory
            : config.dev.assetsSubDirectory

        return path.posix.join(assetsSubDirectory, _path)
    }
(4)修改webpack.prod.conf.js

在webpack.prod.conf.js頁面頭部引入

    const config=require('../config');
    const utils=require('./utils');

修改output屬性的內容

     output: {
            path: config.build.assetsRoot,
            filename: utils.assetsPath('js/[name].[chunkhash:16].js'),
            chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
        },

修改plugins內的相關配置:

    new CleanWebpackPlugin([config.build.assetsRoot], { allowExternal: true }),

    //導出css 
    new MiniCssExtractPlugin({
        filename: utils.assetsPath('css/[name].[hash].css'),
        chunkFilename: utils.assetsPath('css/[id].[hash].css'),
    }),
(5)執行編譯命令查看
npm run build

查看編譯后的文件是否放在static目錄下了。你可以修改參數配置文件,然后試試看吧。

 

2 更多的配置化
 
接下去我們會把更多的參數和變量進行配置化。
(1)index.html HTML模板的位置

在config.js文件的dev和build參數下都配置index屬性:

index: path.resolve(__dirname, '../public/index.html'),

修改HtmlWebpackPlugin內template的值:
webpack.prod.conf.js的相關修改:

     new HtmlWebpackPlugin({
                template: config.build.index,
                inject: 'body',
                minify: {
                    removeComments: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true
                },
            }),

webpack.dev.conf.js的相關修改:

    new HtmlWebpackPlugin({
            template: config.dev.index,
            inject: true
    }),
(2)增加devServer 的配置

dev環境下,啟動的端口號,代理相關,以及是否自動打開瀏覽器等等推薦可以放在參數配置文件內。
在config.js文件內增加相關配置參數:

    proxyTable: {},
    host: 'localhost',
    port: 8080, 
    autoOpenBrowser: true,

修改webpack.dev.conf.js內的相關配置:

     devServer: {
            host: config.dev.host,
            port: config.dev.port,
            contentBase: path.join(__dirname, '../public'),
            compress: true,
            historyApiFallback: true,
            hot: true,
            https: false,
            noInfo: true,
            open: config.dev.autoOpenBrowser,
            proxy: config.dev.proxyTable,
    }

 

更多的css loader加載器
 
我們在loader中配置了less加載器,如果我們要支持其他呢,比如sass,scss等等,顯然,我們需要在rules數組增加配置。其實,這里可以寫成公共的生成方法。並且我們把部分參數變成可配置。比如:是否開啟cssModule等。
(1)前期准備,增加部分參數配置

修改config.js內的配置:

    const path = require('path')

    module.exports = {
        base: {
            // 是否開啟cssModule
            cssModule: true,
            // cssModule排除的目錄, 其他css庫可以放這里
            cssModuleExcludePath: /public/
        },
        dev: {
            assetsSubDirectory: 'static',
            assetsPublicPath: '/',

            index: path.resolve(__dirname, '../public/index.html'),

            proxyTable: {},

            host: 'localhost',
            port: 8080,
            autoOpenBrowser: true,
            // 是否生成sourceMap
            cssSourceMap: true,

        },
        build: {
            assetsRoot: path.resolve(__dirname, '../dist'),
            assetsSubDirectory: 'static',
            assetsPublicPath: '/',

            index: path.resolve(__dirname, '../public/index.html'),

            // 是否生成sourceMap
            productionSourceMap: true,
        }
    }
(2) 在utils.js內增加cssLoaders和styleLoaders方法:
    exports.cssLoaders = function (options) {
        options = options || {}

        let cssLoader = {
            loader: 'css-loader',
            options: {
                importLoaders: 1,
                sourceMap: options.sourceMap
            }
        }
        if (options.cssModule) {
            cssLoader.options.modules = true;
            cssLoader.options.localIdentName = '[local]__[hash:7]';
        }
        const postcssLoader = {
            loader: 'postcss-loader',
            options: {
                sourceMap: options.sourceMap
            }
        }
        function generateLoaders(loader, loaderOptions) {
            const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

            if (loader) {
                loaders.push({
                    loader: loader + '-loader',
                    options: Object.assign({}, loaderOptions, {
                        sourceMap: options.sourceMap
                    })
                })
            }

            if (options.extract) {
                return [MiniCssExtractPlugin.loader].concat(loaders)
            } else {
                return ['style-loader'].concat(loaders)
            }
        }

        return {
            css: generateLoaders(),
            postcss: generateLoaders(),
            less: generateLoaders('less', { javascriptEnabled: true, indentedSyntax: true }),
            sass: generateLoaders('sass', { indentedSyntax: true }),
            scss: generateLoaders('sass'),
            stylus: generateLoaders('stylus'),
            styl: generateLoaders('stylus')
        }
    }

    exports.styleLoaders = function (options) {
        let output = []
        const loaders = exports.cssLoaders(options)
        for (const extension in loaders) {
            const loader = loaders[extension]
            let loaderObj = {
                test: new RegExp('\\.' + extension + '$'),
                use: loader,
            }
            if (options.cssModule) {
                loaderObj.exclude = options.cssModuleExcludePath;
            }
            output.push(loaderObj)
        }

        if (options.cssModule) {
            options.cssModule = false
            const cssModuleLoaders = exports.cssLoaders(options)
            for (const extension in cssModuleLoaders) {
                const cssModuleLoader = cssModuleLoaders[extension]
                let cssModuleLoaderObj = {
                    test: new RegExp('\\.' + extension + '$'),
                    use: cssModuleLoader,
                }
                cssModuleLoaderObj.include = options.cssModuleExcludePath;
                output.push(cssModuleLoaderObj)
            }
        }
        return output
    }
(3) 在webpack.prod.conf.js內使用

確認是否引入了utils,如果沒有引入,在頁面上方增加代碼:

const utils=require('./utils');

修改 module內的rules屬性:

    rules: utils.styleLoaders({
            sourceMap: config.build.productionSourceMap,
            extract: true,
            usePostCSS: true,
            cssModule:config.base.cssModule,
            cssModuleExcludePath:config.base.cssModuleExcludePath
    })

執行編譯查看:

npm run build
(4) 在webpack.dev.conf.js內使用

確認是否引入了utils,如果沒有引入,在頁面上方增加代碼:

const utils=require('./utils');

修改 module內的rules屬性:

     rules: utils.styleLoaders({ 
            sourceMap: config.dev.cssSourceMap, 
            usePostCSS: true,
            cssModule:config.base.cssModule,
            cssModuleExcludePath:config.base.cssModuleExcludePath
    })

執行dev命令試試看

npm run dev

下一節會對 如果對編譯后的文件進行gzip壓縮,如何讓開發環境的控制台輸出更加高逼格,如何更好的對編譯后的文件進行bundle分析等問題展開討論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM