webpack學習筆記: step2 進階用法

幾種基本用法

清理構建的目錄

能夠經過在執行構建的命令前加一句清除目錄的命令
如在package.json裏面的build命令修改成javascript

"scripts": {
    build: rm -rf ./dist && webpack
}

比較經常使用的是經過webpack的插件實現css

const { CleanWebpackPlugin }  = require('clean-webpack-plugin')
modules.export = {
    plugins: [
         new CleanWebpackPlugin()
    ]
}

處理樣式

咱們須要添加css前綴來處理兼容性問題。經過配置postcss-loader來實現。注意是先添加前綴而後再把scss轉換成css,因此要寫在最下面。html

{
                test: /.scss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'sass-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: () => [
                                require('autoprefixer')({
                                    overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
                                })
                            ]
                        }
                    }
                ]
            },
modules.export = {
    plugins: [
        new OptimizeCssAssetsWebpackPlugin({
            assetNameRegExp: /\.css$/g,
            cssProcessor: require('cssnano')
        })
    ]
}

對於字體大小的兼容,咱們可使用rem做爲字體的單位。可是把px轉換成rem是一個比較麻煩的計算過程,並且須要對不一樣分辨率下的設備,設置不一樣的根元素字體大小,從而調整總體的字體大小。一個解決方案就是,在html頁面引入flexible.js,再樣式文件的loader裏面添加px2rem-loader。
引入flexible.js,能夠經過直接用script標籤引入cdn的連接,也能夠經過文件內聯的形式,也就是把flexible.js裏面的內容,直接嵌入到<script></script>中。這裏只介紹內聯方式。
因爲咱們使用的是html-webpack-plugin把html模板編譯到dist下面,因此是支持ejs語法。須要babel-loader把文件的內容轉換成兼容性好的代碼,而後用raw-loader把文件內容輸出成字符串。注意這裏的raw-loader安裝的是0.5版本。html5

<script>
    ${require('raw-loader!babel-loader!../../../node_modules/lib-flexible/flexible.js')}
</script>

這樣咱們打包出來的文件就是java

<script>
   flexible.js的內容
</script>

添加px2rem-loadernode

{
        test: /.scss$/,
        use: [
            MiniCssExtractPlugin.loader,
            'css-loader',
            {
                loader: 'px2rem-loader',
                options: {
                    remUnit: 75, // 1px=75rem
                    remPrecision: 8 // 計算rem保留的精度
                }
            },
            'sass-loader',
            {
                loader: 'postcss-loader',
                options: {
                    plugins: () => [
                        require('autoprefixer')({
                            overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
                        })
                    ]
                }
            }
        ]
}

提取公共資源

多頁應用通用打包方案

這裏主要是經過動態獲取要打包的page路徑,生成entry和對應的html-webpack-pluginreact

const setMAP = () => {
    const entry = {};
    const htmlWebpackPlugins = [];
    const entryFiles = glob.sync(path.join(__dirname, './src/pages/*/index.js'));

    Object.keys(entryFiles).forEach((index) => {
        const entryFile = entryFiles[index]
        const match = entryFile.match(/src\/pages\/(.*)\/index\.js/);
        const pageName = match && match[1];
        entry[pageName] = `./src/pages/${pageName}/index.js`
        console.log(pageName)
        htmlWebpackPlugins.push(new HtmlWebpackPlugin({
            template: path.join(__dirname, `./src/pages/${pageName}/${pageName}.html`),
            filename: `${pageName}.html`,
            chunks: [pageName],
            inject: true,
            minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: false
            }
        }))
    })

    return {
        entry,
        htmlWebpackPlugins
    }
}

const { entry, htmlWebpackPlugins } = setMAP()

modules.export = {
    entry,
    plugins: [
    ].concat(htmlWebpackPlugins)
}

基礎庫分離

一種方案是經過html-webpack-externals-plugin,而後在html裏面直接引入組件庫的cdn連接webpack

const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
moudles.export = {
    plugins: [
        new HtmlWebpackExternalsPlugin({
            externals: [
                {
                    module: 'react',
                    entry: '//11.url.cn/now/lib/16.2.0/react.min.js',
                    global: 'React'
                },
                {
                    module: 'react-dom',
                    entry: '//11.url.cn/now/lib/16.2.0/react-dom.min.js',
                    global: 'ReactDom'
                }
            ]
        })
    ]
}

htmlios

<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react.min.js"></script>
<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react-dom.min.js"></script>

另一種方法是經過webpack4的
SplitChunksPlugins實現,順便提一下,webpack3使用的是commonChunksPluginweb

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            template: path.join(__dirname, `./src/pages/search/search.html`),
            filename: `search.html`,
            chunks: ['vendors', 'common', 'search'], //注意這裏要引入vendors跟common
            inject: true,
            minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: false
            }
        })
    ]
    optimization: {
        splitChunks: {
            minSize: 0,
            cacheGroups: {
                vendors: {
                    test: /(react|react-dom)/,
                    name: 'vendors',
                    chunks: 'all',
                    priority: -10   // 須要設置權重才能都分離出來
                },
                common: {
                    name: 'commons',
                    chunks: 'all',
                    minChunks: 2,
                    priority: -20   
                }
            }
        }
    },
}

代碼動態分割和import

ES6還不支持這個功能,須要藉助babel插件實現。

npm install @babel/plugin-syntax-dynamic-import --save-dev

在babel的配置文件.babelrc裏面添加

{
      "plugins": [
          "@babel/plugin-syntax-dynamic-import"
      ]
  }

使用的時候直接經過import函數引入某個組件

loadComponent () {
        import("./text.js").then((Text) => {
            console.log(Text)
            this.setState({
                Text: Text.default // 注意這裏設置的是Text.default
            })
        })  
    }

這樣就能夠發現,text.js被打包成一個獨立的js,當觸發loadComponent在瀏覽器的network裏面纔看到這個文件。

優化顯示日誌

咱們在build的時候,可能只須要看到報錯的日誌,能夠經過設置stats來控制要顯示的日誌。同時配合插件friendly-errors-webpack-plugin優化日誌的輸出。
stats參數:

modules.export {
    plugins: [
        new FriendlyErrorsWebpackPlugin()
    ],
    stats: 'errors-only'
}

打包組件跟庫

react ssr簡單demo

幾個重要的概念

socucemap
tree shaking

概念:就是在構建的過程當中,刪除掉咱們不須要用的代碼。<br/>
優化原則:無用代碼的判斷,是根據DCE原則,某些代碼不會被執行,或者是執行後的結果不會被用到,或者是執行的結果被用到的變量並無被使用,這些代碼都是無效代碼,在tree-shaking中要被優化掉的。<br/>
執行階段:這裏是經過靜態分析,在編譯階段實現的<br/>
特色:使用ES6的import方法引入文件是能夠進行tree-shaking,require是動態引入的文件,沒法進行tree shaking, 由於不會在運行的時候還去分析優化代碼。<br/>
如何開啓:webpack4的production模式是默認會開啓tree-shaking的

scope hoisting

webpack在編譯的時候,會把import進來的模塊用閉包函數包裹,而後經過__webpack_require__的形式使用。這樣會致使兩個問題。<br/>
一、打包的代碼體積比較大。<br/>
二、運行時的內存開銷比較大。<br/>

scope hoisting經過把import進來的模塊,直接內聯到同一個閉包函數中,經過替換變量名的方式,避免代碼衝突,來減小代碼裏面的閉包函數。可是須要注意的是僅僅對只被引入過一次的函數使用這個方案,對屢次被引入的,咱們仍是但願它是一個獨立的閉包模塊,便於屢次使用。特色:僅在ES6的import下生效,動態引入的require模式下不起做用。<br/>如何開啓:webpack4的production模式是默認會開啓tree-shaking的

相關文章
相關標籤/搜索