前言:文件依賴關係錯綜複雜,靜態資源請求效率低,模塊化支持不友好,瀏覽器對高級JS兼容程度低?那就是時候瞭解webpack了javascript
webpack 是一個JavaScript 應用程序的靜態模塊打包構建器。在處理應用程序時, webpack 會遞歸地構建一個依賴關係圖,其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。webpack提供了友好的模塊化支持,以及代碼壓縮混淆、高級js兼容、性能優化。css
入口起點(entry point)指示 webpack 使用哪一個模塊,做爲構建其內部依賴圖的開始。進入入口起點後,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的。html
webpack.config.js:vue
module.exports = { entry: { main: './src' //打包入口,來指定一個入口起點(或多個入口起點,默認值爲 ./src) }, entry: './src', //這個是上面的簡寫方式,是等價的 entry: { home: "./home.js", about: "./about.js", contact: "./contact.js" },//對象法指定多個入口,若是你想要多個依賴一塊兒注入到一個模塊,向 entry 屬性傳入「文件路徑(file path)數組」。 entry: () => new Promise((resolve) => resolve(['./demo', './demo2'])),//動態入口,當結合 output.library 選項時:若是傳入數組,則只導出最後一項 };
output 屬性告訴 webpack 在哪裏輸出它所建立的 bundles,以及如何命名這些文件。基本上,整個應用程序結構,都會被編譯到你指定的輸出路徑的文件夾中。java
webpack.config.js:node
const path = require('path'); module.exports = { output: { path: path.resolve(__dirname, 'dist'),//打包文件夾名,默認值爲 ./dist filename: '[name].js'//入口文件名 } };
loader 用於轉換某些類型的模塊,webpack 自身只理解 JavaScript,loader 能夠將全部類型的文件轉換爲 webpack 可以處理的有效模塊。loader 可以 import
導入任何類型的模塊(如 .css
),是 webpack 特有的功能,其餘打包工具備可能不支持。webpack
webpack.config.js:ios
const path = require('path'); const config = { module: { rules: [//在 webpack 配置中定義 loader 時,要定義在 module.rules 中,裏面包含兩個"必須屬性":test 和 use { test: /\.txt$/, //test 定義須要使用相應 loader 進行轉換的某類文件 use: 'raw-loader' //use 定義使用哪一個 loader 進行轉換 } ] } }; module.exports = config;
插件接口功能極其強大,能夠用來處理各類各樣的任務。經過require()
使用插件,而後把它添加到 plugins
數組中。多數插件能夠經過選項(option)自定義。es6
webpack.config.js:web
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 經過 npm 安裝 const webpack = require('webpack'); // 用於訪問內置插件 const config = { plugins: [ //在一個配置文件中由於不一樣目的而屢次使用同一個插件,須要經過使用 new 操做符來建立它的一個實例 new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ] }; module.exports = config;
module.exports = { mode: 'production'//經過選擇 development(開發) 或 production(生產),啓用相應模式下的 webpack 內置的優化 };
webpack 須要傳入一個配置對象, 根據對象定義的屬性進行解析,所以不多有 webpack 配置看起來很徹底相同。 webpack 的配置文件,是導出一個對象的 JavaScript 文件。能夠經過兩種方式(終端、Node.js)使用 webpack。
webpack 配置是標準的 Node.js CommonJS 模塊,你能夠:
require(...)
導入其餘文件require(...)
使用 npm 的工具函數?:
操做符應避免如下作法:
--env
)時,訪問命令行接口(CLI)參數webpack 配置是標準的 Node.js CommonJS 模塊,在安裝webpack以前,請確保安裝了 Node.js 的最新版本,使用舊版本可能遇到各類問題(可能缺乏 webpack 功能或者缺乏相關 package 包)。
對於大多數項目,建議本地安裝。這能夠在引入破壞式變動(breaking change)的依賴時,更容易分別升級項目。不推薦全局安裝 webpack。這會將你項目中的 webpack 鎖定到指定版本,而且在使用不一樣的 webpack 版本的項目中,可能會致使構建失敗。
①本地安裝 npm install --save-dev webpack //安裝最新版本 npm install --save-dev webpack@<version> //安裝特定版本 ②全局安裝 npm install --global webpack
若是你使用 webpack 4+ 版本,你還須要安裝 CLI,此工具用於在命令行中運行 webpack。
npm install --save-dev webpack-cli //webpack-cli用於在命令行中運行 webpack
在已有的項目中:
npm init -y //初始化webpack 這裏會自動生成一個package.json npm i -D webpack webpack-cli //安裝webpack及其腳手架
一個項目包兩個項目demo1和demo2(適用於兩個項目功能需求很相似有公用的地方有不一樣的地方):
{ "name": "webpackstudy", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "demo1-start": "webpack-dev-server --progress --color", "demo2-start": "webpack-dev-server --progress --color", "demo1-mock": "webpack-dev-server --progress --color", "demo2-mock": "webpack-dev-server --progress --color", "demo1-te": "webpack --progress --color", "demo2-te": "webpack --progress --color" }, "author": "", "license": "ISC", "dependencies": { "axios": "^0.19.0", "vue": "^2.6.10", "vue-pull-to": "^0.1.8", "vue-router": "^3.1.2", "vuex": "^3.1.1" }, "devDependencies": { "@babel/core": "^7.5.5", "@babel/preset-env": "^7.5.5", "autoprefixer": "^9.6.1", "babel-loader": "^8.0.6", "clean-webpack-plugin": "^3.0.0", "css-loader": "^3.2.0", "file-loader": "^4.2.0", "html-webpack-plugin": "^3.2.0", "html-withimg-loader": "^0.1.16", "jsonc": "^2.0.0", "less": "^3.10.2", "less-loader": "^5.0.0", "mini-css-extract-plugin": "^0.8.0", "mocker-api": "^1.8.1", "optimize-css-assets-webpack-plugin": "^5.0.3", "postcss-loader": "^3.0.0", "style-loader": "^1.0.0", "terser-webpack-plugin": "^1.4.1", "uglifyjs-webpack-plugin": "^2.2.0", "url-loader": "^2.1.0", "vue-loader": "^15.7.1", "vue-style-loader": "^4.1.2", "vue-template-compiler": "^2.6.10", "webpack": "^4.39.2", "webpack-cli": "^3.3.7", "webpack-dev-server": "^3.8.0" } }
const path = require('path'); const webpack = require('webpack'); // script、link動態添加每次compile後的hash,防止引用緩存的外部文件問題; 自動建立html入口文件 const HtmlWebpackPlugin = require('html-webpack-plugin'); // 用terser-webpack-plugin替換掉uglifyjs-webpack-plugin解決uglifyjs不支持es6語法問題 const TerserJSPlugin = require('terser-webpack-plugin'); // 此模塊至少須要Node v6.9.0和webpack v4.0.0 混淆代碼 const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); // 這個插件將CSS提取到單獨的文件中 支持按需加載CSS和SourceMaps 創建在webpack v4上 const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 用於優化、壓縮CSS資源 const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 打包時將以前打包的目錄裏的文件先清除乾淨,再生成新的 const {CleanWebpackPlugin} = require('clean-webpack-plugin'); //mock數據 const apiMocker = require('mocker-api'); const VueLoaderPlugin = require('vue-loader/lib/plugin'); //獲取 npm run 後面的命令 const lifecycle = process.env.npm_lifecycle_event; //npm run 的文件名 const project = lifecycle.split('-')[0]; //npm run 的環境名 const proMode = lifecycle.split('-')[1] === 'te'; const envMode = lifecycle.split('-')[1]; const webpackConfig = { mode: proMode ? 'production' : 'development', //打包入口爲每一個項目的main.js entry: path.resolve(__dirname, `${project}/main.js`), output: { //打包後的文件目錄爲各自項目名+Dist path: path.resolve(__dirname, `${project}Dist`), //打包後源代碼映射 // devtool: proMode ?'cheap-module-eval-source-map':'hidden-source-map', // devtool: "inline-source-map", //打包後的出口js目錄 filename: 'js/[name].[hash].js', //分塊打包的js目錄 chunkFilename: proMode ? 'js/[name].[contenthash].bundle.js' : 'js/[name].bundle.js', }, module: { rules: [ { test: /\.vue$/, exclude: /node_modules/, use: { loader: 'vue-loader' } }, { test: /\.(le|c)ss$/i, use: [ proMode ? MiniCssExtractPlugin.loader : 'vue-style-loader', 'css-loader', 'postcss-loader', 'less-loader', ], }, { test: /\.html$/i, use: [ 'html-withimg-loader' ] }, { test: /\.(png|jpg|gif)$/i, use: [ { loader: 'url-loader', options: { limit: 4096, name: 'img/[name].[contenthash].[ext]' }, }, ], }, { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] }, //webpack-dev-server 配置npm run 時啓動本地服務 devServer: { contentBase: `./${project}Dist`, inline: true //實時刷新 }, //優化 optimization: { // 分塊 splitChunks: { chunks: 'all', cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors', chunks: 'all' }, } } }, plugins: [ new CleanWebpackPlugin(), //定義插件—— 在項目中能夠讀取到 new webpack.DefinePlugin({ 'baseUrl':proMode ? 'https:www.baidu.com':JSON.stringify('localhost') }), new HtmlWebpackPlugin({ title:'webpack練習', filename: 'index.html', template: `${project}/index.html`, // 對 html 文件進行壓縮 minify: { //是否對大小寫敏感,默認false caseSensitive: false, //是否簡寫boolean格式的屬性如:disabled="disabled" 簡寫爲disabled 默認false collapseBooleanAttributes: true, //是否去除空格,默認false collapseWhitespace: true, //是否壓縮html裏的css(使用clean-css進行的壓縮) 默認值false; minifyCSS: true, //是否壓縮html裏的js(使用uglify-js進行的壓縮) minifyJS: true, //是否移除註釋 默認false removeComments: true, //Prevents the escaping of the values of attributes preventAttributesEscaping: true, //是否移除屬性的引號 默認false removeAttributeQuotes: true, //從腳本和樣式刪除的註釋 默認false removeCommentsFromCDATA: true, //是否刪除空屬性,默認false removeEmptyAttributes: false, // 若開啓此項,生成的html中沒有 body 和 head,html也未閉合 removeOptionalTags: false, //刪除多餘的屬性 removeRedundantAttributes: true, //刪除script的類型屬性,在h5下面script的type默認值:text/javascript 默認值false removeScriptTypeAttributes: true, //刪除style的類型屬性, type="text/css" 同上 removeStyleLinkTypeAttributes: true, //使用短的文檔類型,默認false useShortDoctype: false, } }), new VueLoaderPlugin() ], //目錄映射 resolve: { alias: { '@assets': path.resolve(__dirname, `${project}/assets`), '@mixins': path.resolve(__dirname, `${project}/mixins`), '@tools': path.resolve(__dirname, `${project}/tools`), '@components': path.resolve(__dirname, `${project}/components`), } } }; if (proMode) { webpackConfig.optimization.minimizer = [ //混淆語法 new UglifyJsPlugin({ chunkFilter: (chunk) => { if (chunk.name === 'vendor') { return false; } return true; }, //去掉控制檯日誌 uglifyOptions: { compress: { drop_console: true } } }), new OptimizeCssAssetsPlugin({}) ]; // webpackConfig.optimization.minimizer = [new TerserJSPlugin({}), // new OptimizeCssAssetsPlugin({}),]; webpackConfig.plugins.push( new MiniCssExtractPlugin({ filename: proMode ? '[name].css' : '[name].[hash].css', chunkFilename: proMode ? '[id].css' : '[id].[hash].css', }) ) } else { // 熱更新模塊 webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); webpackConfig.devtool = 'inline-source-map'; if (envMode == 'mock') { //mock環境,啓用mock代理服務 webpackConfig.devServer.before = (app) => { apiMocker(app, path.resolve(`${project}/mock/api.js`)); }; //非mock匹配項走測試環境 webpackConfig.devServer.proxy = process.baseUrl; } } module.exports = webpackConfig;