讀這篇文章理清下面概念 webpack 中那些最易混淆的 5 個知識點javascript
1.module,chunk 和 bundle 的區別是什麼?
2.filename 和 chunkFilename 的區別
webpack 2xcss
loadershtml
plugins前端
webpack-parallel-uglify-plugin
來替換 優化打包速度webpack-dev-middlerware
和 webpack-hot-middleware
插件使用webpack 4xvue
自動生成html文件java
let HtmlWebpackPlugin = require('html-webpack-plugin'); new HtmlWebpackPlugin({ template: './src/index.html', // 模板文件,不侷限html後綴 filename: 'index.html', // 生成的html命名 hash: true, // 會在打包好的bundle.js後加hash串 chunks: [name] // 指定輸出頁面須要引入的chunks // removeComments 移除HTML中的註釋 // collapseWhitespace 刪除空白符與換行符,整個文件會壓成一行 // inlineSource 插入到html的css,js文件都要內聯,既不是以link,script引入 // inject 是否能注入內容到輸入的頁面去 })
npm init npm install webpack --save-dev //webpack@4.16.1 npm install webpack-dev-server --save-dev //webpack-dev-server@3.1.4
建立webpack.config.js
node
var config = { } module.exports = config
注:這裏的module.exports = config
至關於export default config
,因爲目前尚未安裝支持ES6的編譯插件,所以不能直接使用ES6的語法 不然會報錯jquery
package.json
的scripts裏添加一個快速啓動webpack-dev-server服務腳本:webpack
npm run dev 後默認打開的地址是: 127.0.0.1:8080
能夠本身配置:ios
"dev": "webpack-dev-server --host 197.163.1.2 --port 8888 --open --config webpack.config.js"
// webpack.config.js var path = require('path') module.exports = { entry: { //告訴webpack從哪裏找依賴並編譯 main: './main' }, output: { // 配置編譯的文件儲存位置和文件名 path: path.join(__dirname, './dist'), publicPath: '/dist/', filename: 'main.js' } };
// index.html <!DOCTYPE html> <html> <head> <title>webpack test</title> </head> <body> <div id="app">您好, 鏡心的小樹屋歡迎您</div> <script type="text/javascript" src="/dist/main.js"></script> </body> </html>
npm run dev 啓動
若是報錯:
npm install webpack-cli -D // "webpack-cli": "^3.0.8", npm run dev
main.js
document.getElementById('app').innerHTML = "你好美"
進行打包
webpack --progress -- hide-modules// 會生成一個/dist/main.js
https://github.com/icarusion/...
// css加載器 npm install css-loader --save-dev // style-loader@0.21.0 npm install style-loader --save-dev // css-loader@1.0.0
安裝後,在webpack.config.js文件配置Loader,添加.css文件處理
module對象rules屬性中能夠指定一系列loaders。
use選型的值能夠是數組或字符串,若是是數組,它的編譯順序就是從後往前。extract-text-webpack-plugin
插件是用來把散落在各地的css提取出來,並生成一個main.css文件,最終在index.html經過<link>加載
npm install extract-text-webpack-plugin --save-dev
var path = require('path'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var config = { entry: { main: './main' }, output: { path: path.join(__dirname, './dist'), publicPath: '/dist/', filename: 'main.js' }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { loaders: { css: ExtractTextPlugin.extract({ use: 'css-loader', fallback: 'vue-style-loader' }) } } }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.css$/, use: ExtractTextPlugin.extract({ use: 'css-loader', fallback: 'style-loader' }) }, { test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/, loader: 'url-loader?limit=1024' } ] }, plugins: [ // 重命名提取後的css文件 new ExtractTextPlugin({ filename: '[name].css', allChunks: true }) ] }; module.exports = config;
快速構建最好的天然是使用腳手架, 你能夠選擇:
Webpack boilerplate CLI: https://www.npmjs.com/package...
easywebpack-cli: https://yuque.com/hubcarl/ves...
vue-cli: https://github.com/vuejs/vue-cli
咱們這裏將以vue-cli3爲例構建一個vue項目,(vue-cli3提供了極其完整的配置來幫助開發者快捷開始一個項目)
同時嘗試修改這些配置以知足特殊的需求。
升級nodejs
從新安裝
9.0.0 也不能用,換成最新版
先看這個:https://vue-loader.vuejs.org/... 瞭解文檔內容
npm install --save vue // vue@2.5.16 npm install --save-dev vue-loader vue-style-loader vue-template-compiler vue-hot-reload-api babel babel-loader babel-core babel-plugin-transform-runtime babel-preset-es2015 babel-runtime VUE-CLI 3 :https://cli.vuejs.org/guide/installation.html
修改webpack.config.js 支持.vue
和 es6
var path = require('path') var ExtractTextPlugin = require('extract-text-webpack-plugin') module.exports = { entry: { //告訴webpack從哪裏找依賴並編譯 main: './main' }, output: { // 配置編譯的文件儲存位置和文件名 path: path.join(__dirname, './dist'),// 打包後的輸出目錄 publicPath: '/dist/',// 指定資源文件引用目錄(若是資源在cdn上 能夠是cdn網址) filename: 'main.js'// }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { loaders: { css: ExtractTextPlugin.extract({ use: 'css-loader', fallback: 'vue-style-loader' }) } } }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.css$/, use: ExtractTextPlugin.extract({ use: 'css-loader', fallback: 'vue-style-loader' }) } ] }, plugins: [ new ExtractTextPlugin("main.css") ] };
根目錄新建.babelrc
{ "presets": ["es2015"], "plugin": ["transform-runtime"], "comments": false }
注意:
此種設置須要把webpack降級到2x:
webpack: 2.3.2
webpack-dev-server: 2.4.2
咱們看看實際項目中依賴(webpack2的)
{ "name": "test", "version": "1.0.0", "description": "A Vue.js project", "author": "AlexZ33", "private": true, "scripts": { "dev": "node build/dev-server.js", "build": "node build/build.js", "lint": "eslint --ext .js,.vue src", "test": "mocha test/*.js" }, "dependencies": { "axios": "^0.16.1", "d3": "^4.8.0", "d3-cloud": "^1.2.4", "echarts": "^3.5.2", "echarts-wordcloud": "^1.1.0", "iview": "^2.5.1", "jquery": "^3.3.1", "jsonp": "^0.2.1", "lodash.merge": "^4.6.1", "promise-polyfill": "^6.0.2", "shave": "^2.1.3", "url-search-params": "^0.9.0", "vue": "^2.3.4", "vue-router": "^2.2.0", "vue-select": "^2.4.0", "vuex": "^2.4.0", "wordcloud": "^1.0.6" }, "devDependencies": { "autoprefixer": "^6.7.2", "babel-core": "^6.22.1", "babel-eslint": "^7.1.1", "babel-loader": "^6.2.10", "babel-plugin-transform-runtime": "^6.22.0", "babel-preset-env": "^1.2.1", "babel-preset-stage-2": "^6.22.0", "babel-register": "^6.22.0", "chai": "^4.0.2", "chalk": "^1.1.3", "connect-history-api-fallback": "^1.3.0", "copy-webpack-plugin": "^4.0.1", "css-loader": "^0.26.1", "eslint": "^3.14.1", "eslint-config-standard": "^6.2.1", "eslint-friendly-formatter": "^2.0.7", "eslint-loader": "^1.6.1", "eslint-plugin-html": "^2.0.0", "eslint-plugin-promise": "^3.4.0", "eslint-plugin-standard": "^2.0.1", "eventsource-polyfill": "^0.9.6", "express": "^4.14.1", "extract-text-webpack-plugin": "^2.0.0", "file-loader": "^0.10.0", "friendly-errors-webpack-plugin": "^1.1.3", "fullpage.js": "^2.9.4", "function-bind": "^1.1.0", "html-webpack-plugin": "^2.28.0", "http-proxy-middleware": "^0.17.3", "less": "^2.7.2", "less-loader": "^4.0.3", "mocha": "^3.4.2", "node-sass": "^4.9.0", "opn": "^4.0.2", "optimize-css-assets-webpack-plugin": "^1.3.0", "ora": "^1.1.0", "rimraf": "^2.6.0", "sass-loader": "^6.0.3", "semver": "^5.3.0", "shelljs": "^0.7.7", "url-loader": "^0.5.7", "vue-loader": "^12.2.1", "vue-style-loader": "^2.0.0", "vue-template-compiler": "^2.3.4", "webpack": "^2.2.1", "webpack-bundle-analyzer": "^2.2.1", "webpack-dev-middleware": "^1.10.0", "webpack-hot-middleware": "^2.16.1", "webpack-merge": "^2.6.1" }, "engines": { "node": ">= 4.0.0", "npm": ">= 3.0.0" }, "browserslist": [ "> 1%", "last 2 versions", "not ie <= 8" ] }
在項目開發的時候,接口聯調的時候通常都是同域名下,且不存在跨域的狀況下進行接口聯調,可是當咱們如今使用vue-cli進行項目打包的時候,咱們在本地啓動服務器後,好比本地開發服務下是 http://localhost:8080 這樣的訪問頁面,可是咱們的接口地址是 http://xxxx.com/save/index 這樣的接口地址,咱們這樣直接使用會存在跨域的請求,致使接口請求不成功,所以咱們須要在打包的時候配置一下,咱們進入 config/index.js 代碼下以下配置便可:
dev: { // 靜態資源文件夾 assetsSubDirectory: 'static', // 發佈路徑 assetsPublicPath: '/', // 代理配置表,在這裏能夠配置特定的請求代理到對應的API接口 // 例如將'localhost:8080/api/xxx'代理到'www.example.com/api/xxx' // 使用方法:https://vuejs-templates.github.io/webpack/proxy.html proxyTable: { '/api': { target: 'http://xxxxxx.com', // 接口的域名 // secure: false, // 若是是https接口,須要配置這個參數 changeOrigin: true, // 若是接口跨域,須要進行這個參數配置 pathRewrite: { '^/api': '' } } }, // 本地訪問 http://localhost:8080 host: 'localhost', // can be overwritten by process.env.HOST
接口地址本來是 /save/index,可是爲了匹配代理地址,在前面加一個 /api, 所以接口地址須要寫成這樣的便可生效 /api/save/index。
注意: '/api' 爲匹配項,target 爲被請求的地址,由於在 ajax 的 url 中加了前綴 '/api',而本來的接口是沒有這個前綴的,因此須要經過 pathRewrite 來重寫地址,將前綴 '/api' 轉爲 '/'。若是自己的接口地址就有 '/api' 這種通用前綴,就能夠把 pathRewrite 刪掉。
常見示例如在 :https://github.com/bailicangd... 這裏加
proxyTable: { // '/pre-web': 'http://118.24.153.55/' // 線上 '/pre-web': 'http://118.24.153.56' // 測試 // 'pre-web': 'http://118.24.153.57' // 本地服務器 },
-> 用法戳 文檔
HotModuleReplacementPlugin
插件
webpack-dev-middlerware
和 webpack-hot-middleware
插件
require('./check-versions')() var config = require('../config') if (!process.env.NODE_ENV) { process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) } var opn = require('opn') var path = require('path') var express = require('express') var webpack = require('webpack') var proxyMiddleware = require('http-proxy-middleware') var webpackConfig = require('./webpack.dev.conf') // 端口配置 var port = process.env.PORT || config.dev.port // 打開瀏覽器 var autoOpenBrowser = !!config.dev.autoOpenBrowser // 代理配置 var proxyTable = config.dev.proxyTable var app = express() var compiler = webpack(webpackConfig) // 本地服務配置 var devMiddleware = require('webpack-dev-middleware')(compiler, { publicPath: webpackConfig.output.publicPath, quiet: true }) //載入熱加載配置 var hotMiddleware = require('webpack-hot-middleware')(compiler, { log: () => {} }) // 配置view層代碼啓用熱載 compiler.plugin('compilation', function (compilation) { compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { hotMiddleware.publish({ action: 'reload' }) cb() }) }) // 載入代理配置 Object.keys(proxyTable).forEach(function (context) { var options = proxyTable[context] if (typeof options === 'string') { options = { target: options } } app.use(proxyMiddleware(options.filter || context, options)) }) // 回退配置 app.use(require('connect-history-api-fallback')()) // 載入開發服務配置 app.use(devMiddleware) // 載入熱加載配置 app.use(hotMiddleware) // 掛載靜態資源 var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) app.use(staticPath, express.static('./static')) var uri = 'http://localhost:' + port var _resolve var readyPromise = new Promise(resolve => { _resolve = resolve }) console.log('> 啓動本地開發服務...') devMiddleware.waitUntilValid(() => { console.log('> 服務地址 ' + uri + '\n') _resolve() }) // 開啓 express 服務 var server = app.listen(port) module.exports = { ready: readyPromise, close: () => { server.close() } }
koa
引入對應的 koa-webpack-dev-middlerware
和 koa-webpack-hot-middleware
const devMiddleware = require('koa-webpack-dev-middleware')(compiler, { publicPath, stats: { colors: true, children: true, modules: false, chunks: false, chunkModules: false, }, watchOptions: { ignored: /node_modules/, } }); app.use(devMiddleware); const hotMiddleware = require('koa-webpack-hot-middleware')(compiler, { log: false, reload: true }); app.use(hotMiddleware);
entry
注入熱更新代碼webpack-hot-middleware/client?path=http://127.0.0.1:9000/__webpack_hmr&noInfo=false&reload=true&quiet=false
這裏注入熱更新代碼是關鍵,保證服務端和客戶端可以通訊。
瀏覽器的網頁經過websocket協議與服務器創建起一個長鏈接,當服務器的css/js/html進行了修改的時候,服務器會向前端發送一個更新的消息,若是是css或者html發生了改變,網頁執行js直接操做dom,局部刷新,若是是js發生了改變,只好刷新整個頁面
爲什麼沒有提到圖片的更新?
若是是在html或者css裏修改了圖片路徑,那麼更新html和css,只要圖片路徑沒有錯,那麼就已經達到了更新圖片的路徑。若是是相同路徑的圖片進行了替換,這每每須要重啓下服務在簡單的網頁應用中,這一個過程可能僅僅是節省了手動刷新瀏覽器的繁瑣,可是在負責的應用中,若是你在調試的部分須要從頁面入口操做好幾步纔到達,例如:登陸
->列表
->詳情
->彈出窗口
,那麼局部刷新將大大提升調試效率
static/
目錄下的文件並不會被webpack處理,它們會被複制到最終目錄(默認是dist/static
下),必須使用絕對路徑引用這些文件,這是經過在config.js
文件中的build.assetsPublicPath
和build.assetsSubDirectory
鏈接來肯定的
任何放在 static/
中文件須要以絕對路徑的形式引用 /static/[filename]
.
若是更assetSubDirectory
的值爲assets
,那麼路徑需改成/assets/[filename]
src/assets
裏面的會被webpack打包進你的代碼裏,而static裏面的,就直接引用了,
通常static裏面放一些類庫的文件,在assets裏面放屬於該項目的資源文件。
在vue-cli2構建的項目中,build
和config
是項目的構建和配內容
var path = require('path') var utils = require('./utils') var config = require('../config') var vueLoaderConfig = require('./vue-loader.conf') var webpack = require("webpack") // webpack 基礎文件配置 function resolve (dir) { return path.join(__dirname, '..', dir) } module.exports = { entry: { app: './src/main.js' }, plugins: [ new webpack.ProvidePlugin({ jQuery: "jquery", $: "jquery" }) ], output: { path: config.build.assetsRoot, filename: '[name].js', publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, resolve: { extensions: ['.js', '.vue', '.json'], modules: [ resolve('src'), resolve('node_modules'), resolve('static') ], alias: { 'vue$': 'vue/dist/vue.min.js', '@': resolve('src'), 'echart': 'echart/dist/echarts.common.min.js' } }, module: { rules: [ { test: /\.(js|vue)$/, loader: 'eslint-loader', enforce: 'pre', include: [resolve('src'), resolve('test')], options: { formatter: require('eslint-friendly-formatter') } }, { test: /\.vue$/, loader: 'vue-loader', options: vueLoaderConfig, exclude: /node_modules/ }, { test: /\.js$/, loader: 'babel-loader', // 把對.js 的文件處理交給id爲happyBabel 的HappyPack 的實例執行 // loader: 'happypack/loader?id=happyBabel', include: [resolve('src'), resolve('test'), resolve('static')], exclude: /node_modules/ }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ] } }
var utils = require('./utils') var webpack = require('webpack') var config = require('../config') var merge = require('webpack-merge') var baseWebpackConfig = require('./webpack.base.conf') var HtmlWebpackPlugin = require('html-webpack-plugin') var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') // 配置 需熱載文件 Object.keys(baseWebpackConfig.entry).forEach(function (name) { baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) }) module.exports = merge(baseWebpackConfig, { module: { rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) }, resolve: { alias: { 'vue$': 'vue/dist/vue.js', } }, // devtool: '#source-map', // devtool: '#eval-source-map', devtool: 'cheap-module-eval-source-map', // devtool: false, plugins: [ new webpack.DefinePlugin({ 'process.env': config.dev.env }), // https://github.com/glenjamin/webpack-hot-middleware#installation--usage new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin(), // https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html', title: config.dev.title, favicon: config.dev.favicon, inject: true }), new FriendlyErrorsPlugin() ] })
var path = require('path') var utils = require('./utils') var webpack = require('webpack') var config = require('../config') var merge = require('webpack-merge') var baseWebpackConfig = require('./webpack.base.conf') var CopyWebpackPlugin = require('copy-webpack-plugin') var HtmlWebpackPlugin = require('html-webpack-plugin') var ExtractTextPlugin = require('extract-text-webpack-plugin') var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') var ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin') var env = config.build.env var webpackConfig = merge(baseWebpackConfig, { module: { rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) }, devtool: config.build.productionSourceMap ? '#source-map' : false, output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }, resolve: { alias: { 'vue$': 'vue/dist/vue.min.js' } }, plugins: [ // http://vuejs.github.io/vue-loader/en/workflow/production.html //去除重複引用 new webpack.DefinePlugin({ 'process.env': env }), // 刪掉webpack提供的UglifyJS插件 以webpack-parallel-uglify-plugin來替換 優化打包速度 // new webpack.optimize.UglifyJsPlugin({ // compress: { // warnings: false // }, // sourceMap: true // }), // 增長 webpack-parallel-uglify-plugin new ParallelUglifyPlugin({ cacheDir: '.cache/', uglifyJs: { output: { comments: false }, compress: { warnings: false } } }), // 添加DllReferencePlugin插件 new webpack.DllReferencePlugin({ context: path.resolve(__dirname, '..'), manifest: require('./vendor-manifest.json') }), // 生產單個樣式文件 new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css') }), new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }), // 加入 hash 生成html 文件 new HtmlWebpackPlugin({ filename: config.build.index, template: 'index.html', inject: true, title: config.build.title, favicon: config.build.favicon, minify: { // 刪除註釋 removeComments: true, // 合併空白 collapseWhitespace: true, // 刪除屬性的引號 removeAttributeQuotes: true // https://github.com/kangax/html-minifier#options-quick-reference }, // 容許控制塊在添加到頁面以前的排序方式 // dependency 按照依賴關係添加 chunksSortMode: 'dependency' }), // new HtmlWebpackPlugin({ // filename: 'update-browser.html', // template: 'update-browser.html' // }), // 分離類庫文件 new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: function (module, count) { return ( module.resource && /\.js$/.test(module.resource) && module.resource.indexOf( path.join(__dirname, '../node_modules') ) === 0 ) } }), // 分離 webpack run time 文件 new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', chunks: ['vendor'] }), // copy自定義文件 new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../static'), to: config.build.assetsSubDirectory, ignore: ['.*'] } ]) ] }) if (config.build.productionGzip) { var CompressionWebpackPlugin = require('compression-webpack-plugin') webpackConfig.plugins.push( new CompressionWebpackPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp( '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' ), threshold: 10240, minRatio: 0.8 }) ) } if (config.build.bundleAnalyzerReport) { var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin webpackConfig.plugins.push(new BundleAnalyzerPlugin()) } module.exports = webpackConfig
預編譯,優化打包速度的
//DllPlugin 插件:做用是預先編譯一些模塊。 //DllReferencePlugin 插件:它的所用則是把這些預先編譯好的模塊引用起來。 var path = require('path') var webpack = require('webpack') module.exports = { entry: { vendor: [ 'vue/dist/vue.common.js', 'vue-router', 'vuex',//提早打包一些基本不怎麼修改的文件 ] }, output: { path: path.join(__dirname, '../static/js'),//放在項目的static/js目錄下面 filename: '[name].dll.js', // 打包文件的名字 library: '[name]_library' // 可選 暴露出的全局變量名 // vendor.dll.js中暴露出的全局變量名。 // 主要是給DllPlugin中的name使用, // 故這裏須要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。 }, plugins: [ // 注意:DllPlugin 必需要在 DllReferencePlugin 執行前先執行一次,dll 這個概念應該也是借鑑了 windows 程序開發中的 dll 文件的設計理念。 new webpack.DllPlugin({ path: path.join(__dirname, '.', '[name]-manifest.json'),//生成上文說到清單文件,放在當前build文件下面 name: '[name]_library' }), //壓縮 只是爲了包更小一點 new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, drop_console: true, drop_debugger: true }, output: { // 去掉註釋 comments: false }, sourceMap: true }) ] }
require('./check-versions')() var config = require('../config') if (!process.env.NODE_ENV) { process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) } var opn = require('opn') var path = require('path') var express = require('express') var webpack = require('webpack') var proxyMiddleware = require('http-proxy-middleware') var webpackConfig = require('./webpack.dev.conf') // 端口配置 var port = process.env.PORT || config.dev.port // 打開瀏覽器 var autoOpenBrowser = !!config.dev.autoOpenBrowser // 代理配置 var proxyTable = config.dev.proxyTable var app = express() var compiler = webpack(webpackConfig) // 本地服務配置 var devMiddleware = require('webpack-dev-middleware')(compiler, { publicPath: webpackConfig.output.publicPath, quiet: true }) //載入熱加載配置 var hotMiddleware = require('webpack-hot-middleware')(compiler, { log: () => {} }) // 配置view層代碼啓用熱載 compiler.plugin('compilation', function (compilation) { compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { hotMiddleware.publish({ action: 'reload' }) cb() }) }) // 載入代理配置 Object.keys(proxyTable).forEach(function (context) { var options = proxyTable[context] if (typeof options === 'string') { options = { target: options } } app.use(proxyMiddleware(options.filter || context, options)) }) // 回退配置 // https://blog.csdn.net/astonishqft/article/details/82762354 app.use(require('connect-history-api-fallback')()) // 載入開發服務配置 app.use(devMiddleware) // 載入熱加載配置 app.use(hotMiddleware) // 掛載靜態資源 var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) app.use(staticPath, express.static('./static')) var uri = 'http://localhost:' + port var _resolve var readyPromise = new Promise(resolve => { _resolve = resolve }) console.log('> 啓動本地開發服務...') devMiddleware.waitUntilValid(() => { console.log('> 服務地址 ' + uri + '\n') _resolve() }) // 開啓 express 服務 var server = app.listen(port) module.exports = { ready: readyPromise, close: () => { server.close() } }
vue-style-loader 最新
在
文件下添加了process.traceDeprecation = true
運行 npm run dev
,按照webpack.dev.conf.js
配置跑下dev-server,發現
升級下
再跑,發現
更新
npm install webpack-dev-middleware@3 -D
Webpack打包是把全部js代碼打成一個js文件,咱們能夠經過 CommonsChunkPlugin 分離出公共組件,但這遠遠不夠。 實際業務開發時,一些主要頁面內容每每比較多, 並且會引入第三方組件。其中有些內容的展現再也不首屏或者監控腳本等對用戶不是那麼重要的腳本咱們能夠經過 require.ensure 代碼分離延遲加載。在 Webpack在構建時,解析到require.ensure 時,會單獨針對引入的js資源單獨構建出chunk文件,這樣就能從主js文件裏面分離出來。 而後頁面加載完後, 經過script標籤的方式動態插入到文檔中。
require.ensure 使用方式, 第三個參數是指定生產的chunk文件名,不設置時是用數字編號代理。相同require.ensure只會生產一個chunk文件。
require.ensure(['swiper'], ()=> { const Swiper = require('swiper'); ...... }, 'swiper');
Vue.component('async-swiper', (resolve) => { // 經過註釋webpackChunkName 指定生成的chunk名稱 import(/* webpackChunkName: "asyncSwiper" */ './AsyncSwiper.vue') }); <div id="app"> <p>Vue dynamic component load</p><async-swiper></async-swiper> </div>
其實這裏說的就是 vue-router裏的 路由懶加載
實際spa項目中:
《vue實戰》
vue-loader: https://vue-loader.vuejs.org/...
https://www.jianshu.com/p/f05...
https://www.cnblogs.com/tugen...
http://vuejs-templates.github...
性能優化篇---Webpack構建代碼質量壓縮
Webpack 4 和單頁應用入門
Webpack 熱更新實現原理分析
前端開發熱更新原理解讀
實現個簡單webpack
詳解CommonsChunkPlugin的配置和用法
connect-history-api-fallback庫的理解
To v4 from v3 文檔