能夠經過在執行構建的命令前加一句清除目錄的命令
如在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 } } } }, }
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' }
概念:就是在構建的過程當中,刪除掉咱們不須要用的代碼。<br/>
優化原則:無用代碼的判斷,是根據DCE原則,某些代碼不會被執行,或者是執行後的結果不會被用到,或者是執行的結果被用到的變量並無被使用,這些代碼都是無效代碼,在tree-shaking中要被優化掉的。<br/>
執行階段:這裏是經過靜態分析,在編譯階段實現的<br/>
特色:使用ES6的import方法引入文件是能夠進行tree-shaking,require是動態引入的文件,沒法進行tree shaking, 由於不會在運行的時候還去分析優化代碼。<br/>
如何開啓:webpack4的production模式是默認會開啓tree-shaking的
webpack在編譯的時候,會把import進來的模塊用閉包函數包裹,而後經過__webpack_require__的形式使用。這樣會致使兩個問題。<br/>
一、打包的代碼體積比較大。<br/>
二、運行時的內存開銷比較大。<br/>
scope hoisting經過把import進來的模塊,直接內聯到同一個閉包函數中,經過替換變量名的方式,避免代碼衝突,來減小代碼裏面的閉包函數。可是須要注意的是僅僅對只被引入過一次的函數使用這個方案,對屢次被引入的,咱們仍是但願它是一個獨立的閉包模塊,便於屢次使用。特色:僅在ES6的import下生效,動態引入的require模式下不起做用。<br/>如何開啓:webpack4的production模式是默認會開啓tree-shaking的