如何学习配置webpack(一)
項目小白如何從0開始配置webpack
自己配置過webpack的人應該都知道,webpack真的好復雜,一開始做項目都是拿別人現成的做做小修改,但是別人的終究沒有自己配的舒服。所以我打算寫這篇文章,從我的配置中帶大家了解webpack配置,簡化讀webpack官方頁面的復雜度。
首先我們需要明確我們要求webpack做什么?
1.所寫即所得,我們在編譯器中寫了代碼能馬上呈現在調試器上(熱更新服務)
2.本地開發獲取數據存在的跨域問題(代理,解決跨域)
3.使用es678,less,sass等(翻譯,讓瀏覽器懂得我們的代碼)
4.提高項目性能,比如壓縮代碼,壓縮圖片等(項目優化)
5.如果與輸入相關的需求,找entry(比如多頁面就有多個入口) 6.如果與輸出相關的需求,找output(比如你需要定義輸出文件的路徑、名字等等) 7.如果與模塊尋址相關的需求,找resolve(比如定義別名alias) 8.如果與轉譯相關的需求,找loader(比如處理sass處理es678N) 9.如果與構建流程相關的需求,找plugin(比如我需要在打包完成后,將打包好的文件復制到某個目錄,然后提交到git上) 接下來我們來看下webpack的一些基本配置
1.entry(項目入口)
2.output(出口文件)
3.modules(模塊處理)
4.plugin(插件)
5.resolve
6.devserver
7.mode,
8devtool
1.項目入口設置(entry)
主要有三種方式
1.字符串形式
entry: '.src/main.js' 復制代碼2.數組形式
entry: [react, react-dom] 復制代碼3.對象形式
entry: {main:'./src/index2.js',second: './src/index2.js',vendor:['react', 'react-dom'] } 復制代碼2.出口文件設置及(output)
const path = require('path'); module.exports = {entry: './path/to/my/entry/file.js',output: {path: path.resolve(__dirname, 'dist'),filename: 'my-first-webpack.bundle.js'} }; 復制代碼在上面的示例中,我們通過 output.filename 和 output.path 屬性,來告訴 webpack bundle 的名稱,以及我們想要 bundle 生成(emit)到哪里。 Path.resolve是什么,引入的path模塊是干什么用的
Nodejs
該path.resolve()方法將一系列路徑或路徑段解析為絕對路徑。
給定的路徑序列從右到左處理,隨后每個path路徑都被預先加載,直到構造出絕對路徑。例如,給定路徑段的序列:/foo,/bar,baz,調用path.resolve('/foo', '/bar', 'baz')將返回/bar/baz。
如果在處理path完所有給定段之后尚未生成絕對路徑,則使用當前工作目錄。 生成的路徑已規范化,并且除非將路徑解析為根目錄,否則將刪除尾部斜杠。 零長度path段被忽略。
如果沒有path傳遞段,path.resolve()將返回當前工作目錄的絕對路徑。
path.resolve('/foo/bar', './baz'); // Returns: '/foo/bar/baz' path.resolve('/foo/bar', '/tmp/file/'); // Returns: '/tmp/file' path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif'); // If the current working directory is /home/myself/node, // this returns '/home/myself/node/wwwroot/static_files/gif/image.gif' _dirname 復制代碼當前模塊的目錄名稱。這是一樣 path.dirname()的__filename。
示例:node example.js從中運行/Users/mjr
console.log(__dirname); // Prints: /Users/mjr console.log(path.dirname(__filename)); // Prints: /Users/mjr 復制代碼我們在配置output是常用的幾個
filename 這個是輸出文件的名稱,字符串類型,如果只有一個輸出文件,可以寫成靜態名稱。例如
output:{filename:'bundle.js' } 復制代碼當然了,在我們日常工作中,一般情況下是不會有這種情況的,當項目很大的時候,如果不分塊打包,bundle.js會驚人的大,項目越大,bundle.js就會越大,這不是我們今天討論的重點,以后再說
多個chunk的時候怎么辦呢
webpack會為每個生成的Chunk取一個名稱,Chunk的名稱和Entry的配置有關:
1. 如果entry是一個string或者array,就只會生成一個chunk,這個chunk的名稱是main;
2. 如果entry是一個object,就可能出現多個chunk,這時chunk的名稱是object鍵值對里鍵的名稱
然而,當通過多個入口起點(entry point)、代碼拆分(code splitting)或各種插件(plugin)創建多個
bundle,應該使用以下一種替換方式,來賦予每個 bundle 一個唯一的名稱…… 使用入口名稱:
output:{filename: "[name].bundle.js" } 復制代碼使用內部 chunk id
output:{filename: "[id].bundle.js" } 復制代碼使用每次構建過程中,唯一的 hash 生成
output:{ filename: "[name].[hash].bundle.js" } 復制代碼使用基于每個 chunk 內容的 hash:
output:{ filename: "[chunkhash].bundle.js" } 復制代碼這里多出來幾個陌生詞匯hash、chunkhash,它們是什么? hash、chunkhash和contenthash三者的區別 hash
hash的值是相同的,如果都使用hash的話,因為這是工程級別的,即每次修改任何一個文件,所有文件名的hash至都將改變。所以一旦修改了任何一個文件,整個項目的文件緩存都將失效。所以對于沒有改變的模塊而言,這樣做顯然不恰當,因為緩存失效了嘛。此時,chunkhash的用途隨之而來。 chunkhash
只有被修改了的文件的文件名,hash值修改
filename: '[name]-[chunkhash].js'
當我們使用mini-css-extract-plugin拆分css的時候,就需要使用chunkhash,我一個js文件里面引入了css文件。這時要是我修改了js,但沒修改css,可以通過chunkhash緩存css文件
contenthash
對css使用了chunkhash之后,我們測試會發現,如果修改了js,css文件名的hash值確實沒變,但這時要是我們修改css文件的話,我們就會發現css文件名的chunkhash值居然沒變化,這樣就導致我們的非覆蓋發布css文件失效了。所以這里需要注意就是css文件必須使用contenthash。
上面介紹的 id、name、hash、chunkhash等都是webpack內置變量, id是唯一標示,不會重復,從0開始, name 是模塊名稱,是你自己起的,在配置路由懶加載的時候可以自己命名 官網介紹的很清楚,我就不再這里啰嗦了, chunkFilename
官網解釋:此選項決定了非入口(non-entry) chunk 文件的名稱, 什么場景需要呢?
在按需加載(異步)模塊的時候,也就是路由懶加載,這樣的文件是沒有被列在entry中的,
比如
{entry: {"index": "pages/index.jsx"},output: {filename: "[name].min.js",chunkFilename: "[name].min.js"} } const myModel = r => require.ensure([], () => r(require('./myVue.vue')), 'myModel') 復制代碼上面的例子,通過filename輸出的是index.min.js 異步加載的模塊是要以文件形式加載哦,所以這時生成的文件名是以chunkname配置的,通過chunkFilename輸出的是myModel.min.js 所以chunkFilename也很重要哦!!! path path是配置輸出文件存放在本地的目錄,字符串類型,是絕對路徑
output:{path: path.resolve(__dirname, 'dist/assets') } 復制代碼__dirname,這個昨天說過,可以回顧一下,就是當前文件所在的文件夾的名字 publicPath 對構建出的資源進行異步加載(圖片,文件),該選項的值是以 runtime(運行時) 或 loader(載入時) 所創建的每個 URL 為前綴。因此,在多數情況下,此選項的值都會以/結束。 默認值是一個空字符串 "",即相對路徑,配置錯誤會導致404 簡單說,就是靜態文件托管在cdn上 舉個栗子: 如果你這么配置:
output:{filename:'[name]_[chunkhash:8].js',publicPath:'https://www.qdtalk.com/assets/' } 復制代碼打包編譯后,html頁面就是這樣的
path 和publicPath都支持字符串模板
- 配置 單出口 // webpack 配置
- 配置 多出口
3.modules(模塊處理)
模塊處理主要是對loader的配置
此處引用官網對loader的定義
loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以將所有類型的文件轉換為webpack能夠處理的有效模塊,然后你就可以利用webpack的打包能力,對它們進行處理。
本質上,webpack loader 將所有類型的文件,轉換為應用程序的依賴圖(和最終的 bundle)可以直接引用的模塊。 注意,loader 能夠 import 導入任何類型的模塊(例如 .css 文件),這是 webpack 特有的功能,其他打包程序或任務執行器的可能并不支持。我們認為這種語言擴展是有很必要的,因為這可以使開發人員創建出更準確的依賴關系圖。 在更高層面,在 webpack 的配置中 loader 有兩個目標:
1. test 屬性,用于標識出應該被對應的 loader 進行轉換的某個或某些文件。
2. use 屬性,表示進行轉換時,應該使用哪個 loader。
webpack.config.js const path = require('path'); const config = {output: {filename: 'my-first-webpack.bundle.js'},module: {rules: [{ test: /\.txt$/, use: 'raw-loader' }]} }; module.exports = config; 復制代碼以上配置中,對一個單獨的 module 對象定義了 rules 屬性,里面包含兩個必須屬性:test 和 use。這告訴 webpack 編譯器(compiler) 如下信息:
“嘿,webpack 編譯器,當你碰到「在 require()/import 語句中被解析為 '.txt' 的路徑」時,在你對它打包之前,先使用 raw-loader 轉換一下。” 重要的是要記得,在 webpack 配置中定義 loader 時,要定義在 module.rules 中,而不是 rules。然而,在定義錯誤時 webpack 會給出嚴重的警告。為了使你受益于此,如果沒有按照正確方式去做,webpack 會“給出嚴重的警告”
在webpack中有許許多多的loader,此處我按照官方文檔解釋下和我理解的用法 loader 特性
- 幾乎所有 loader 都 需要安裝, 但 不需要 在 webpack 配置文件中通過 require 引入
- 逆向編譯,鏈式傳遞 文件
- raw-loader 加載文件原始內容(utf-8)
- val-loader 將代碼作為模塊執行,并將 exports 轉為 JS 代碼
- url-loader 像 file loader 一樣工作,但如果文件小于限制,可以返回 data URL
- file-loader 將文件發送到輸出文件夾,并返回(相對)URL raw-loader 可以讓你在代碼中引入文件
val-loader 加載的模塊必須使用以下函數接口,將 default export 導出為一個函數。
function answer () {return {code: 'module.exports = 42;'} }; module.exports = answer; 復制代碼url-loader
url-loader 功能類似于 file-loader,但是在文件大小(單位 byte)低于指定的限制時,可以返回一個 DataURL。 file-loader 將文件發送到輸出文件夾,并返回(相對)URL(不會再對文件做處理) JSON
- json-loader 加載 JSON 文件(默認包含)
- json5-loader 加載和轉譯 JSON 5 文件
- cson-loader 加載和轉譯 CSON 文件 主要處理json文件
轉換編譯(Transpiling)
- script-loader 在全局上下文中執行一次 JavaScript 文件(如在 script 標簽),不需要解析
- babel-loader 加載 ES2015+ 代碼,然后使用 Babel 轉譯為 ES5
- buble-loader 使用 Bublé 加載 ES2015+ 代碼,并且將代碼轉譯為 ES5
- traceur-loader 加載 ES2015+ 代碼,然后使用 Traceur 轉譯為 ES5
- ts-loader 或 awesome-typescript-loader 像 JavaScript 一樣加載 TypeScript 2.0+
- coffee-loader 像 JavaScript 一樣加載 CoffeeScript
React開發過程中我們需要將jsx或者es6代碼轉譯成es5代碼。 我們需要用到babel-loader
{ 'test': /\.(js|jsx)$/, // babel 轉換為兼容性的 js 'exclude': /node_modules/, 'loader': 'babel-loader', 'query': { 'presets': ['react', 'latest', 'stage-0', 'react-hmre'] }, 'include': path.resolve(__dirname, '../client') }, 復制代碼注:exclude是不轉換node_modules的代碼,query === options 此處注意babel版本6和7設置上有區別。 如果引用錯誤會報錯 模板(Templating)
- html-loader 導出 HTML 為字符串,需要引用靜態資源
- pug-loader 加載 Pug 模板并返回一個函數
- jade-loader 加載 Jade 模板并返回一個函數
- markdown-loader 將 Markdown 轉譯為 HTML
- react-markdown-loader 使用 markdown-parse parser(解析器) 將 Markdown 編譯為 React 組件
- posthtml-loader 使用 PostHTML 加載并轉換 HTML 文件
- handlebars-loader 將 Handlebars 轉移為 HTML
- markup-inline-loader 將內聯的 SVG/MathML 文件轉換為 HTML。在應用于圖標字體,或將 CSS 動畫應用于 SVG 時非常有用。
樣式
- style-loader 將模塊的導出作為樣式添加到 DOM 中
- css-loader 解析 CSS 文件后,使用 import 加載,并且返回 CSS 代碼
- less-loader 加載和轉譯 LESS 文件
- sass-loader 加載和轉譯 SASS/SCSS 文件
- postcss-loader 使用 PostCSS 加載和轉譯 CSS/SSS 文件
- stylus-loader 加載和轉譯 Stylus 文件 如果我們在開發中使用了less或者sass,我們需要先轉換成css在引入到項目中
此處的執行順序。less-loader -> css-loader -> style-loader 清理和測試(Linting && Testing)
- mocha-loader 使用 mocha 測試(瀏覽器/NodeJS)
- eslint-loader PreLoader,使用 ESLint 清理代碼
- jshint-loader PreLoader,使用 JSHint 清理代碼
- jscs-loader PreLoader,使用 JSCS 檢查代碼樣式
- coverjs-loader PreLoader,使用 CoverJS 確定測試覆蓋率
框架(Frameworks)
- vue-loader 加載和轉譯 Vue 組件
- polymer-loader 使用選擇預處理器(preprocessor)處理,并且 require() 類似一等模塊(first-class)的 Web 組件
- angular2-template-loader 加載和轉譯 Angular 組件
核心重點(敲黑板)
plugins(插件)
作用:可以處理各種任務,從打包優化和壓縮,一直到重新定義環境中的變量 loader不需要require. plugin需要
loader 被用于轉換某些類型的模塊,而插件則可以用于執行范圍更廣的任務。插件的范圍包括,從打包優化和壓縮,一直到重新定義環境中的變量。插件接口功能極其強大,可以用來處理各種各樣的任務。
想要使用一個插件,你只需要 require() 它,然后把它添加到 plugins 數組中。多數插件可以通過選項(option)自定義。你也可以在一個配置文件中因為不同目的而多次使用同一個插件,這時需要通過使用 new 操作符來創建它的一個實例。 下面是我配置的用于開發環境的plugins實例
webpack.config.js const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通過 npm 安裝 const webpack = require('webpack'); // 用于訪問內置插件 const config = {module: {rules: [{ test: /\.txt$/, use: 'raw-loader' }]},plugins: [new HtmlWebpackPlugin({template: './src/index.html'})] }; module.exports = config; 復制代碼'plugins': [ new webpack.optimize.OccurrenceOrderPlugin(), // 調整模塊的打包順序,用到次數更多的會出現在文件的前面 new webpack.DefinePlugin({ // DefinePlugin 允許創建一個在編譯時可以配置的全局常量。 'process.env.NODE_ENV': JSON.stringify('development') }), new HtmlWebpackPlugin({ // HtmlWebpackPlugin簡化了HTML文件的創建,以便為你的webpack包提供服務。這對于在文件名中包含每次會隨著編譯而發生變化哈希的 webpack bundle 尤其有用。 你可以讓插件為你生成一個HTML文件,使用lodash模板提供你自己的模板,或使用你自己的loader。 'hash': true, 'title': 'Demo', 'filename': 'index.html', 'template': path.resolve(__dirname, '../views/index.ejs'), 'inject': 'body' }), new webpack.HotModuleReplacementPlugin(), // 啟用熱更新 new webpack.NoEmitOnErrorsPlugin(), // 輸出階段遇到編譯錯誤跳過 new webpack.NamedModulesPlugin(), // 當開啟 HMR 的時候使用該插件會顯示模塊的相對路徑,建議用于開發環境。 new webpack.ProgressPlugin(), // 輸出構建進度 ] 復制代碼轉載于:https://juejin.im/post/5cc133f5f265da03914d65d1
總結
以上是生活随笔為你收集整理的如何学习配置webpack(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CrazyDiskInfo硬盘检测工具
- 下一篇: 浅复制与深复制概念