容易混淆概念解析
讀這篇文章理清下面概念 webpack 中那些最易混淆的 5 個知識點
1.module,chunk 和 bundle 的區別是什么?版本區別
2.filename 和 chunkFilename 的區別
webpack 2x
entry
output
loaders
file-loader:把文件輸出到一個文件夾中,在代碼中通過相對 URL 去引用輸出的文件
url-loader:和 file-loader 類似,但是能在文件很小的情況下以 base64 的方式把文件內容注入到代碼中去
source-map-loader:加載額外的 Source Map 文件,以方便斷點調試
image-loader:加載并且壓縮圖片文件
babel-loader:把 ES6 轉換成 ES5
css-loader:加載 CSS,支持模塊化、壓縮、文件導入等特性
style-loader:把 CSS 代碼注入到 JavaScript 中,通過 DOM 操作去加載 CSS。
eslint-loader:通過 ESLint 檢查 JavaScript 代碼
plugins
CommonsChunkPlugin:CommonsChunkPlugin主要是用來提取第三方庫和公共模塊,避免首屏加載的bundle文件或者按需加載的bundle文件體積過大,從而導致加載時間過長,著實是優化的一把利器。
define-plugin:定義環境變量
HtmlWebpackPlugin: 加入 hash 生成html 文件
uglifyjs-webpack-plugin:通過UglifyES壓縮ES6代碼
webpack-parallel-uglify-plugin: 刪掉webpack提供的UglifyJS插件 以webpack-parallel-uglify-plugin來替換 優化打包速度
HotModuleReplacementPlugin: 熱更新, 配合dev-serve中的webpack-dev-middlerware 和 webpack-hot-middleware 插件使用
NoEmitOnErrorsPlugin: 在編譯出現錯誤時,使用 NoEmitOnErrorsPlugin 來跳過輸出階段。這樣可以確保輸出資源不會包含錯誤。對于所有資源,統計資料(stat)的 emitted 標識都是 false。
ExtractTextPlugin:該插件的主要是為了抽離css樣式,防止將樣式打包在js中引起頁面樣式加載錯亂的現象。
imagemin-webpack-plugin: This is a simple plugin that uses Imagemin to compress all images in your project.
webpack 4x
html-webpack-plugin
自動生成html文件
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
var config = { } module.exports = config
注:這里的module.exports = config相當于export default config ,由于目前還沒有安裝支持ES6的編譯插件,因此不能直接使用ES6的語法 否則會報錯
package.json的scripts里添加一個快速啟動webpack-dev-server服務腳本:
npm run dev 后默認打開的地址是: 127.0.0.1:8080
可以自己配置:
"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.htmlwebpack test 您好, 鏡心的小樹屋歡迎您
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通過加載
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"http:// }, 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" ] }webpack+vue-cil 中proxyTable配置接口地址代理
在項目開發的時候,接口聯調的時候一般都是同域名下,且不存在跨域的情況下進行接口聯調,但是當我們現在使用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" // 本地服務器 },單頁面的多頁面切換 按需加載 常用插件 DefinePlugin
-> 用法戳 文檔
Webpack 配置添加 HotModuleReplacementPlugin 插件
Node Server 引入 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 + " ") _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發生了改變,只好刷新整個頁面
js發生改變的時候,不太可能判斷出對dom的局部影響,只能全局刷新
為何沒有提到圖片的更新?如果是在html或者css里修改了圖片路徑,那么更新html和css,只要圖片路徑沒有錯,那么就已經達到了更新圖片的路徑。如果是相同路徑的圖片進行了替換,這往往需要重啟下服務
在簡單的網頁應用中,這一個過程可能僅僅是節省了手動刷新瀏覽器的繁瑣,但是在負責的應用中,如果你在調試的部分需要從頁面入口操作好幾步才到達,例如:登錄->列表->詳情->彈出窗口,那么局部刷新將大大提高調試效率
常見面試問題gulp/grunt 與 webpack的區別是什么?
webpack plugin loader區別
webpack是解決什么問題而生的?
如何配置多入口文件?
你是如何提高webpack構件速度的?
利用webpack如何優化前端性能?
遷移 關于vue-cli2項目 "Real" Static Assetsstatic/目錄下的文件并不會被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是項目的構建和配內容
webpack.base.conf.jsvar 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]") } } ] } }webpack.dev.conf.js
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() ] })webpack.prod.conf.js
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 = webpackConfigwebpack.dll.conf.js
預編譯,優化打包速度的
//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 }) ] }dev-server.js
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 + " ") _resolve() }) // 開啟 express 服務 var server = app.listen(port) module.exports = { ready: readyPromise, close: () => { server.close() } }vue項目 migrate to webpack v4 from v2
webpack 升級 (npm i webpack@4 -D)
webpack-cli
webpack-dev-server@3
html-webpack-plugin (npm i html-webpack-plugin@3.2.0 -D)
babel-loader(npm i babel-loader@7 -D)
vue-loader(npm i vue-loader@15 -D)
style-loader 最新
css-loader 最新
vue-style-loader 最新
(如果有sass-loaderless-loader,也更新最新)
url-loader@1
file-loader@1
ts-loader 更新最新
extract-text-webpack-plugin的beta包 (npm i extract-text-webpack-plugin@next -D) 或者 mini-css-extract-plugin
mini-css-extract-plugin
遇到的問題(node:8532) DeprecationWarning: Tapable.plugin is deprecated. Use new API on .hooks instead
在
文件下添加了process.traceDeprecation = true
運行 npm run dev,按照webpack.dev.conf.js配置跑下dev-server,發現
升級下
再跑,發現
更新
npm install webpack-dev-middleware@3 -DjavaScript File Code Spliting 代碼分離
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 Code Spliting 代碼分離
我們在用 Vue 開發業務時,往往是把某個功能封裝成 Vue 組件,Vue 動態組件加載 相比 純js 加載更有實際意義。
異步加載 Vue 組件(.vue) 已在 Vue 2.5+ 版本支持,包括路由異步加載和非路由異步加載。在具體實現時,我們可以通過 import(filepath) 加載組件。
Webpack 已經支持了該特性。import() 返回的 Promise,通過注釋 webpackChunkName 指定生成的 chunk 名稱。 Webpack 構建時會獨立的 chunkjs 文件,然后在客戶端動態插入組件,chunk 機制與 require.ensure 一樣。有了動態加載的方案,可以減少服務端渲染 jsbundle 文件的大小,頁面 Vue 組件模塊也可以按需加載。
Vue.component("async-swiper", (resolve) => { // 通過注釋webpackChunkName 指定生成的chunk名稱 import(/* webpackChunkName: "asyncSwiper" */ "./AsyncSwiper.vue") });Vue dynamic component load
其實這里說的就是 vue-router里的 路由懶加載
實際spa項目中:
webpack 指南
4.30版本中文文檔
《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 文檔
Egg + Vue SSR 組件異步加載
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/96221.html
摘要:本篇不包含所有坑,暫時只記錄自己踩到的部分坑一安裝安裝最新版本安裝新增依賴這個在中,本身和它的是在同一個包中,中將兩個分開管理。我記錄下自己更新這個的過程,以下前半部分可以直接跳過。以下記錄踩坑過程。 本篇不包含所有坑,暫時只記錄自己踩到的部分坑 一.安裝 安裝webpack4最新版本 npm install --save-dev webpack@4 安裝新增依賴 webpack-c...
摘要:簡介來構建用戶界面的庫,不是框架關注于層虛擬單向數據流這些概念如何使用下載文件也可以使用,需要用到的模塊介紹是編寫組件的一種語法規范,可以看為是的擴展,它支持將和混寫在一起,最后使用編譯為常規的,方便瀏覽器解析編寫第一個例子使用編寫組件 react簡介 來構建用戶界面的庫,不是框架 關注于view層 虛擬DOM 單向數據流 JSX這些概念 如何使用react 下載文件 rea...
摘要:體驗記錄大法好退保平安打包工具前端工程化一直是前端的一塊重點之前構建工具的選擇上,公司也是很早之前就從收攏為的確是個好工具,作為工具核心的依賴表是非常好的構建思路,也是很多大公司一直在用的構建工具但是個人用的非常不習慣生態不是很好它太大太重 Webpack體驗記錄 webpack大法好 退fis保平安 打包工具前端工程化一直是前端的一塊重點.之前構建工具的選擇上,公司也是很早之前就從g...
摘要:體驗記錄大法好退保平安打包工具前端工程化一直是前端的一塊重點之前構建工具的選擇上,公司也是很早之前就從收攏為的確是個好工具,作為工具核心的依賴表是非常好的構建思路,也是很多大公司一直在用的構建工具但是個人用的非常不習慣生態不是很好它太大太重 Webpack體驗記錄 webpack大法好 退fis保平安 打包工具前端工程化一直是前端的一塊重點.之前構建工具的選擇上,公司也是很早之前就從g...
摘要:安裝寫在里安裝和配置和之前一樣用來處理文件相關的這個包括的就比較多,有,后面兩個是為了寫和服務。 這兩天學習了一些webpack的知識,loaders+plugins真的很強大!不過配置起來也很復雜,看了一些文章,自己也寫了項目練手,寫下來加深自己的印象。 首先,非常非常推薦的幾篇文章,初學者一定要看!http://www.jianshu.com/p/42e1...(標題一點也不夸張,...
閱讀 1686·2021-09-22 10:02
閱讀 1931·2021-09-02 15:40
閱讀 2835·2019-08-30 15:55
閱讀 2243·2019-08-30 15:44
閱讀 3593·2019-08-30 13:18
閱讀 3224·2019-08-30 11:00
閱讀 1945·2019-08-29 16:57
閱讀 564·2019-08-29 16:41