隨着前端的不斷髮展與壯大,前端變得愈來愈複雜,組件化、模塊化、工程化、自動化成了前端發展中不可或缺的一部分,具體到前端工程化,面臨的問題是如何提升編碼->測試->維護階段的生產效率。javascript
前端工程化是使用軟件工程的技術和方法來進行前端項目的開發、維護和管理。css
前端工程化是依據業務特色,將前端開發的規範、流程、技術、工具、經驗等造成規範並創建成一種標準的體系。html
如今的項目可能會不停的迭代,發佈就成了平常開發的一部分,前端不只要保證功能還要保證性能,傳統的一次次的發佈效率會很是低,前端工程化通常都有會藉助一些工具。前端
實現前端工程化的目的簡單來講就是經過流程規範、自動化工具來提高前端的開發效率、性能、質量、多人協做能力以及開發體驗,創建前端工程化是各個團隊必經的成長過程。vue
前端不只要保證功能還要考慮性能,要減小http請求數量、壓縮、合併、預處理、規範代碼、清理、打包、轉換等工做。java
前端大部分狀況下源代碼沒法直接運行,必須經過轉換後才能夠正常運行。構建就是作這件事情,把源代碼轉換成發佈到線上的可執行 JavaScrip、CSS、HTML 代碼,包括以下內容。node
(1)、代碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等。react
(2)、文件優化:壓縮 JavaScript、CSS、HTML 代碼,壓縮合並圖片等。jquery
(3)、代碼分割:提取多個頁面的公共代碼、提取首屏不須要執行部分的代碼讓其異步加載。webpack
(4)、模塊合併:在採用模塊化的項目裏會有不少個模塊和文件,須要構建功能把模塊分類合併成一個文件。
(5)、自動刷新:監聽本地源代碼的變化,自動從新構建、刷新瀏覽器。
(6)、代碼校驗:在代碼被提交到倉庫前須要校驗代碼是否符合規範,以及單元測試是否經過。
(7)、自動發佈:更新完代碼後,自動構建出線上發佈代碼並傳輸給發佈系統。
構建實際上是工程化、自動化思想在前端開發中的體現,把一系列流程用代碼去實現,讓代碼自動化地執行這一系列複雜的流程。 構建給前端開發注入了更大的活力,解放了咱們的生產力。
歷史上前後出現一系列構建工具,它們各有其優缺點。因爲前端工程師很熟悉 JavaScript ,Node.js 又能夠勝任全部構建需求,因此大多數構建工具都是用 Node.js 開發的。
構建工具的主要功能就是實現自動化處理,例如對代碼進行檢查、預編譯、合併、壓縮;生成雪碧圖、sourceMap、版本管理;運行單元測試、監控等,固然有的工具還提供模塊化、組件化的開發流程功能。
若是把工具按類型分能夠分爲這三類:
(一)、基於任務運行的工具:Grunt、Gulp
它們會自動執行指定的任務,就像流水線,把資源放上去而後經過不一樣插件進行加工,它們包含活躍的社區,豐富的插件,能方便的打造各類工做流。
(二)、基於模塊化打包的工具:Browserify、Webpack、rollup.js
有過 Node.js 開發經歷的應該對模塊很熟悉,須要引用組件直接一個 require 就 OK,這類工具就是這個模式,還能夠實現按需加載、異步加載模塊。
(三)、整合型工具:Yeoman、FIS、jdf、Athena、cooking、weflow
使用了多種技術棧實現的腳手架工具,好處是即開即用,缺點就是它們約束了技術選型,而且學習成本相對較高。
Grunt([ɡrʌnt]做呼嚕聲) 生態系統很是龐大,而且一直在增加。因爲擁有數量龐大的插件可供選擇,所以,你能夠利用 Grunt 自動完成許多事,而且花費不多的代價。若是找不到你所須要的插件,那就本身動手創造一個 Grunt 插件,而後將其發佈到 npm 上吧。
GitHub:https://github.com/gruntjs/
對於須要反覆重複的任務,例如壓縮(minification)、編譯、單元測試、linting等,自動化工具能夠減輕你的勞動,簡化你的工做。當你在 Gruntfile 文件正確配置好了任務,任務運行器就會自動幫你或你的小組完成大部分無聊的工做。
Grunt 是老牌的構建工具,特色是配置驅動,你須要作的就是了解各類插件的功能,而後把配置整合到 Gruntfile.js 中,下面是配置例子:
module.exports = function(grunt) { grunt.initConfig({ jshint: { files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'], options: { globals: { jQuery: true } } }, watch: { files: ['<%= jshint.files %>'], tasks: ['jshint'] } }); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.registerTask('default', ['jshint']); };
Grunt 缺點也是配置驅動,當任務很是多的狀況下,試圖用配置完成全部事簡直就是個災難;再就是它的 I/O 操做也是個弊病,它的每一次任務都須要從磁盤中讀取文件,處理完後再寫入到磁盤,例如:我想對多個 less 進行預編譯、壓縮操做,那麼 Grunt 的操做就是:
讀取 less 文件 -> 編譯成 css -> 存儲到磁盤 -> 讀取 css -> 壓縮處理 -> 存儲到磁盤
這樣一來當資源文件較多,任務較複雜的時候性能就是個問題了。
Gulp(ɡʌlp狼吞虎嚥地吃,吞嚥)是一個基於流的自動化構建工具。 除了能夠管理和執行任務,還支持監聽文件、讀寫文件。
中文網:https://www.gulpjs.com.cn/
特色:
易於使用:經過代碼優於配置的策略,Gulp 讓簡單的任務簡單,複雜的任務可管理。
構建快速:利用 Node.js 流的威力,你能夠快速構建項目並減小頻繁的 IO 操做。
插件高質:Gulp 嚴格的插件指南確保插件如你指望的那樣簡潔高質得工做。
易於學習:經過最少的 API,掌握 Gulp 不太費力,構建工做盡在掌握:如同一系列流管道。
Gulp 被設計得很是簡單,只經過下面5種個方法就能夠勝任幾乎全部構建場景:
經過 gulp.task 註冊一個任務;
經過 gulp.run 執行任務;
經過 gulp.watch 監聽文件變化;
經過 gulp.src 讀取文件;
經過 gulp.dest 寫文件。
Gulp 的最大特色是引入了流的概念,同時提供了一系列經常使用的插件去處理流,流能夠在插件之間傳遞
Gulp 特色是代碼驅動,寫任務就和寫普通的 Node.js 代碼同樣:
var gulp = require('gulp'); var pug = require('gulp-pug'); var less = require('gulp-less'); var minifyCSS = require('gulp-csso'); gulp.task('html', function(){ return gulp.src('client/templates/*.pug') .pipe(pug()) .pipe(gulp.dest('build/html')) }); gulp.task('css', function(){ return gulp.src('client/templates/*.less') .pipe(less()) .pipe(minifyCSS()) .pipe(gulp.dest('build/css')) }); gulp.task('default', [ 'html', 'css' ]);
再一個對文件讀取是流式操做(Stream),也就是說一次 I/O 能夠處理多個任務,仍是 less 的例子,Gulp 的流程就是:
讀取 less 文件 -> 編譯成 css -> 壓縮處理 -> 存儲到磁盤
Gulp 做爲任務類型的工具沒有明顯的缺點,惟一的問題可能就是完成相同的任務它須要寫的代碼更多一些,因此除非是項目有歷史包袱(原有項目就是基於 Grunt 構建)在 Grunt 與 Gulp 對比看來仍是比較推薦 Gulp!
適用場景:
經過上面的介紹能夠看出它們側重對整個過程的控制管理,實現簡單、對架構無要求、不改變開發模式,因此很是適合前端、小型、須要快速啓動的項目。
Yeoman是一個強健的腳手架與構建工具,庫,及工做流程的組合,幫你網頁開發者快速建立出漂亮並且引人入勝的網頁程序,Yeoman幫助咱們建立項目,提供更好的工具來使咱們的項目更多樣化。
Yeoman提供generator系統,一個generator是一個插件,在咱們在一個完整的項目上使用‘yo’命令時,會運行該generator。經過這些官方的Generators,推出了Yeoman工做流,工做流是一個健壯、有本身特點的客戶端堆棧,包含能快速構建漂亮的網絡應用的工具和框架。Yeoman提供了負責開始項目開發的一切,沒有任何讓人頭痛的手動配置。
Yeoman主要提供了三個工具:腳手架(yo),構建工具(grunt),包管理器(bower)。這三個工具是分別獨立開發的,可是須要配合使用,來實現咱們更高效的工做流模式。
小結:
在 Npm Script 和 Grunt 時代,Web 開發要作的事情變多,流程複雜,自動化思想被引入,用於簡化流程;
在 Gulp 時代開始出現一些新語言用於提升開發效率,流式處理思想的出現是爲了簡化文件轉換的流程,例如將 ES6 轉換成 ES5。
在 Webpack 時代因爲單頁應用的流行,一個網頁的功能和實現代碼變得龐大,Web 開發向模塊化改進。
這些構建工具都有各自的定位和專一點,它們之間既能夠單獨地完成任務,也能夠相互搭配起來彌補各自的不足。 在瞭解這些常見的構建工具後,你須要根據本身的需求去判斷應該如何選擇和搭配它們才能更好地完成本身的需求。
通過多年的發展, Webpack 已經成爲構建工具中的首選,緣由是:
大多數團隊在開發新項目時會採用緊跟時代的技術,這些技術幾乎都會採用「模塊化+新語言+新框架」,Webpack 能夠爲這些新項目提供一站式的解決方案;
Webpack 有良好的生態鏈和維護團隊,能提供良好的開發體驗和保證質量;
Webpack 被全世界的大量 Web 開發者使用和驗證,能找到各個層面所需的教程和經驗分享。
webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。
Webpack 是一個打包模塊化 JavaScript 的工具,在 Webpack 裏一切文件皆模塊,經過 Loader 轉換文件,經過 Plugin 注入鉤子,最後輸出由多個模塊組合成的文件。Webpack 專一於構建模塊化項目。
其官網的首頁圖很形象的畫出了 Webpack 是什麼,以下:
一切文件:JavaScript、CSS、SCSS、圖片、模板,在 Webpack 眼中都是一個個模塊,這樣的好處是能清晰的描述出各個模塊之間的依賴關係,以方便 Webpack 對模塊進行組合和打包。 通過 Webpack 的處理,最終會輸出瀏覽器能使用的靜態資源。
Webpack 具備很大的靈活性,能配置如何處理文件,大體使用以下:
module.exports = { // 全部模塊的入口,Webpack 從入口開始遞歸解析出全部依賴的模塊 entry: './app.js', output: { // 把入口所依賴的全部模塊打包成一個文件 bundle.js 輸出 filename: 'bundle.js' } }
把一切都視爲模塊:無論是 CSS、JS、Image 仍是 HTML 均可以互相引用,經過定義 entry.js,對全部依賴的文件進行跟蹤,將各個模塊經過 loader 和 plugins 處理,而後打包在一塊兒。
按需加載:打包過程當中 Webpack 經過 Code Splitting 功能將文件分爲多個 chunks,還能夠將重複的部分單獨提取出來做爲 commonChunk,從而實現按需加載。
優勢:
專一於處理模塊化的項目,能作到開箱即用一步到位;
經過 Plugin 擴展,完整好用又不失靈活;
使用場景不只限於 Web 開發;
社區龐大活躍,常常引入緊跟時代發展的新特性,能爲大多數場景找到已有的開源擴展;
良好的開發體驗。
缺點:
Webpack的缺點是隻能用於採用模塊化開發的項目。
上手比較難、對於新手而言須要經歷踩坑的過程。
對於Server 端渲染的多頁應用有點力不從心。
小結:
Webpack 特別適合配合 React.js、Vue.js 構建單頁面應用以及須要多人合做的大型項目,在規範流程都已約定好的狀況下每每能極大的提高開發效率與開發體驗。
github:https://github.com/webpack/webpack
中文網:https://www.webpackjs.com/
深刻淺出webpack電子書:http://webpack.wuhaolin.cn/
Webpack 是經過配置來實現管理,與 Grunt 不一樣的是它包含的許多自動化的黑盒操做因此配置起來會簡單不少(但遇到問題調試起來就很麻煩),一個典型的配置以下:
module.exports = { //插件項 plugins: [commonsPlugin], //頁面入口文件配置 entry: { index : './src/js/page/index.js' }, //入口文件輸出配置 output: { path: 'dist/js/page', filename: '[name].js' }, module: { //加載器配置 loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.js$/, loader: 'jsx-loader?harmony' }, { test: /\.scss$/, loader: 'style!css!sass?sourceMap'}, { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} ] }, //其它解決方案配置 resolve: { root: '/Users/Bell/github/flux-example/src', //絕對路徑 extensions: ['', '.js', '.json', '.scss'], alias: { AppStore : 'js/stores/AppStores.js', ActionType : 'js/actions/ActionType.js', AppAction : 'js/actions/AppAction.js' } } };
(1)、安裝NodeJS
在用 Webpack 執行構建任務時須要經過 webpack 可執行文件去啓動構建任務,因此須要安裝 webpack 可執行文件。 在安裝 Webpack 前請確保你的系統安裝了5.0.0及以上版本的 Node.js。
去https://nodejs.org/下載安裝
設置國內npm的鏡像
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
使用時用cnpm代替npm
(2)、安裝webpack
安裝 Webpack 到全局
安裝到全局後你能夠在任何地方共用一個 Webpack 可執行文件,而不用各個項目重複安裝,安裝方式以下:
npm i -g webpack
cli:
全部cli參數:
webpack-cli 3.1.2 Usage: webpack-cli [options] webpack-cli [options] --entry <entry> --output <output> webpack-cli [options] <entries...> --output <output> webpack-cli <command> [options] For more information, see https://webpack.js.org/api/cli/. Config options: --config Path to the config file [string] [default: webpack.config.js or webpackfile.js] --config-register, -r Preload one or more modules before loading the webpack configuration [array] [default: module id or path] --config-name Name of the config to use [string] --env Environment passed to the config, when it is a function --mode Enable production optimizations or development hints. [choices: "development", "production", "none"] Basic options: --context The base directory (absolute path!) for resolving the `entry` option. If `output.pathinfo` is set, the included pathinfo is shortened to this directory. [string] [default: The current directory] --entry The entry point(s) of the compilation. [string] --watch, -w Enter watch mode, which rebuilds on file change. [boolean] --debug Switch loaders to debug mode [boolean] --devtool A developer tool to enhance debugging. [string] -d shortcut for --debug --devtool eval-cheap-module-source-map --output-pathinfo [boolean] -p shortcut for --optimize-minimize --define process.env.NODE_ENV="production" [boolean] --progress Print compilation progress in percentage [boolean] Module options: --module-bind Bind an extension to a loader [string] --module-bind-post Bind an extension to a post loader [string] --module-bind-pre Bind an extension to a pre loader [string] Output options: --output, -o The output path and file for compilation assets --output-path The output directory as **absolute path** (required). [string] [default: The current directory] --output-filename Specifies the name of each output file on disk. You must **not** specify an absolute path here! The `output.path` option determines the location on disk the files are written to, filename is used solely for naming the individual files. [string] [default: [name].js] --output-chunk-filename The filename of non-entry chunks as relative path inside the `output.path` directory. [string] [default: filename with [id] instead of [name] or [id] prefixed] --output-source-map-filename The filename of the SourceMaps for the JavaScript files. They are inside the `output.path` directory. [string] --output-public-path The `publicPath` specifies the public URL address of the output files when referenced in a browser. [string] --output-jsonp-function The JSONP function used by webpack for async loading of chunks. [string] --output-pathinfo Include comments with information about the modules. [boolean] --output-library Expose the exports of the entry point as library [string] --output-library-target Type of library [string] [choices: "var", "assign", "this", "window", "self", "global", "commonjs", "commonjs2", "commonjs-module", "amd", "umd", "umd2", "jsonp"] Advanced options: --records-input-path Store compiler state to a json file. [string] --records-output-path Load compiler state from a json file. [string] --records-path Store/Load compiler state from/to a json file. This will result in persistent ids of modules and chunks. An absolute path is expected. `recordsPath` is used for `recordsInputPath` and `recordsOutputPath` if they left undefined.[string] --define Define any free var in the bundle [string] --target Environment to build for [string] --cache Cache generated modules and chunks to improve performance for multiple incremental builds. [boolean] [default: It's enabled by default when watching] --watch-stdin, --stdin Stop watching when stdin stream has ended [boolean] --watch-aggregate-timeout Delay the rebuilt after the first change. Value is a time in ms. [number] --watch-poll Enable polling mode for watching [string] --hot Enables Hot Module Replacement [boolean] --prefetch Prefetch this request (Example: --prefetch ./file.js) [string] --provide Provide these modules as free vars in all modules (Example: --provide jQuery=jquery) [string] --labeled-modules Enables labeled modules [boolean] --plugin Load this plugin [string] --bail Report the first error as a hard error instead of tolerating it. [boolean] [default: null] --profile Capture timing information for each module. [boolean] [default: null] Resolving options: --resolve-alias Redirect module requests [string] --resolve-extensions Redirect module requests [array] --resolve-loader-alias Setup a loader alias for resolving [string] Optimizing options: --optimize-max-chunks Try to keep the chunk count below a limit --optimize-min-chunk-size Minimal size for the created chunk --optimize-minimize Enable minimizing the output. Uses optimization.minimizer. [boolean] Stats options: --color, --colors Enables/Disables colors on the console [boolean] [default: (supports-color)] --sort-modules-by Sorts the modules list by property in module [string] --sort-chunks-by Sorts the chunks list by property in chunk [string] --sort-assets-by Sorts the assets list by property in asset [string] --hide-modules Hides info about modules [boolean] --display-exclude Exclude modules in the output [string] --display-modules Display even excluded modules in the output [boolean] --display-max-modules Sets the maximum number of visible modules in output [number] --display-chunks Display chunks in the output [boolean] --display-entrypoints Display entry points in the output [boolean] --display-origins Display origins of chunks in the output [boolean] --display-cached Display also cached modules in the output [boolean] --display-cached-assets Display also cached assets in the output [boolean] --display-reasons Display reasons about module inclusion in the output [boolean] --display-depth Display distance from entry point for each module [boolean] --display-used-exports Display information about used exports in modules (Tree Shaking) [boolean] --display-provided-exports Display information about exports provided from modules [boolean] --display-optimization-bailout Display information about why optimization bailed out for modules [boolean] --display-error-details Display details about errors [boolean] --display Select display preset [string] [choices: "", "verbose", "detailed", "normal", "minimal", "errors-only", "none"] --verbose Show more details [boolean] --info-verbosity Controls the output of lifecycle messaging e.g. Started watching files... [string] [choices: "none", "info", "verbose"] [default: "info"] --build-delimiter Display custom text after build output[string] Options: --help, -h Show help [boolean] --version, -v Show version number [boolean] --silent Prevent output from being displayed in stdout [boolean] --json, -j Prints the result as JSON. [boolean]
要安裝 Webpack 到本項目,可按照你的須要選擇如下任意命令運行:
# npm i -D 是 npm install --save-dev 的簡寫,是指安裝模塊並保存到 package.json 的 devDependencies # 安裝最新穩定版 npm i -D webpack # 安裝指定版本 npm i -D webpack@<version> # 安裝最新體驗版本 npm i -D webpack@beta
建立一個空項目或一個空目錄,不必定須要使用IDE,這裏我使用WebStorm
npm init -y (-y直接跳過提問階段)
name - 包名. version - 包的版本號。 description - 包的描述。 homepage - 包的官網URL。 author - 包的做者,它的值是你在https://npmjs.org網站的有效帳戶名,遵循「帳戶名<郵件>」的規則,例如:zhangsan <zhangsan@163.com>。 contributors - 包的其餘貢獻者。 dependencies / devDependencies - 生產/開發環境依賴包列表。它們將會被安裝在 node_module 目錄下。 repository - 包代碼的Repo信息,包括type和URL,type能夠是git或svn,URL則是包的Repo地址。 main - main 字段指定了程序的主入口文件,require('moduleName') 就會加載這個文件。這個字段的默認值是模塊根目錄下面的 index.js。 keywords - 關鍵字
webpack4須要安裝webpack-cli:
npm i webpack webpack-cli --save-dev
src/bar.js
//定義模塊 //部分依賴lodash中的join方法 import {join} from 'lodash' //導出一個默認模塊 export default function bar() { function component() { //建立DOM元素 var element=document.createElement("h2"); //使用join鏈接數組將結果寫入元素的html中 element.innerHTML=join(['Hello','Webpack','!'],' '); return element; } //在body中添加子元素 document.body.appendChild(component()); }
實現使用lodash的join 鏈接字符串,在網頁中輸出字符串
依賴lodash、npm安裝lodash,在bar.js中import lodash的join方法,輸出text
npm i lodash --save
src/index.js
//入口文件 //導入自定義好的模塊 import bar from './bar'; //調用 bar();
建立配置文件webpack.config.js
//webpack配置文件 //依賴node中的path模塊 const path=require('path'); //定義一個默認模塊對象 module.exports={ //指定入口文件的位置 entry:"./src/index.js", //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path:path.resolve(__dirname,'dist'), //文件 filename: "bundle.js" } };
path.resolve獲取文件的路徑,_dirname爲當前模塊的絕對路徑,詳細解釋以下:
path.resolve() //做用:path.resolve() 該方法將一些的 路徑/路徑段 解析爲絕對路徑。 //語法:path.resolve( [from…],to ) //說明:將參數to位置的字符解析到一個絕對路徑裏,[from … ]爲選填項,路徑源; 用法: var path = require("path") //引入node的path模塊 path.resolve('/foo/bar', './baz') // returns '/foo/bar/baz' path.resolve('/foo/bar', 'baz') // returns '/foo/bar/baz' path.resolve('/foo/bar', '/baz') // returns '/baz' path.resolve('/foo/bar', '../baz') // returns '/foo/baz' path.resolve('home','/foo/bar', '../baz') // returns '/foo/baz' path.resolve('home','./foo/bar', '../baz') // returns '/home/foo/baz' path.resolve('home','foo/bar', '../baz') // returns '/home/foo/baz' //總結:從後向前,若字符以 / 開頭,不會拼接到前面的路徑;若以 ../ 開頭,拼接前面的路徑,且不含最後一節路徑;若以 ./ 開頭 或者沒有符號 則拼接前面路徑; //另:path.resolve老是返回一個以相對於當前的工做目錄(working directory)的絕對路徑。
index.html
webpack建立dist文件在dist中生成打包文件,而後再index.html中引用index.js文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Hello WebPack</title> </head> <body> <h2>Hello WebPack</h2> <script src="dist/bundle.js"></script> </body> </html>
能夠指定配置文件
webpack --config webpack.config.js
也可使用默認的配置文件
webpack
打包的結果:
!function(n){var t={};function r(e){if(t[e])return t[e].exports;var u=t[e]={i:e,l:!1,exports:{}};return n[e].call(u.exports,u,u.exports,r),u.l=!0,u.exports}r.m=n,r.c=t,r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:e})},r.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},r.t=function(n,t){if(1&t&&(n=r(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var e=Object.create(null);if(r.r(e),Object.defineProperty(e,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var u in n)r.d(e,u,function(t){return n[t]}.bind(null,u));return e},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},r.p="",r(r.s=3)}([function(n,t,r){(function(n,e){var u;
bundle.js文件:
本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。
從 webpack v4.0.0 開始,能夠不用引入一個配置文件。然而,webpack 仍然仍是高度可配置的。在開始前你須要先理解幾個核心概念:
在Webpack裏一切皆模塊,一個模塊對應着一個文件。Webpack 會從配置的Entry開始遞歸找出全部依賴的模塊。
webpack把一切都視爲模塊,無論是 CSS、JS、Image 仍是 HTML 均可以互相引用。Node.js 從最一開始就支持模塊化編程。然而,在 web,模塊化的支持正緩慢到來。在 web 存在多種支持 JavaScript 模塊化的工具,這些工具各有優點和限制。webpack 基於從這些系統得到的經驗教訓,並將模塊的概念應用於項目中的任何文件。
什麼是 webpack 模塊
對比 Node.js 模塊,webpack 模塊可以以各類方式表達它們的依賴關係,幾個例子以下:
支持的模塊類型
webpack 經過 loader 能夠支持各類語言和預處理器編寫模塊。loader 描述了 webpack 如何處理 非 JavaScript(non-JavaScript) _模塊_,而且在 bundle 中引入這些依賴。 webpack 社區已經爲各類流行語言和語言處理器構建了 loader,包括:
入口,Webpack 執行構建的第一步將從 Entry 開始,可抽象成輸入。
入口起點(entry point)指示 webpack 應該使用哪一個模塊,來做爲構建其內部依賴圖的開始。進入入口起點後,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的。
每一個依賴項隨即被處理,最後輸出到稱之爲 bundles 的文件中,咱們將在下一章節詳細討論這個過程。
能夠經過在 webpack 配置中配置 entry 屬性,來指定一個入口起點(或多個入口起點)。默認值爲 ./src。
接下來咱們看一個 entry 配置的最簡單例子:
webpack.config.js module.exports = { entry: './path/to/my/entry/file.js' };
根據應用程序的特定需求,能夠以多種方式配置 entry 屬性。
多入口與多出口:
{ entry: { app: './src/app.js', search: './src/search.js' }, output: { filename: '[name].js', path: __dirname + '/dist' } } // 寫入到硬盤:./dist/app.js, ./dist/search.js
經常使用的佔位:
輸出結果,在 Webpack 通過一系列處理並得出最終想要的代碼後輸出結果。
output 屬性告訴 webpack 在哪裏輸出它所建立的 bundles,以及如何命名這些文件,默認值爲 ./dist。基本上,整個應用程序結構,都會被編譯到你指定的輸出路徑的文件夾中。你能夠經過在配置中指定一個 output 字段,來配置這些處理過程:
webpack.config.js 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 模塊是什麼,它是一個 Node.js 核心模塊,用於操做文件路徑。
示例:
模塊轉換器,用於把模塊原內容按照需求轉換成新內容。
loader 讓 webpack 可以去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 能夠將全部類型的文件轉換爲 webpack 可以處理的有效模塊,而後你就能夠利用 webpack 的打包能力,對它們進行處理。
本質上,webpack loader 將全部類型的文件,轉換爲應用程序的依賴圖(和最終的 bundle)能夠直接引用的模塊。
注意,loader 可以 import 導入任何類型的模塊(例如 .css 文件),這是 webpack 特有的功能,其餘打包程序或任務執行器的可能並不支持。咱們認爲這種語言擴展是有很必要的,由於這可使開發人員建立出更準確的依賴關係圖。
在更高層面,在 webpack 的配置中 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 被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。插件接口功能極其強大,能夠用來處理各類各樣的任務。
想要使用一個插件,你只須要 require() 它,而後把它添加到 plugins 數組中。多數插件能夠經過選項(option)自定義。你也能夠在一個配置文件中由於不一樣目的而屢次使用同一個插件,這時須要經過使用 new 操做符來建立它的一個實例。
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;
經過選擇 development 或 production 之中的一個,來設置 mode 參數,你能夠啓用相應模式下的 webpack 內置的優化
module.exports = { mode: 'production' };
webpack4容許咱們指定編譯使用開發模式仍是生產模式,這由mode這個配置來控制,value爲枚舉值:development/production,分別對應開發模式和生產模式(這個配置能夠做爲命令行的配置參數也能夠做爲配置文件中的一個配置項,默認值是production,即生產模式)。
源碼仍是不支持調試(都用eval函數包住),指定編譯時的source-map生成方式,默認值是eval,能夠解決問題。
一個 Chunk 由多個模塊組合而成,用於代碼合併與分割。
Webpack 啓動後會從 Entry 裏配置的 Module 開始遞歸解析 Entry 依賴的全部 Module。 每找到一個 Module, 就會根據配置的 Loader 去找出對應的轉換規則,對 Module 進行轉換後,再解析出當前 Module 依賴的 Module。 這些模塊會以 Entry 爲單位進行分組,一個 Entry 和其全部依賴的 Module 被分到一個組也就是一個 Chunk。最後 Webpack 會把全部 Chunk 轉換成文件輸出。 在整個流程中 Webpack 會在恰當的時機執行 Plugin 裏定義的邏輯。
Webpack從入口(entry)開始工做,一般這些是JavaScript模塊,其中webpack開始其遍歷過程。在此過程當中,webpack會根據加載器配置評估入口(entry)匹配,這些配置告訴webpack如何轉換每一個匹配。
入口(entry)自己就是一個模塊。當webpack遇到一個入口時,webpack會嘗試使用入口的resolve配置將入口與文件系統匹配。除了node_modules以外,咱們還能夠告訴webpack對特定目錄執行查找。也能夠調整webpack與文件擴展名匹配的方式,而且能夠爲目錄定義特定的別名。該耗竭與包章涵蓋了更詳細的這些想法。
若是解析經過失敗,webpack會引起運行時錯誤。若是webpack設法正確解析文件,webpack將根據加載器定義對匹配的文件執行處理。每一個加載器對模塊內容應用特定的轉換。
能夠經過多種方式配置加載程序與已解析文件匹配的方式,包括文件類型和文件系統中的位置。Webpack的靈活性甚至容許咱們根據文件導入項目的位置對文件應用特定的轉換。
對webpack的加載器執行相同的解析過程。Webpack容許咱們在肯定應使用哪一個加載器時應用相似的邏輯。因爲這個緣由,裝載程序已經解析了本身的配置。若是webpack沒法執行加載程序查找,則會引起運行時錯誤。
在實際應用中你可能會遇到各類奇怪複雜的場景,不知道從哪開始。 根據以上總結,你會對 Webpack 有一個總體的認識,這能讓你在之後使用 Webpack 的過程當中快速知道應該經過配置什麼去完成你想要的功能,而不是無從下手。
下圖能夠簡易的描述出webpack打包過程,該過程主要分爲三個階段:module構建、trunk構建和產出三個階段:
loader 用於對模塊的源代碼進行轉換。loader 可使你在 import 或"加載"模塊時預處理文件。所以,loader 相似於其餘構建工具中「任務(task)」,並提供了處理前端構建步驟的強大方法。loader 能夠將文件從不一樣的語言(如 TypeScript)轉換爲 JavaScript,或將內聯圖像轉換爲 data URL。loader 甚至容許你直接在 JavaScript 模塊中 import CSS文件!
loader 是對應用程序中資源文件進行轉換。它們是(運行在 Node.js 中的)函數,能夠將資源文件做爲參數的來源,而後返回新的資源文件。
loader 支持鏈式傳遞。可以對資源使用流水線(pipeline)。一組鏈式的 loader 將按照相反的順序執行。loader 鏈中的第一個 loader 返回值給下一個 loader。在最後一個 loader,返回 webpack 所預期的 JavaScript。
除了使用 package.json 常見的 main 屬性,還能夠將普通的 npm 模塊導出爲 loader,作法是在 package.json 裏定義一個 loader 字段。
插件(plugin)能夠爲 loader 帶來更多特性。
loader 可以產生額外的任意文件。
loader 經過(loader)預處理函數,爲 JavaScript 生態系統提供了更多能力。 用戶如今能夠更加靈活地引入細粒度邏輯,例如壓縮、打包、語言翻譯和其餘更多。
loader 遵循標準的模塊解析。多數狀況下,loader 將從模塊路徑(一般將模塊路徑認爲是 npm install, node_modules)解析。
loader 模塊須要導出爲一個函數,而且使用 Node.js 兼容的 JavaScript 編寫。一般使用 npm 進行管理,可是也能夠將自定義 loader 做爲應用程序中的文件。按照約定,loader 一般被命名爲 xxx-loader(例如 json-loader)。
(1)、配置(推薦):在 webpack.config.js 文件中指定 loader
module.rules 容許你在 webpack 配置中指定多個 loader。 這是展現 loader 的一種簡明方式,而且有助於使代碼變得簡潔。同時讓你對各個 loader 有個全局概覽:
module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] }
Loaders須要單獨安裝而且須要在webpack.config.js中的modules關鍵字下進行配置,Loaders的配置包括如下幾方面:
test:一個用以匹配loaders所處理文件的拓展名的正則表達式(必須) loader:loader的名稱(必須) include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不須要處理的文件(文件夾)(可選) query:爲loaders提供額外的設置選項(可選)
(2)、內聯:在每一個 import 語句中顯式指定 loader
能夠在 import 語句或任何等效於 "import" 的方式中指定 loader。使用 ! 將資源中的 loader 分開。分開的每一個部分都相對於當前目錄解析。
import Styles from 'style-loader!css-loader?modules!./styles.css';
經過前置全部規則及使用 !,能夠對應覆蓋到配置中的任意 loader。
選項能夠傳遞查詢參數,例如 ?key=value&foo=bar,或者一個 JSON 對象,例如 ?{"key":"value","foo":"bar"}。
儘量使用 module.rules,由於這樣能夠減小源碼中的代碼量,而且能夠在出錯時,更快地調試和定位 loader 中的問題。
(3)、CLI:在 shell 命令中指定它們
你也能夠經過 CLI 使用 loader:
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
這會對 .jade 文件使用 jade-loader,對 .css 文件使用 style-loader 和 css-loader。
raw-loader
加載文件原始內容(utf-8)val-loader
將代碼做爲模塊執行,並將 exports 轉爲 JS 代碼url-loader
像 file loader 同樣工做,但若是文件小於限制,能夠返回 data URLfile-loader
將文件發送到輸出文件夾,並返回(相對)URLjson-loader
加載 JSON 文件(默認包含)json5-loader
加載和轉譯 JSON 5 文件cson-loader
加載和轉譯 CSON 文件script-loader
在全局上下文中執行一次 JavaScript 文件(如在 script 標籤),不須要解析babel-loader
加載 ES2015+ 代碼,而後使用 Babel 轉譯爲 ES5buble-loader
使用 Bublé 加載 ES2015+ 代碼,而且將代碼轉譯爲 ES5traceur-loader
加載 ES2015+ 代碼,而後使用 Traceur 轉譯爲 ES5ts-loader
或 awesome-typescript-loader
像 JavaScript 同樣加載 TypeScript 2.0+coffee-loader
像 JavaScript 同樣加載 CoffeeScripthtml-loader
導出 HTML 爲字符串,須要引用靜態資源pug-loader
加載 Pug 模板並返回一個函數jade-loader
加載 Jade 模板並返回一個函數markdown-loader
將 Markdown 轉譯爲 HTMLreact-markdown-loader
使用 markdown-parse parser(解析器) 將 Markdown 編譯爲 React 組件posthtml-loader
使用 PostHTML 加載並轉換 HTML 文件handlebars-loader
將 Handlebars 轉移爲 HTMLmarkup-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 文件mocha-loader
使用 mocha 測試(瀏覽器/NodeJS)eslint-loader
PreLoader,使用 ESLint 清理代碼jshint-loader
PreLoader,使用 JSHint 清理代碼jscs-loader
PreLoader,使用 JSCS 檢查代碼樣式coverjs-loader
PreLoader,使用 CoverJS 肯定測試覆蓋率vue-loader
加載和轉譯 Vue 組件polymer-loader
使用選擇預處理器(preprocessor)處理,而且 require()
相似一等模塊(first-class)的 Web 組件angular2-template-loader
加載和轉譯 Angular 組件一個能夠用於加載文件做爲字符串使用的加載器,使用UTF-8編碼。
安裝
npm i --D raw-loader
安裝結果:
用法一:
經過 webpack 配置、命令行或者內聯使用 loader。
webpack.config.js
module.exports = { module: { rules: [ { test: /\.txt$/, use: 'raw-loader' } ] } }
在你的項目中
import txt from './file.txt';
用法二:經過命令行(CLI)
webpack --module-bind 'txt=raw-loader'
用法三:在你的項目中
import txt from 'file.txt';
內聯使用
import txt from 'raw-loader!./file.txt';
示例:
webpack.config.json
//webpack配置文件 //依賴node中的path模塊 var path=require('path'); //定義一個默認模塊對象 module.exports={ //指定入口文件的位置,多入口 entry:{ index:"./src/index.js", main:"./src/main.js" }, //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path:path.resolve(__dirname,'dist'), //文件,[name]是模塊名稱,佔位 filename: "[name].bundle.js" }, module: { //模塊處理 rules: [ //處理器 { test:/\.txt$/, //當模塊的後綴爲.txt時匹配 use: "raw-loader" //模塊轉換器,能夠以對象的形式指定參數 } ] }, mode: "development" };
src/file1.txt
A loader for webpack that lets you import files as a string.
src/bar.js
//定義模塊 //部分依賴lodash中的join方法 import {join} from 'lodash'; //導入模塊,得到file1.txt中的文件內容,被raw-loader處理 import message from './file1.txt'; //導出一個默認模塊 export default function bar() { function component() { //建立DOM元素 var element=document.createElement("h2"); //使用join鏈接數組將結果寫入元素的html中 element.innerHTML=join(['Hello','Webpack','!'],' ')+"<br/>"+message; return element; } //在body中添加子元素 document.body.appendChild(component()); }
運行結果:
內聯使用模塊處理器:
webpack提供兩個工具處理樣式表,css-loader 和 style-loader,兩者處理的任務不一樣,css-loader使你可以使用相似@import 和 url(...)的方法實現 require()的功能,style-loader將全部的計算後的樣式加入頁面中,兩者組合在一塊兒使你可以把樣式表嵌入webpack打包後的JS文件中。
css-loader詳解:
https://www.npmjs.com/package/css-loader
https://www.webpackjs.com/loaders/css-loader/
style-loader詳解:
https://www.npmjs.com/package/style-loader
https://www.webpackjs.com/loaders/style-loader/
//安裝 npm i style-loader css-loader -D
const path = require("path"); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), filename: "bundle.js" }, module: { rules: [ { test:/\.css/, use:['style-loader',{ loader: 'css-loader', options: { sourceMap:true } }] } ] }, mode: "development" };
base.css
h2{ height: 40px; line-height: 40px; background: crimson; color:#fff; }
bar.js
import {join} from 'lodash'; import base from '../css/base.css'; export default function bar() { function component() { var element=document.createElement("h2"); element.innerHTML=join(['Hello','Webpack!']); return element; } document.body.appendChild(component()); }
打包:
運行:
生成代碼:
用css-loader或raw-loader 轉換成一個JS模塊或用ExtractTextPlugin插件將樣式分隔成一個單獨文件。
安裝
npm i sass-loader node-sass --D
node-sass 和 webpack 是 sass-loader 的 peerDependency,所以可以精確控制它們的版本。
示例
css/baseScss.scss
$height:50px; $color:#3366ff; h2{ background: $color; height: $height; line-height: $height; color: white; padding-left: $height/5; }
經過將 style-loader 和 css-loader 與 sass-loader 鏈式調用,能夠馬上將樣式做用在 DOM 元素。
配置webpack.config.json
//webpack配置文件 //依賴node中的path模塊 var path=require('path'); //定義一個默認模塊對象 module.exports={ //指定入口文件的位置,多入口 entry:{ index:"./src/index.js", main:"./src/main.js" }, //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path:path.resolve(__dirname,'dist'), //文件,[name]是模塊名稱,佔位 filename: "[name].bundle.js" }, module: { //模塊處理 rules: [ //處理器 { test:/\.txt$/, //當模塊的後綴爲.txt時匹配 use: "raw-loader" //模塊轉換器,能夠以對象的形式指定參數 }, { test:/\.css$/, //匹配全部css模塊 //use表示要使用哪一個loader,它的值是個數組,loader的使用順序是從後往前 use: ["style-loader",{ loader: "css-loader", //轉換器名稱 options: { //配置選項 modules:true, //模塊化 sourceMap:true //是否生成調試文件 } }] //使用多個模塊轉換器 }, { test: /\.scss$/, use: [{ loader: "style-loader" // 將 JS 字符串生成爲 style 節點 }, { loader: "css-loader" // 將 CSS 轉化成 CommonJS 模塊 }, { loader: "sass-loader" // 將 Scss 編譯成 CSS }] } ] }, mode: "development" };
導入scss做爲模塊
//定義模塊 //部分依賴lodash中的join方法 import {join} from 'lodash'; //導入模塊,得到file1.txt中的文件內容,被raw-loader處理 import message from './file1.txt'; //導入樣式文件 //import '../css/baseCss.css' //導入預處理樣式文件 import '../css/baseScss.scss' //導出一個默認模塊 export default function bar() { function component() { //建立DOM元素 var element=document.createElement("h2"); //使用join鏈接數組將結果寫入元素的html中 element.innerHTML=join(['Hello','Webpack','!'],' ')+"<br/>"+message; return element; } //在body中添加子元素 document.body.appendChild(component()); }
打包後運行結果:
一般,生產環境下比較推薦的作法是,使用 ExtractTextPlugin 將樣式表抽離成專門的單獨文件。這樣,樣式表將再也不依賴於 JavaScript:
const ExtractTextPlugin = require("extract-text-webpack-plugin"); const extractSass = new ExtractTextPlugin({ filename: "[name].[contenthash].css", disable: process.env.NODE_ENV === "development" }); module.exports = { ... module : { rules: [{ test: /\.scss$/, use: extractSass.extract({ use: [{ loader: "css-loader" }, { loader: "sass-loader" }], // 在開發環境使用 style-loader fallback: "style-loader" }) }] } , plugins: [ extractSass ] } ;
Webpack 容許你在js文件中require圖片 , 經過 url-loader和file-loader來預處理圖片文件,將圖片轉換成base64編碼。
安裝
npm install --save-dev url-loader file-loader
用法
url-loader 功能相似於 file-loader,可是在文件大小(單位 byte)低於指定的限制時,能夠返回一個 DataURL。
import img from './image.png'
配置
webpack.config.js module.exports = { module: { rules: [ { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ] } ] } }
示例
webpack.config.js
//webpack配置文件 //依賴node中的path模塊 var path=require('path'); //定義一個默認模塊對象 module.exports={ entry:{app01:"./src/app01.js"}, //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path:path.resolve(__dirname,'dist'), //文件,[name]是模塊名稱,佔位 filename: "[name].bundle.js" }, module: { rules: [ { //如是文件名是gif,jpg,jpeg,bmp圖片則匹配,不分大小寫 test:/\.(gif|jpe?g|png|bmp)/i, use: { loader: "url-loader", options: { //若是圖片的大小小於1024byte(B)時轉換成dataUrl,base64編碼 limit:1024, fallback:"responsive-loader" } } } ] } };
src/app01.js
//導入大圖片 404byte import srcBig from '../img/big.jpg'; //導入小圖片 100Kbyte import srcSma from '../img/small.gif'; console.log(srcBig); console.log(srcSma) alert("Hello App01!"); //建立大圖片DOM var img1=document.createElement("img"); //指定url img1.src=srcBig; //添加到文檔中 document.body.appendChild(img1); //建立小圖片DOM var img2=document.createElement("img"); //指定url img2.src=srcSma; //添加到文檔中 document.body.appendChild(img2);
運行結果:
Plugin 是用來擴展 Webpack 功能的,經過在構建流程裏注入鉤子實現,它給 Webpack 帶來了很大的靈活性。
插件是 webpack 的支柱功能。webpack 自身也是構建於,你在 webpack 配置中用到的相同的插件系統之上!插件目的在於解決 loader 沒法實現的其餘事。
webpack 插件是一個具備 apply 屬性的 JavaScript 對象。apply 屬性會被 webpack compiler 調用,而且 compiler 對象可在整個編譯生命週期訪問。
ConsoleLogOnBuildWebpackPlugin.js const pluginName = 'ConsoleLogOnBuildWebpackPlugin'; class ConsoleLogOnBuildWebpackPlugin { apply(compiler) { compiler.hooks.run.tap(pluginName, compilation => { console.log("webpack 構建過程開始!"); }); } }
compiler hook 的 tap 方法的第一個參數,應該是駝峯式命名的插件名稱。建議爲此使用一個常量,以便它能夠在全部 hook 中複用。
因爲插件能夠帶參數/選項,你必須在 webpack 配置中,向 plugins 屬性傳入 new 實例。
根據你的 webpack 用法,這裏有多種方式使用插件。
webpack.config.js const HtmlWebpackPlugin = require('html-webpack-plugin'); //經過 npm 安裝 const webpack = require('webpack'); //訪問內置的插件 const path = require('path'); const config = { entry: './path/to/my/entry/file.js', output: { filename: 'my-first-webpack.bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.(js|jsx)$/, use: 'babel-loader' } ] }, plugins: [ new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ] }; module.exports = config;
該個插件的做用是用來自動生成html頁面,既能夠生成單個頁面又能夠生成多個頁面,而且在生成前能夠給它一些的配置參數,它會按照你想要的生成方式去生成頁面。
第一步:安裝
npm i html-webpack-plugin -D
第二步:在webpack.config.js裏引入模塊
const HtmlWebpackPlugin=require('html-webpack-plugin');
第三步:在webpack.config.js中的plugins對象裏new一個實例
plugins:[ new HtmlWebpackPlugin({參數}) ]
結果
const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: 'index.js', output: { path: __dirname + '/dist', filename: 'index_bundle.js' }, plugins: [ new HtmlWebpackPlugin() ] }
參數:
title
生成頁面的titile
元素
filename
生成的html文件的文件名。默認index.html
,能夠直接配置帶有子目錄
//webpack.config.js ... plugins: [ new HtmlWebpackPlugin({ ... filename: 'index1.html'//可帶子目錄'html/index1.html' }) ]
template
模版文件路徑
templateParameters
{Boolean|Object|Function}
容許覆蓋模板中使用的參數
//webpack.config.js ... plugins: [ new HtmlWebpackPlugin({ ... templateParameters: { title: 'xxxx', favicon: './favicon/index.ico', } }) ]
inject
插入的script
插入的位置,四個可選值:true
: 默認值,script
標籤位於html
文件的body
底部body
: 同true
head
: script
標籤位於html
文件的head
標籤內false
: 不插入生成的js
文件,只是生成的html
文件
favicon
爲生成的html
文件生成一個favicon
,屬性值是路徑
minify
對html
文件進行壓縮。屬性值是false
或者壓縮選項值。默認false
不對html
文件進行壓縮。html-webpack-plugin
中集成的html-minifier
,生成模板文件壓縮配置,有不少配置項,這些配置項就是minify
的壓縮選項值。
hash
給生成的js
文件尾部添加一個hash
值。這個hash
值是本次webpack
編譯的hash
值。默認false
;
//webpack.config.js ... plugins: [ new HtmlWebpackPlugin({ ... hash: true }) ] //html <script type="text/javascript" src="bundle.js?59a5ed17040d94df87fe"> //59a5ed17040d94df87fe是本次webpack編譯的hash值
cache
Boolean
類型。只在文件被修改的時候才生成一個新文件。默認值true
showErrors
Boolean
類型。錯誤信息是否寫入html
文件。默認true
chunks
在html
文件中引用哪些js
文件,用於多入口文件時。不指定chunks時,全部文件都引用
//webpack.config.js entry: { index1: path.resolve(__dirname, './index1.js'), index2: path.resolve(__dirname, './index2.js'), index3: path.resolve(__dirname, './index3.js') } ... plugins: [ new HtmlWebpackPlugin({ ... chunks: [index1, index2]//html文件中只引入index1.js, index2.js }) ]
excludeChunks
與chunks相反,html
文件不引用哪些js
文件
//webpack.config.js entry: { index1: path.resolve(__dirname, './index1.js'), index2: path.resolve(__dirname, './index2.js'), index3: path.resolve(__dirname, './index3.js') } ... plugins: [ new HtmlWebpackPlugin({ ... excludeChunks: [index3.js]//html文件中不引入index3.js }) ]
chunksSortMode
控制script
標籤的引用順序。默認五個選項:none
: 無序auto
: 默認值, 按插件內置的排序方式dependency
: 根據不一樣文件的依賴關係排序manual
: chunks按引入的順序排序, 即屬性chunks的順序{Function}
: 指定具體的排序規則
xhtml
Boolean
類型,默認false
, true
時以兼容xhtml
的模式引用文件
示例:
plugins:[ new HtmlWebpackPlugin({ title:'Hello app', /*這個值對應html裏的title*/ template:'./src/template.html', //模板文件地址 filename:'test1.html', //文件名,默認爲index.html(路徑相對於output.path的值) inject:true, //script標籤的位置,true/body爲在</body>標籤前,head爲在<head>裏,false表示頁面不引入js文件 hash:true, //是否爲引入的js文件添加hash值 chunks:['one'], //頁面裏要引入的js文件,值對應的是entry裏的key。省略參數會把entry裏全部文件都引入 //excludeChunks:['one'],//頁面裏不能引入的js文件,與chunks恰好相反 minify:{ //html-webpack-plugin內部集成了html-minifier collapseWhitespace:true, //壓縮空格 removeAttributeQuotes:true, //移除引號 removeComments:true, //移除註釋 }, }), //生成兩個文件,分別引入兩個js文件(如今是一個文件裏引入了兩個js) new HtmlWebpackPlugin({ title:'kaivon', template:'./src/template.html', hash:true, filename:'test2.html', chunks:['two'] }) ]
示例1:
webpack.config03.js配置文件
//webpack配置文件 //導入用於生成html的插件 const HtmlWebpackPlugin=require("html-webpack-plugin"); //依賴node中的path模塊 var path=require('path'); //定義一個默認模塊對象 module.exports={ entry:{app01:"./src/app03.js"}, //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path:path.resolve(__dirname,'dist'), //文件,[name]是模塊名稱,佔位 filename: "[hash:8].bundle.js" }, module: { }, plugins: [ //建立一個插件對象,並指定參數 new HtmlWebpackPlugin({ //指定生成的文件路徑與名稱 filename:"../app03.html", //標題 title:"Hello App03!" }) ] };
arc/app03.js
alert("Hello App03!");
打包結果:
運行:
示例2:
webpack.config03.js配置文件
//webpack配置文件 //導入用於生成html的插件 const HtmlWebpackPlugin=require("html-webpack-plugin"); //依賴node中的path模塊 var path=require('path'); //定義一個默認模塊對象 module.exports={ entry:{app01:"./src/app03.js"}, //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path:path.resolve(__dirname,'dist'), //文件,[name]是模塊名稱,佔位 filename: "[hash:8].bundle.js" }, module: { }, plugins: [ //建立一個插件對象,並指定參數 new HtmlWebpackPlugin({ //指定生成的文件路徑與名稱 filename:"../app03.html", //標題 title:"Hello App03!", //指定模板 template:"./templates/tmpl03.html", //模板參數,容許覆蓋templates中的參數 templateParameters:{ content:"Hello templateParameters!", //重寫title title:"Hello App03 title!", key:"value" }, minify:{ removeComments:true, //移除註釋 collapseWhitespace:true, //摺疊空格 //更新請參數https://github.com/kangax/html-minifier#options-quick-reference } }) ] };
/templates/tmpl03.html 模板文件
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <title><%=title %></title> </head> <body> <!--這是一個標題--> <h2> <%=content%> </h2> </body> </html>
生成結果:
將CSS提取爲獨立的文件的插件,對每一個包含css的js文件都會建立一個CSS文件,支持按需加載css和sourceMap
默認狀況下css是被js注入的一段style,以下所示:
只能用在webpack4中,對比另外一個插件 extract-text-webpack-plugin特色:
目前缺失功能,HMR(熱模塊替換)。
全稱是Hot Module ReplaceMent(HMR),理解成熱模塊替換或者模塊熱替換均可以吧,和.net中的熱插拔一個意思,就是在運行中對程序的模塊進行更新。這個功能主要是用於開發過程當中,對生產環境沒有任何幫助(這一點區別.net熱插拔)。效果上就是界面的無刷新更新。
HMR基於WDS,style-loader能夠經過它來實現無刷新更新樣式。可是對於JavaScript模塊就須要作一點額外的處理,怎麼處理繼續往下看。由於HMR是用於開發環境的,因此咱們修改下配置,作兩份準備。一個用於生產,一個用於開發。
安裝:
npm install --save-dev mini-css-extract-plugin
使用:
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { plugins: [ new MiniCssExtractPlugin({ // 相似 webpackOptions.output裏面的配置 能夠忽略 filename: '[name].css', chunkFilename: '[id].css', }), ], module: { rules: [ { test: /\.css$/, use: [ { loader: MiniCssExtractPlugin.loader, options: { // 這裏能夠指定一個 publicPath // 默認使用 webpackOptions.output中的publicPath publicPath: '../' }, }, 'css-loader', ], } ] } }
高級配置:
這個插件應該只用在 production 配置中,而且在loaders鏈中不使用 style-loader, 特別是在開發中使用HMR,由於這個插件暫時不支持HMR
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const devMode = process.env.NODE_ENV !== 'production'; module.exports = { plugins: [ new MiniCssExtractPlugin({ filename: devMode ? '[name].css' : '[name].[hash].css', chunkFilename: devMode ? '[id].css' : '[id].[hash].css', }) ], module: { rules: [ { test: /\.(sa|sc|c)ss$/, use: [ devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader', ], } ] } }
示例:
webpack.config03.js
//webpack配置文件 //導入用於生成html的插件 const HtmlWebpackPlugin=require("html-webpack-plugin"); //導入用於提取css的插件 const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //依賴node中的path模塊 var path=require('path'); //定義一個默認模塊對象 module.exports={ entry:{app01:"./src/app03.js"}, //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path:path.resolve(__dirname,'dist'), //文件,[name]是模塊名稱,佔位 filename: "[hash:8].bundle.js" }, module: { rules: [ { test: /\.scss$/, use: [{ loader:MiniCssExtractPlugin.loader //提取css並link }, { loader: "css-loader" // 將 CSS 轉化成 CommonJS 模塊 }, { loader: "sass-loader" // 將 Scss 編譯成 CSS }] } ] }, plugins: [ //建立一個插件對象,並指定參數 new HtmlWebpackPlugin({ //指定生成的文件路徑與名稱 filename:"../app03.html", //標題 title:"Hello App03!", //指定模板 template:"./templates/tmpl03.html", //模板參數,容許覆蓋templates中的參數 templateParameters:{ content:"Hello templateParameters!", //重寫title title:"Hello App03 title!", key:"value" }, minify:{ removeComments:true, //移除註釋 collapseWhitespace:true, //摺疊空格 //更新請參數https://github.com/kangax/html-minifier#options-quick-reference } }), //建立一個用於提取css的插件對象 new MiniCssExtractPlugin({ filename:"[name]_[hash:10].css", chunkFilename:"[id]" }) ] };
src/app03.js
import '../css/baseScss.scss';
alert("Hello App03!");
打包生成的結果
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <title>Hello App03 title!</title> <link href="dist/app01_1b7c11aa92.css" rel="stylesheet"> </head> <body><h2>Hello templateParameters!</h2> <script type="text/javascript" src="dist/1b7c11aa.bundle.js"></script> </body> </html>
運行結果:
在用HtmlWebpackPlugin的時候時須要把dist目錄刪掉再去看生成的文件,clean-webpack-plugin這個插件就能夠作這件事情
第一步:安裝
npm i clean-webpack-plugin --save-dev
第二步:在webpack.config.js裏引入模塊
const CleanWebpackPlugin=require('clean-webpack-plugin');
第三步:在plugins的最前面建立清理對象
plugins:[ new CleanWebpackPlugin(['./dist']), //這個必定要放在最上面,做用是先刪除dist目錄再建立新的dist目錄。裏面的參數爲要刪除的目錄,放在一個數組裏面 ... ]
在文件夾裏打開dist所在的目錄,並在終端裏再次執行命令webpack後,會看到dist目錄先被刪除後又被建立。
關於clean-webpack-plugin插件的全部配置參數請參考:https://www.npmjs.com/package/clean-webpack-plugin
該插件有兩個參數:
Paths ( 必須)
An [array] of string paths to clean
[ 'dist', // removes 'dist' folder 'build/*.*', // removes all files in 'build' folder 'web/*.js' // removes all JavaScript files in 'web' folder ]
{ // Absolute path to your webpack root folder (paths appended to this) // Default: root of your package root: __dirname, // Write logs to console. verbose: true, // Use boolean "true" to test/emulate delete. (will not remove files). // Default: false - remove files dry: false, // If true, remove files on recompile. // Default: false watch: false, // Instead of removing whole path recursively, // remove all path's content with exclusion of provided immediate children. // Good for not removing shared files from build directories. exclude: [ 'files', 'to', 'ignore' ], // allow the plugin to clean folders outside of the webpack root. // Default: false - don't allow clean folder outside of the webpack root allowExternal: false // perform clean just before files are emitted to the output dir // Default: false beforeEmit: false }
示例:
const CleanWebpackPlugin = require('clean-webpack-plugin'); //installed via npm const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm const webpack = require('webpack'); //to access built-in plugins const path = require('path'); // the path(s) that should be cleaned let pathsToClean = [ 'dist', 'build' ] // the clean options to use let cleanOptions = { root: '/full/webpack/root/path', exclude: ['shared.js'], verbose: true, dry: false } // sample WebPack config const webpackConfig = { entry: './path/to/my/entry/file.js', output: { filename: 'my-first-webpack.bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.(js|jsx)$/, loader: 'babel-loader' } ] }, plugins: [ new CleanWebpackPlugin(pathsToClean, cleanOptions), new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ] }
示例:
webpack.config03.js
//webpack配置文件 //導入用於理清目錄的插件 const CleanWebpackPlugin=require('clean-webpack-plugin'); //導入用於生成html的插件 const HtmlWebpackPlugin=require("html-webpack-plugin"); //導入用於提取css的插件 const MiniCssExtractPlugin = require('mini-css-extract-plugin'); //依賴node中的path模塊 var path=require('path'); //定義一個默認模塊對象 module.exports={ entry:{app01:"./src/app03.js"}, //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path:path.resolve(__dirname,'dist'), //文件,[name]是模塊名稱,佔位 filename: "[hash:8].bundle.js" }, module: { rules: [ { test: /\.scss$/, use: [{ loader:MiniCssExtractPlugin.loader //提取css並link }, { loader: "css-loader" // 將 CSS 轉化成 CommonJS 模塊 }, { loader: "sass-loader" // 將 Scss 編譯成 CSS }] } ] }, plugins: [ //建立一個清理插件,參數一爲目標,如路徑,參數二爲選項 new CleanWebpackPlugin(['dist'],{dry:false}), //建立一個插件對象,並指定參數 new HtmlWebpackPlugin({ //指定生成的文件路徑與名稱 filename:"../app03.html", //標題 title:"Hello App03!", //指定模板 template:"./templates/tmpl03.html", //模板參數,容許覆蓋templates中的參數 templateParameters:{ content:"Hello templateParameters!", //重寫title title:"Hello App03 title!", key:"value" }, minify:{ removeComments:true, //移除註釋 collapseWhitespace:true, //摺疊空格 //更新請參數https://github.com/kangax/html-minifier#options-quick-reference } }), //建立一個用於提取css的插件對象 new MiniCssExtractPlugin({ filename:"[name]_[hash:10].css", chunkFilename:"[id]" }) ] };
運行前:
運行後:
require
語句在尋找文件時的默認行爲。webpack-dev-server就是一個基於Node.js和webpack的一個簡易服務器。它在服務器端使用webpack-dev-middleware進行webpack構建打包;並在客戶端注入一份runtime,用於接受服務器端的構建打包後信息。
在實際開發中咱們可能會須要完成以下功能:
Webpack 原生支持上述第二、3點內容,再結合官方提供的開發工具 DevServer 也能夠很方便地作到第1點。 DevServer 會啓動一個 HTTP 服務器用於服務網頁請求,同時會幫助啓動 Webpack ,並接收 Webpack 發出的文件更變信號,經過 WebSocket 協議自動刷新網頁作到實時預覽。
安裝 DevServer:
npm i -D webpack-dev-server
安裝成功後在項目的根目錄下執行webpack-dev-server 命令, DevServer 服務器就啓動了,這時你會看到控制檯有一串日誌輸出:
Project is running at http://localhost:8080/
webpack output is served from /
如今就能夠直接訪問了
這意味着 DevServer 啓動的 HTTP 服務器監聽在 http://localhost:8080/ ,DevServer 啓動後會一直駐留在後臺保持運行,訪問這個網址你就能獲取項目根目錄下的 index.html。
注意:
一、此時可能會提示webpack-dev-server不是內部命令,解決辦法爲在全局再次安裝一下webpack-dev-server模塊,或者在package.json裏的scripts里加上"dev": "webpack-dev-server",而後執行命令npm run dev
二、並無經過webpack命令生成一個dist目錄,而後在瀏覽器裏輸入地址http://localhost:8080/後,頁面會正常顯示。這個緣由是devServer會將webpack構建出的文件保存到內存裏,不須要打包生成就能預覽
在webpack.config.js中能夠根據須要配置dev-server知足你更多的需求。
// webpack.config.js 配置一下 devServer devServer: { clientLogLevel: 'warning', historyApiFallback: true, hot: true, compress: true, host: 'localhost', port: 8080 }
Hot (文檔)
HMR 這個插件是真正實現熱模塊更新的
。而 devServer 裏配置了 hot: true , webpack會自動添加 HMR 插件。因此模塊熱更新最終仍是 HMR 這個插件起的做用。host (文檔)
port (文檔)
historyApiFallback (文檔)
若是爲 {...} , 看看通常裏面有什麼。
rewrites: [ { from: /^\/subpage/, to: '/views/subpage.html' }, { from: /^\/helloWorld\/.*$/, to: function() { return '/views/hello_world.html; } } ] // 從代碼能夠看出 url 匹配正則,匹配成功就到某個頁面。 // 並不建議將路由寫在這,通常 historyApiFallback: true 就好了。
.
。compress (文檔)
contentBase (文檔)
你要提供哪裏的內容給虛擬服務器用。這裏最好填 絕對路徑。
// 單目錄 contentBase: path.join(__dirname, "public") // 多目錄 contentBase: [path.join(__dirname, "public"), path.join(__dirname, "assets")]
Open (文檔)
overlay (文檔)
overlay:{ errors:true, warnings:false }
quiet (文檔)
publicPath (文檔)
url = '主機名' + 'publicPath配置的' +
'原來的url.path'
。這個其實與 output.publicPath 用法大同小異。// devServer.publicPath publicPath: "/assets/" // 本來路徑 --> 變換後的路徑 http://localhost:8080/app.js --> http://localhost:8080/assets/app.js
proxy (文檔)
proxy: { '/proxy': { target: 'http://your_api_server.com', changeOrigin: true, pathRewrite: { '^/proxy': '' } }
http://localhost:8080/proxy/user/list
。http://localhost:8080/proxy/user/list 變爲 http://your_api_server.com/proxy/user/list
。但還不是咱們要的 url 。''
,那麼 url 最終爲 http://your_api_server.com/user/list
。watchOptions (文檔)
watchOptions: { aggregateTimeout: 300, poll: 1000, ignored: /node_modules/ }
false
。var path = require("path"); var webpack = require("webpack"); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode:"development", entry:{ app:"./src/js/main.js" }, output:{ filename: "bundle.js", path:path.resolve(__dirname,"../dist"), //path.resolve是nodejs裏的方法,具體看nodejs api }, devServer:{ contentBase:false, //我這裏沒有設置contentBase,contentBase必須指向存在的bundle.js文件所在目錄, //由於這裏是開發模式,因此dist目錄並不存在,因此用false. host:'localhost', port:'8888', inline:true,//webpack官方推薦 watchOptions: { aggregateTimeout: 2000,//瀏覽器延遲多少秒更新 poll: 1000//每秒檢查一次變更 }, compress:true,//一切服務都啓用gzip 壓縮 historyApiFallback:true,//找不到頁面默認跳index.html hot:true,//啓動熱更新,必須搭配new webpack.HotModuleReplacementPlugin()插件 open:true, }, plugins: [ new webpack.HotModuleReplacementPlugin(), new HtmlWebpackPlugin({ template:"index.html", title:'index', inject: true }), // new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. // new webpack.NoEmitOnErrorsPlugin() ] }
示例:
配置文件:
//webpack配置文件 //依賴node中的path模塊 var path = require('path'); //定義一個默認模塊對象 module.exports = { //指定入口文件的位置,多入口 entry: { index: "./src/index.js", main: "./src/main.js" }, //設置輸出結果 output: { //路徑,將相對路徑轉絕對路徑 path: path.resolve(__dirname, 'dist'), //文件,[name]是模塊名稱,佔位 filename: "[name].bundle.js" }, module: { //模塊處理 rules: [ //處理器 { test: /\.txt$/, //當模塊的後綴爲.txt時匹配 use: "raw-loader" //模塊轉換器,能夠以對象的形式指定參數 }, { test: /\.css$/, //匹配全部css模塊 //use表示要使用哪一個loader,它的值是個數組,loader的使用順序是從後往前 use: ["style-loader", { loader: "css-loader", //轉換器名稱 options: { //配置選項 modules: true, //模塊化 sourceMap: true //是否生成調試文件 } }] //使用多個模塊轉換器 }, { test: /\.scss$/, use: [{ loader: "style-loader" // 將 JS 字符串生成爲 style 節點 }, { loader: "css-loader" // 將 CSS 轉化成 CommonJS 模塊 }, { loader: "sass-loader" // 將 Scss 編譯成 CSS }] } ] }, mode: "development", devServer: { //端口號 port:8889, //運行時打開瀏覽器測試效果 open:true, //主機地址 host:"192.168.4.113", //是否開啓壓縮 compress:true, //是否開啓熱模塊替換 hot:true } };
運行結果:
https://www.bilibili.com/video/av37008594/
https://git.dev.tencent.com/zhangguo5/WebPackDemo.git
(1)、建立一個項目,項目中使用ES6的模塊功能與箭頭函數,使用babel-loader轉譯成兼容IE8的前端輸出。