webpack是一個現代的JavaScript應用的靜態模塊打包工具。
涉及到兩個概念:模塊 和 打包css
經過模塊化開發完成項目後,還須要處理模塊間的各類依賴,而且將其進行整合打包。而webpack其中一個核心就是讓咱們可能進行模塊化開發,而且會幫助咱們處理模塊間的依賴關係。並且不只僅是JavaScript文件,咱們的CSS、圖片、json文件等等在webpack中均可以被當作模塊來使用。這就是webpack中模塊化的概念。html
就是將webpack中的各類資源模塊進行打包合併成一個或多個包(Bundle)。而且在打包的過程當中,還能夠對資源進行處理,好比壓縮圖片,將scss
轉成css
,將ES6
語法轉成ES5
語法,將TypeScript
轉成JavaScript
等等操做。前端
但打包的操做彷佛grunt/gulp也能夠幫助咱們完成,它們有什麼不一樣呢?vue
grunt/gulp的核心是Task
咱們能夠配置一系列的task
,而且定義task
要處理的事務(例如ES六、ts轉化,圖片壓縮,scss轉成css)。以後讓grunt/gulp
來依次執行這些task
,並且讓整個流程自動化。因此grunt/gulp也被稱爲前端自動化任務管理工具。node
來看一個gulp的task:下面的task就是將src下面的全部js文件轉成ES5的語法。而且最終輸出到dist文件夾中。webpack
const gu1p = requireC('gulp'); const babe1 = require('gu1p-babe1'); gulp.task('js',()=> gulp.src('src/*.js') .pipe(babe1({ presets: ['es2015'] })) .pipe(gulp. dest('dist')) );
何時用grunt/gulp呢?
若是你的工程模塊依賴很是簡單,甚至是沒有用到模塊化的概念。只須要進行簡單的合併、壓縮,就使用grunt/gulp便可。可是若是整個項目使用了模塊化管理,並且相互依賴很是強,咱們就可使用更增強大的webpack了。
因此,grunt/gulp和webpack有什麼不一樣呢?web
grunt/gulp
更增強調的是前端流程的自動化,模塊化不是它的核心。webpack
更增強調模塊化開發管理,而文件壓縮合並、預處理等功能,是他附帶的功能。安裝webpack首先須要安裝Node.js,Node.js自帶了軟件包管理工具npm。express
cnpm install webpack --save-dev //--save-dev是開發時依賴,項目打包後不須要繼續使用的。
在終端直接執行webpack命令,使用的全局安裝的webpack。當在package.json中定義了scripts時,其中包含了webpack命令,那麼使用的是局部webpack。npm
文件和文件夾解析:
dist文件夾:用於存放以後打包的文件
src文件夾:用於存放咱們寫的源文件
-----main.js項目的入口 文件。具體內容查看下面詳情。
index.html:瀏覽器打開展現的首頁html
package.json:經過npm init生成的,npm包管理的文件(暫時沒有用上,後面纔會用上)json
js文件的打包
webpack src/main.js dist/bundle.js
使用打包後的文件
打包後會在dist文件下,生成一個bundle.js文件。bundle.js文件,是webpack處理了項目直接文件依賴後生成的一個js文件,咱們只須要將這個js文件在index.html中引入便可
若是每次使用webpack的命令都須要寫上入口和出口做爲參數,有一種方法能夠將這兩個參數寫到配置中,在運行時,直接讀取。
建立一個webpack.config.js文件
const path = require('path') module.exports = { //入口:能夠是字符串/數組/對象,這裏咱們入口只有一個,因此寫一個字符串便可 entry:'./src/main.js' , //出口:一般是一個對象,裏面至少包含兩個重要屬性,path 和filename output:{ path: path. resolve(__dirname, 'dist'), //注意: path一般是一 個絕對路徑 filename: 'bundle.js' } }
由於一個項目每每依賴特定的webpack版本,全局的版本可能很這個項目的webpack版本不一致,導出打包出現問題。因此一般一個項目,都有本身局部的webpack。
//安裝指定本身須要的版本 cnpm install webpack@3.6.0 --save-dev //啓動webpack打包 node_modules/.bin/webpack
咱們能夠在package.json的scripts中定義本身的執行腳本。
{ "name": "meetwebpack", "version": "1.0.0", "description":"", "main": 'index.js', "scripts": { "build": "'webpack" }, "author":"", "license":"ISC", "devDependencies": { "webpack": "^3. 6. 0" } }
package.json中的scripts的腳本在執行時,會按照必定的順序尋找命令對應的位置。
首先,會尋找本地的node_modules/.bin路徑中對應的命令。若是沒有找到,會去全局的環境變量中尋找。
//執行build指令 cnpm run build
什麼是loader?
loader是webpack中一個很是核心的概念。在開發中咱們不只僅有基本的js代碼處理,咱們也須要加載css、圖片,也包括一些高級的將ES6轉成ES5代碼,將TypeScript轉成ES5代碼,將scss、less轉成css,將.jsx、.vue文件轉成js文件等等。對於webpack自己的能力來講,對於這些轉化是不支持的。此時須要給webpack擴展對應的loader。
loader使用過程:
步驟一:經過npm安裝須要使用的loader
步驟二:在webpack.config.js中的modules關鍵字下進行配置
大部分loader咱們均可以在webpack的官網中找到,而且學習對應的用法。loader 的執行順序是從下到上,從右到左。
須要用到兩個loader:css-loader 和 style-loader。css-loader
負責加載css文件;style-loader
負責將css具體樣式嵌入到文檔中。
安裝
cnpm install --save-dev css-loader style-loader
webpack.config.js中配置
const path = require('path'); module.exports = { mode: 'development', entry: { main: './src/index.js' }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module:{ rules:[ { test:/\.css$/, use:['style-loader','css-loader'], } ] }, }
由於webpack在讀取使用的loader的過程當中,是按照從右向左的順序讀取的。因此style-loader
須要放在css-loader
的前面。
須要安裝less 和 less-loader。
rules: [{ test: /\.less$/, use: [{ loader: "style-loader" // creates style nodes from JS strings }, { loader: "css-loader" // translates CSS into CommonJS }, { loader: "less-loader" // compiles Less to CSS }] }]
url-loader、file-loader
當加載的圖片, 小於limit
時, 會將圖片編譯成base64
字符串形式.
當加載的圖片, 大於limit
時, 須要使用file-loader
模塊進行加載.
修改文件名稱
當圖片大於limit時,使用file-loader
默認會將該圖片打包從新命名爲32位的hash值放到dist文件夾下。
{ test: /\.(png|jpg|gif|jpeg)$/, use: [ { loader: 'url-loader', options: { // 當加載的圖片, 小於limit時, 會將圖片編譯成base64字符串形式. // 當加載的圖片, 大於limit時, 須要使用file-loader模塊進行加載. limit: 13000, // [ext]:表示原始文件名的後綴。[name]:表示原始文件名。[hash:8]:爲了防止圖片名稱衝突,依然使用hash,可是咱們只保留8位 name: 'img/[name].[hash:8].[ext]' }, } ] },
咱們發現圖片並無顯示出來,這是由於圖片使用的路徑不正確。默認狀況下,webpack會將生成的路徑直接返回給使用者可是,咱們整個程序是打包在dist文件夾下的,因此這裏咱們須要在路徑下再添加一個dist/
。
output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js', publicPath: 'dist/' },
若是但願將ES6的語法轉成ES5,那麼就須要使用babel。而在webpack中,咱們直接使用babel對應的loader就能夠了。
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js文件
{ test: /\.js$/, // exclude: 排除 // include: 包含 exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }
plugin
是插件的意思,一般是用於對某個現有的架構進行擴展。webpack中的插件,就是對webpack現有功能的各類擴展,好比打包優化,文件壓縮等等。
loader
主要用於轉換某些類型的模塊,它是一個轉換器。plugin
是插件,它是對webpack自己的擴展,是一個擴展器。
步驟一:經過npm安裝須要使用的plugins(某些webpack已經內置的插件不須要安裝)
步驟二:在webpack.config.js中的plugins中配置插件。
BannerPlugin
,屬於webpack自帶的插件。
const path = require('path') const webpack = require('webpack') module.exports = { ... plugins: [ new webpack.BannerPlugin('最終版權歸aaa全部'), ], }
在真實發布項目時,須要將index.html文件打包到dist文件夾中,這個時候就可使用 HtmlWebpackPlugin
插件。HtmlWebpackPlugin
插件能夠爲咱們作這些事情:自動生成一個index.html文件(能夠指定模板來生成)將打包的js文件,自動經過script標籤插入到body中。
npm install html-webpack-plugin --save-dev
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { ... plugins: [ new HtmlWebpackPlugin({ template: 'index.html'//指定生成Html文件時使用的模板。 }), ], }
另外,咱們須要刪除以前在output
中添加的publicPath
屬性,不然插入的script標籤中的src可能會有問題。
CleanWebpackPlugin 會在打包以前刪除指定目錄下的內容。
npm install clean-webpack-plugin -D
webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); //注意加{} module.exports = { ... plugins:[ new HtmlWebpackPlugin({ template: 'src/index.html' }), new CleanWebpackPlugin() //不能加參數。 ], }
webpack提供了一個可選的本地開發服務器,這個本地服務器基於node.js搭建,內部使用express框架,能夠實現咱們想要的讓瀏覽器自動刷新顯示咱們修改後的結果。
npm install --save-dev webpack-dev-server@2.9.1
devserver
也是做爲webpack中的一個選項,選項自己能夠設置以下屬性:
`contentBase`:爲哪個文件夾提供本地服務,默認是根文件夾,咱們這裏要填寫./dist `port`:端口號 `inline`:頁面實時刷新 `historyApiFallback`:在SPA頁面中,依賴HTML5的history模式
devServer: { contentBase: './dist', inline: true }
能夠再配置另一個scripts:--open參數表示直接打開瀏覽器
"scripts": { "build": "webpack", "dev": "webpack-dev-server --open" },
在前面的Vue實例中,咱們定義了el屬性,用於和index.html中的#app進行綁定,讓Vue實例以後能夠管理它其中的內容。
這裏,咱們能夠將div元素中的{{message}}內容刪掉,只保留一個基本的id爲div的元素
可是若是我依然但願在其中顯示{{message}}的內容,應該怎麼處理呢?
咱們能夠再定義一個template屬性,代碼以下:
new Vue({ el: '#app', template: '<div id="app">{{message}}</div>', data: { message:'coderwhy' } })
el和template模板的關係是什麼呢?
el用於指定Vue要管理的DOM,能夠幫助解析其中的指令、事件監聽等等。
而若是Vue實例中同時指定了template,那麼template模板的內容會替換掉掛載的對應el的模板。這樣作以後咱們就不須要在之後的開發中再次操做index.html,只須要在template中寫入對應的標籤便可
稍後會將template
模板中的內容進行抽離。會分紅三部分書寫:template
、script
、style
,結構變得很是清晰。
main.js
//使用Vue進行開發 import Vue from 'vue' import App from './vue/App.vue' new Vue({ el: '#app', template: '<App/>', components: { App } })
vue-->App.vue
<template> <div> <h2 class="title">{{message}}</h2> <h2>{{name}}</h2> </div> </template> <script> export default { name: "App", data() { return { message: 'Hello Webpack', name: '張三' } }, } </script> <style scoped> .title { color: green; } </style>
安裝vue、vue-loader 和 vue-template-compiler 進行處理。
npm install vue-loader vue-template-compiler --save-dev
cnpm install vue --save
module: { rules: [ { test: /\.vue$/, use: ['vue-loader'] } ] }, //解決runtime-only版本的Vue報錯 resolve: { // alias: 別名 extensions: ['.js', '.css', '.vue'], alias: { 'vue$': 'vue/dist/vue.esm.js' } }