Webpack 學習總結
1.Webpack的特性
webpack 模塊打包機,分析你的項目結構,找到JavaScript模塊以及其他一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),將其打包為合適的格式以供瀏覽器使用。
webpack具有requireJs和browserify的功能,但仍有很多自己的新特性:
1. 對 CommonJS 、 AMD 、ES6的語法做了兼容
2. 對js、css、圖片等資源文件都支持打包
3. 串聯式模塊加載器以及插件機制,讓其具有更好的靈活性和擴展性,例如提供對CoffeeScript、ES6的支持
4. 有獨立的配置文件webpack.config.js
5. 可以將代碼切割成不同的chunk,實現按需加載,降低了初始化時間
6. 支持 SourceUrls 和 SourceMaps,易於調試
7. 具有強大的Plugin接口,大多是內部插件,使用起來比較靈活
8.webpack 使用異步 IO 並具有多級緩存。這使得 webpack 很快且在增量編譯上更加快
Webpack和Grunt, Gulp的區別:
Grunt和Gulp的工作方式是:在一個配置文件中,指明對某些文件進行類似編譯,組合,壓縮等任務的具體步驟,然後這個工具自動替你完成這些任務。(Do a series of tasks)
Webpack的工作方式是,把項目當做一個整體,通過給定一個主文件entry(index.js),Webpack 將從這個文件開始找到項目的所有依賴文件,使用loaders處理他們,最後打包為瀏覽器可識別的JavaScript文件。(從入口文件查找下載依賴) 效率更高,打包更好。
2.開始使用Webpack
webpack 可以作為全局的npm模塊安裝,也可以在當前項目中安裝。
npm install -g webpack
npm install --save-dev webpack
在終端的最基礎命令:webpack {entry file/入口文件} {destination for bundled file/存放bundle.js的地方} 只需要一個入口文件,webpack將自動識別項目所依賴的其他文件。
如果是非全局安裝,直接在命令行下執行 node_modules/.bin/webpack,就會自動讀取webpack.config.js文件中的配置,輸出打包後的文件。
在項目的package.son 文件中配置,實現快速打包:
{ "name": "webpack-sample-project", "version": "1.0.0", "description": "Sample webpack project", "scripts": { "start": "webpack" //配置的地方就是這裏啦,相當於把npm的start命令指向webpack命令 }, "author": “dd”, "license": "ISC", "devDependencies": { "webpack": "^1.13.2", } }
在項目中通過配置webpack.config.js 文件來使用Webpack, Webpack的強大功能都體現在配置文件中。下面是一個基本配置示例:
var path = require(‘path‘); module.exports = { entry: path.resolve(__dirname, ‘./src/index.js‘), //已多次提及的唯一入口文件 output: { path: path.resolve(__dirname, ‘./bundle‘), //打包後的文件存放的地方 filename: ‘bundle.js‘ //打包後輸出文件的文件名 }, module: { loaders: [ { test: /\.js?$/, loaders: [‘babel‘], exclude: /node_modules/ }, { test: /\.js$/, loader: ‘babel-loader‘, exclude: /node_modules/} ] }, resolve:{ extensions:[‘‘,‘.js‘,‘.json‘] }, }; 註:“__dirname”是node.js中的一個全局變量,它指向當前執行腳本所在的目錄。
(1)entry
entry參數定義了打包後的入口文件,可以是個字符串或數組或者是對象;如果是數組,數組中的所有文件會打包生成一個filename文件;如果是對象,可以將不同的文件構建成不同的文件。
{ entry: { page1: "./page1", //支持數組形式,將加載數組中的所有模塊,但以最後一個模塊作為輸出 page2: ["./entry1", "./entry2"] }, output: { path: "dist/js/page", publicPath: "/output/", filename: "[name].bundle.js" } }
該段代碼最終會生成一個 page1.bundle.js 和 page2.bundle.js,並存放到 ./dist/js/page 文件夾下
(2)output
output參數是個對象,定義了輸出文件的位置及名字:
output: { path: "dist/js/page", publicPath: "/output/", filename: "[name].bundle.js" }
path: 打包文件存放的絕對路徑
publicPath: 網站運行時的訪問路徑
filename:打包後的文件名
當我們在entry中定義構建多個文件時,filename可以對應的更改為[name].js用於定義不同文件構建後的名字。
(3)module
module: { //加載器配置 loaders: [ //.css 文件使用 style-loader 和 css-loader 來處理 { test: /\.css$/, loader: ‘style-loader!css-loader‘ }, //.js 文件使用 jsx-loader 來編譯處理 { test: /\.js$/, loader: ‘jsx-loader?harmony‘ }, //.scss 文件使用 style-loader、css-loader 和 sass-loader 來編譯處理 { test: /\.scss$/, loader: ‘style!css!sass?sourceMap‘}, //圖片文件使用 url-loader 來處理,小於8kb的直接轉為base64 { test: /\.(png|jpg)$/, loader: ‘url-loader?limit=8192‘} ] }
在webpack中JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,圖片等靜態文件都是模塊,不同模塊的加載是通過模塊加載器(webpack-loader)來統一管理的。loaders之間是可以串聯的,一個加載器的輸出可以作為下一個加載器的輸入,最終返回到JavaScript上。
(4)resolve
webpack在構建包的時候會按目錄的進行文件的查找,resolve屬性中的extensions數組中用於配置程序可以自行補全哪些文件後綴:
resolve: { //查找module的話從這裏開始查找 root: ‘/pomy/github/flux-example/src‘, //絕對路徑 //自動擴展文件後綴名,意味著我們require模塊可以省略不寫後綴名 extensions: [‘‘, ‘.js‘, ‘.json‘, ‘.scss‘], //模塊別名定義,方便後續直接引用別名,無須多寫長長的地址 alias: { AppStore : ‘js/stores/AppStores.js‘,//後續直接 require(‘AppStore‘) 即可 ActionType : ‘js/actions/ActionType.js‘, AppAction : ‘js/actions/AppAction.js‘ } }
然後我們想要加載一個js文件時,只要require(‘common‘)就可以加載common.js文件了。
註意一下, extensions 第一個是空字符串 ‘‘ 對應不需要後綴的情況.
(5)externals
當我們想在項目中require一些其他的類庫或者API,而又不想讓這些類庫的源碼被構建到運行時文件中,這在實際開發中很有必要。此時我們就可以通過配置externals參數來解決這個問題:
externals: {
"jquery": "jQuery"
}
(6)devtool使調試變得更容易
devtool選項 配置結果
source-map: 在一個單獨的文件中產生一個完整且功能完全的文件。這個文件具有最好的source map,但是它會減慢打包文件的構建速度;
cheap-module-source-map: 在一個單獨的文件中生成一個不帶列映射的map,不帶列映射提高項目構建速度,但是也使得瀏覽器開發者工具只能對應到具體的行,不能對應到具體的列(符號),會對調試造成不便;
eval-source-map: 使用eval打包源文件模塊,在同一個文件中生成幹凈的完整的source map。這個選項可以在不影響構建速度的前提下生成完整的sourcemap,但是對打包後輸出的JS文件的執行具有性能和安全的隱患。不過在開發階段這是一個非常好的選項,但是在生產階段一定不要用這個選項;
cheap-module-eval-source-map: 這是在打包文件時最快的生成source map的方法,生成的Source Map. 會和打包後的JavaScript文件同行顯示,沒有列映射,和eval-source-map選項具有相似的缺點;
(7)devServer 構建本地服務器
contentBase: 默認webpack-dev-server會為根文件夾提供本地服務器, 如果想為另外一個目錄下的文件提供本地服務器,應該在這裏設置其所在目錄
port: 設置默認監聽端口,如果省略,默認為”8080“
inline: 設置為true,當源文件改變時會自動刷新頁面
colors: 設置為true,使終端輸出的文件為彩色的
historyApiFallback: 在開發單頁應用時非常有用,它依賴於HTML5 history API,如果設置為true,所有的跳轉將指向index.html
(8)loader配置
通過使用不同的loader,webpack通過調用外部的腳本或工具可以對各種各樣的格式的文件進行處理,
比如說分析JSON文件並把它轉換為JavaScript文件,或者說把下一代的JS文件(ES6,ES7)轉換為現代瀏覽器可以識別的JS文件。
或者說對React的開發而言,合適的Loaders可以把React的JSX文件轉換為JS文件。
Loaders需要單獨安裝並且需要在webpack.config.js下的modules關鍵字下進行配置,
Loaders的配置選項包括以下幾方面:
test:一個匹配loaders所處理的文件的拓展名的正則表達式(必須)
loader:loader的名稱(必須)
include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不需要處理的文件(文件夾)(可選);
query:為loaders提供額外的設置選項(可選)
安裝babel,babel具有非常多的配置選項,在單一的webpack.config.js文件中進行配置往往使得這個文件顯得太復雜,因此一些開發者支持把babel的配置選項放在一個單獨的名為 ".babelrc" 的配置文件中。如果不復雜,可以直接在webpack.config.js中進行配置。
{ test: /\.jsx?$/, exclude: /node_modules/, loader: ‘babel-loader‘, options: { cacheDirectory: true, presets: [‘env‘, ‘stage-2‘, ‘react‘], plugins: [‘transform-runtime‘], }, }
css Loader處理:
test: /\.(less|css)$/, use: [ { loader: ‘style-loader‘, }, { loader: ‘css-loader‘, options: { minimize: false, sourceMap: true, }, }, { loader: ‘postcss-loader‘, options: { plugins: postcss, //自動添加適應不同瀏覽器的前綴 }, }, { loader: ‘less-loader‘, options: { sourceMap: true, }, }, ]
npm一次性安裝多個依賴模塊,模塊之間用空格隔開,安裝babel 常用的依賴
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
(9)plugins
const plugins = [ // plugin for passing in data to the js, like what NODE_ENV we are in. new webpack.DefinePlugin(config.globals), new webpack.optimize.CommonsChunkPlugin({ names: [‘common‘, ‘vendor‘, ‘manifest‘], minChunks: 2, }), new webpack.NoEmitOnErrorsPlugin(), //Hot Module Replacement(HMR)也是webpack裏很有用的一個插件,它允許你在修改組件代碼後,自動刷新實時預覽修改後的效果。在webpack中實現HMR也很簡單,只需要做兩項配置。 /**在webpack配置文件中添加HMR插件,在Webpack Dev Server中添加“hot”參數; devServer: { hot: true } */ new webpack.HotModuleReplacementPlugin(), /**在入口文件中index.js中: if (module.hot) { module.hot.accept(‘./home.js’); //接收這個文件的修改用來熱加載 module.hot.accept(‘./routes‘, () => { //路由的改變將造成熱加載,重新渲染 render(createRouter) }) } */ new webpack.NamedModulesPlugin(), //HtmlWebpackPlugin 這個插件的作用是依據一個簡單的模板(index.template.html),
//幫你生成最終的Html5文件,這個文件中自動引用了你打包後的JS文件。每次編譯都在文件名中插入一個不同的哈希值。 new HtmlWebpackPlugin({ title: ‘ACTIVE Reader Cloud Dev‘, inject: true, chunksSortMode: ‘dependency‘, filename: ‘index.html‘, template: paths.base(‘build/index.template.html‘), })
]
在package.json文件中:
devDependencies 裏面的插件只用於開發環境,不用於生產環境,而 dependencies 是需要發布到生產環境的,安裝的時候註意控制。
3.Webpack3的新特性
6月20日發布了webpack3, 它和2有什麽區別?
(1)更新方法以及版本遷移
通過命令直接安裝即可,後面需要加上版本號。
npm install [email protected] --save-dev
(2)scope hoisting
webpack2處理後的每個模塊均被一個函數包裹,如下:
/* 50 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { window.lib = {} ... /* harmony default export */ __webpack_exports__["a"] = (window.lib); /***/ }),
這樣會帶來一個問題:降低瀏覽器中JS執行效率,這主要是閉包函數降低了JS引擎解析速度。
於是webpack團隊參考Closure Compiler和Rollup JS,將一些有聯系的模塊,放到一個閉包函數裏面去,通過減少閉包函數數量從而加快JS的執行速度。
webpack3通過設置ModuleConcatenationPlugin使用這個新特性:
module.exports = { plugins: [ new webpack.optimize.ModuleConcatenationPlugin() ] };
(3)Magic Comments
用於動態引入ES Module,webpack將傳入import方法的模塊打包到一個單獨的代碼塊(chunk),但是卻不能像require.ensure一樣,為生成的chunk指定chunkName,因此在webpack3中提出了Magic Comment用於解決該問題,用法如下:
import(/* webpackChunkName: "my-chunk-name" */ ‘module‘);
其實就是可以命令 chunk name 了.
Webpack接下來的還會持續有的新特性:
- 更好的編譯緩存
- 更快的首次以及增量編譯速度
- 對 TypeScript 更加友好地支持
- 修改 Long term caching
- 增加對 WASM Module 的支持
- 用戶體驗的改進
小夥伴們敬請期待吧...
Webpack 學習總結