須要兩步來實現:javascript
下載插件並配置:css
npm i px2rem-loader lib-flexible module: { rules: [ { test: /\.less$/, use: [ MiniCssExtractPlugin.loader, "css-loader", { loader: "postcss-loader", ... }, { loader: "px2rem-loader", options: { remUnit: 75, remPrecision: 8 } }, "less-loader", ] }, ] },
而後,須要將淘寶的插件的內聯在html文件中:html
<script src='../node_modules/lib-flexible/flexible.js'></script>
靜態資源內聯是指將CSS、JS等靜態文件中的內容抽離出來,內聯到html中。咱們以前藉助插件作到了將內聯的資源獨立成文件,爲何還要將資源內聯呢?html5
資源內聯的意義:java
HTML和JS內聯node
使用raw-loader,注意要使用0.5的版本,新版本的存在一些問題。react
npm i raw-loader@0.5.1 /src/meta.html 【例:騰訊NOW直播官網的meta標籤】 <meta charset="UTF-8"> <meta name="viewport" content="viewport-fit=cover,width=device-width,initial-scale=1,user-scalable=no"> <meta name="format-detection" content="telephone=no"> <meta name="keywords" content="now,now直播,直播,騰訊直播,QQ直播,美女直播,附近直播,才藝直播,小視頻,我的直播,美女視頻,在線直播,手機直播"> <meta name="name" itemprop="name" content="NOW直播—騰訊旗下全民視頻社交直播平臺"> <meta name="description" itemprop="description" content="NOW直播,騰訊旗下全民高清視頻直播平臺,聚集中外大咖,最in網紅,草根偶像,明星藝人,校花,小鮮肉,逗逼段子手,各種美食、音樂、旅遊、時尚、健身達人與你24小時不間斷互動直播,各類奇葩刺激的直播玩法,讓你躍躍欲試,你會發現,原來人人均可以當主播賺錢!"> <meta name="image" itemprop="image" content="https://pub.idqqimg.com/pc/misc/files/20170831/60b60446e34b40b98fa26afcc62a5f74.jpg"> <meta name="baidu-site-verification" content="G4ovcyX25V"> <meta name="apple-mobile-web-app-capable" content="no"> <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> /node_modules/lib-flexible/flexible.js 【npm下載的淘寶庫】 /src/index.html <!DOCTYPE html> <html lang="en"> <head> ${ require('raw-loader!./meta/meta.html') } <title>Hello Webpack</title> <script>${ require('raw-loader!babel-loader!../node_modules/lib-flexible/flexible.js') }</script> <!-- 先用raw-loader內聯,再用babel-laoder轉換語法 --> </head> <body> <div id="root"></div> </body> </html>
CSS內聯webpack
藉助style-loader便可web
{ loader: 'style-loader', options: { insertAt: 'top', // 樣式插入到<head> singleton: true, // 將全部style標籤合併成一個 } }
每當增長一個頁面,咱們就手動地在webapck配置中對應增長一個entry、html-webpack-plugin。chrome
必定能夠有更優的方案,那就是:動態獲取entry的數量、而後自動生成html-webpack-plugin。
須要藉助glob.sync,能夠在每次構建的時候獲取頁面的數量。這須要咱們規範目錄,將每一個頁面(文件夾)都放在src文件夾下,每一個頁面(文件夾)入口文件是index.js,入口頁面是index.html。
npm i glob const glob = require('glob'); const setMPA = () => { let entry = {}; let htmlWebpackPlugins = []; const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js')); // 獲取全部頁面的入口文件路徑。entryFiles是全部頁面index.js的絕對路徑造成的數組 entryFiles.forEach((file)=>{ let name = file.match(/src\/(.*)\/index\.js/); let pageName = name && name[1]; entry[pageName] = file; htmlWebpackPlugins.push(new HtmlWebpackPlugin({ template: file.replace("index.js","index.html"), filename: `${pageName}.html`, chunks: [`${pageName}`], inject: true, minify: { html5: true, collapseWhitespace: true, preserveLineBreaks: false, minifyCSS: true, minifyJS: true, removeComments: true, }, })) }); return { entry, htmlWebpackPlugins } }; const result = setMPA(); module.exports = { entry: result.entry, output: { filename: "bundle[chunkhash:8].js", path: path.join(__dirname, "/dist") }, mode: 'production', module: { rules: [ ... ] }, plugins: [ ...result.htmlWebpackPlugins, // 將N個HtmlWebpackPlugin對象插入列表 new MiniCssExtractPlugin({ filename: '[name][contenthash:8].css' }), new OptimizeCssAssetsPlugin({ assetNameRegExp: /\.css$/g, cssProcessor: require('cssnano'), }), new CleanWebpackPlugin(), };
什麼是source map?顧名思義,就是代碼地圖,能夠將構建先後的兩份代碼作一個映射。
sourcemap的做用:構建後的代碼已經變了模樣,沒有可讀性,開發調試的時候沒法定位問題所在。sourcemap的存在能夠直接將問題定位到源代碼,排查問題。
配置文件中devtool屬性能夠設置,有很是多的類型可選,通常狀況下,開發環境使用"source-map",生產環境關閉。
module.exports = { devtool: "source-map" };
對於大型的web應用來講,將全部的代碼編譯成一個文件顯示很差,會形成文件體積過大以及須要加載大量與首屏無關的代碼,用戶體驗很差。webpack提供將代碼分割成chunk(語塊),當代碼運行到須要的它們的時候再進行加載。
代碼分割有兩種類型:
須要藉助插件,有兩個插件可供選擇:html-webpack-externals-plugin 和 SplitChunsPlugin(webpack4內置,代替webpack3的CommonsChunkPlugin)
說明:
html-webpack-externals-plugin:
npm i html-webpack-externals-plugin const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin'); plugins: [ new HtmlWebpackExternalsPlugin({ externals: [ { module: "react", // 代碼中引入的庫的名稱 entry: "https://11.url.cn/now/lib/16.2.0/react.min.js", // entry: "cjs/react", // 相對於node_modules/react的路徑【官網示例,實際並不成功】 global: "React", // 代碼中引入的庫的全局對象的名稱 }, { module: "react-dom", entry: "https://11.url.cn/now/lib/16.2.0/react-dom.min.js", // entry: "dist/react-dom", // 相對於node_modules/react-dom的路徑 【官網示例,實際並不成功】 global: "ReactDOM", }, ], }) ]
SplitChunksPlugin:
module.exports = { optimization: { splitChunks: { minSize: 0, // 分離包體積的最小大小 cacheGroups: { commons: { // test: /(react|react-dom)/, // 經過正則匹配,只分離react/react-dom這兩個庫,不寫test則不做限制 name: 'commonss', // 分離塊的名稱,須要加在HtmlWebpackPlugin插件的chunks屬性中,才能正確命名分離後的文件 chunks: "all", // 須要分割哪些代碼塊,all表示全部代碼塊,async按需加載的代碼塊,initial初始化代碼塊 // minChunks: 2, // 最小引用次數,少於這個引用次數就不會單獨提取出來 } } } } };
實現懶加載不須要對webpack配置,動態引入import('')語法尚未成爲JS標準(也許不久的未來會),目前要藉助js插件
實現懶加載:
npm i @babel/plugin-syntax-dynamic-import .babelrc { "presets": [ "@babel/preset-react", "@babel/preset-env" ], "plugins": [ "@babel/plugin-syntax-dynamic-import", // 懶加載插件 "@babel/plugin-proposal-class-properties" ] }
在此基礎上,若是使用React開發項目,還可使用react-loadable插件來更好的實現異步加載
npm i react-loadable index.js中部分代碼 import Loadable from "react-loadable"; const TextLoad = Loadable({ loader: () => import(/* webpackChunkName: 'text' */ './text'), // 經過註釋的方式指定打包後的chunk的名字 loading: ()=> <div>正在加載</div> }); class Search extends React.Component{ constructor(props){ super(props); this.state = { text: false, }; } loadComponent = () => { this.setState({ text: true }) }; render() { const { text } = this.state; return ( <> <div>你好,顯示字體 Hello Webpacks</div> { text ? <TextLoad /> : null } <img alt="" src={logo} style={{ width: 100 }} onClick={this.loadComponent}/> </> ) } } export default Search;
一個文件會有多個方法、對象、語句,只要用到其中一小部分,便會將整個文件內的全部內容打包進去。tree shaking只把用到的方法打包進去,沒用到的會在uglfiy階段被擦出掉。
使用:webpack默認支持,生產環境默認開啓
要求:必須是ES6的寫法,CommonJS的方式不支持
構建以後的代碼存在大量閉包,致使:
scope hoisting就是減小閉包函數的聲明。
原理:將全部模塊的代碼按照引用順序放在一個函數做用域裏,而後適當地重命名一些變量以防止變量名衝突,以此減小閉包函數聲明代碼。
使用:webpack默認支持,生產環境默認開啓
要求:必須是ES6寫法,CommonJS的方式不支持
每次構建,命令行輸出大量日誌,有不少是咱們徹底不關心的,想要優化它,能夠在webpack中設置state屬性。
// 若是是打包,在最外層的state屬性 module.exports = { stats: 'errors-only', }; // 若是是devserver熱更新 const devConfig = { devServer: { contentBase: './dist', hot: true, stats: 'errors-only', }, };
state的取值有:
咱們但願是在發生錯誤的時候輸出,當state爲error-only時,若是沒有錯誤,沒有任何輸出,不太友好。
藉助插件:friendly-errors-webpack-plugin。此時將state設置成errors-only
npm i friendly-errors-webpack-plugin const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); module.exports = { plugins: [ new FriendlyErrorsWebpackPlugin(), ], };
個人博客即將同步至騰訊雲+社區,邀請你們一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=1jot771valo8l