webpack 是一個打包工具,用在asp.net Core MVC 會覺得有必要嗎? MVC 本身就有bundler~ 如果用過webpack就會知道,打包出來的效果結果就是不一樣,MVC的打包就是把所有的代碼放在一起,而且一個項目就只可以有一個打包,那里夠用?
打包主要目的減少多頁面應用反問服務器的次數,以前一個頁面可以訪問服務器多打20多個(不包括圖片),現在css + script 就只有4個,通過緩存,其他頁面就只有2個訪問。webpack 還對css 和 script 有hash 管理,這解決了顧客游覽器緩存問題。
開始第一步,先搞定package.json
{
"name": "webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack --env production",
"build": "webpack-dev-server --env development"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babili-webpack-plugin": "^0.1.2",
"css-loader": "^0.28.7",
"extract-text-webpack-plugin": "^3.0.1",
"html-webpack-inline-source-plugin": "0.0.9",
"html-webpack-plugin": "^2.30.1",
"inline-resource-plugin": "^0.6.3",
"sass-loader": "^6.0.6",
"style-loader": "^0.18.2",
"url-loader": "^0.6.2",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
},
"dependencies": {
"bootstrap": "^4.0.0-alpha.6",
"jquery": "2.2.0"
}
}
npm install 后再准備webpack.config.js
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const BabiliPlugin = require('babili-webpack-plugin'); const webpack = require('webpack'); const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin'); const extractTextPlugin = new ExtractTextPlugin({ filename: '[name].[contenthash].css',//打包后的css 需要hash ignoreOrder: true }); module.exports = { devServer: { //這沒什么用到,就是在開發時的設定,我一般都是直接production host: process.env.host, port: 4200, overlay: { errors: true, // warnings : true } }, watch: true,//當改變代碼時,會自動更新,除了config devtool: 'source-map',//在有bug時,可以看到源碼 entry: { //這是個對象,是聲明要打包什么,需要一個key(也是最終打包的位置) 'content/shared': path.join(__dirname, 'Web/Shared/Index'),//需要聲明要打包對應的Index.js 'content/home': path.join(__dirname, 'Web/Home/Index'), //amp 'content/homeAmp': path.join(__dirname, 'Web/Home/Amp/Index') }, output: { //輸出位置 publicPath: "/", path: path.resolve(__dirname, 'wwwroot'),//MVC 最終可以調用的文檔都放在wwwrooot filename: '[name].[hash].js'//hash 管理js }, module: { //不同的文檔需要不同的loader處理器 rules: [ { test: /\.css$/,//主要的css exclude: /node_modules/, use: extractTextPlugin.extract({ use: { loader: 'css-loader', options: { modules: true, minimize: true || {/* CSSNano Options */ } //要minimize } }, fallback: 'style-loader' }) }, { test: /\.scss$/, //如果沒用到就拿掉吧 use: ExtractTextPlugin.extract({ fallback: 'style-loader', //resolve-url-loader may be chained before sass-loader if necessary use: [ //先跑sass loader 再跑css loader { loader: 'css-loader', options: { modules: true, minimize: true || {/* CSSNano Options */ } } }, 'sass-loader' ] }) }, { test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000' } //在文檔中會出現其他文檔,需要聲明處理 ] }, plugins: [ new webpack.ProvidePlugin({ //全局,只要package.json 有,就能直接全場調用,那么為什么不直接import呢?因為不是每個js都符合webpack規范 $: "jquery", jQuery: "jquery" }), new HtmlWebpackPlugin({ //處理html inject: false,//false 是不處理置入,結果是把css 和 script 放在指定的位置 template: 'Web/Shared/Template.cshtml',//需要一個模版來做正真的html filename: '../Web/Shared/_Layout.cshtml',//正真的html chunks: ['content/shared']//輸出位置 }), new HtmlWebpackPlugin({ inject: false, template: 'Web/Home/Template.cshtml', filename: '../Web/Home/Index.cshtml', chunks: ['content/home'] }), //amp new HtmlWebpackPlugin({ inject: "head",//把css 和 script 放在head里 template: 'Web/Home/Amp/Template.cshtml', filename: '../Web/Home/Amp/Index.cshtml', chunks: ['content/homeAmp'], inlineSource: '.(css)$',//把css打包成一行,直接放在html里 }), new HtmlWebpackInlineSourcePlugin(), extractTextPlugin, new BabiliPlugin(), new webpack.optimize.CommonsChunkPlugin( { name: ['content/shared'] } //優化,由於同個頁面重復使用某個css 和 script,這里會過濾掉
) ] }
接着是index.js
import '../../node_modules/bootstrap-sass/assets/stylesheets/_bootstrap.scss';
import './Index.scss';
import '../../node_modules/bootstrap-sass/assets/javascripts/bootstrap.js';
接着是layout template
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Project</title>
<% for (var css in htmlWebpackPlugin.files.css) { %><link href="<%=htmlWebpackPlugin.files.css[css] %>" rel="stylesheet"><% } %> //inject css 位置
@RenderSection("Css", required: false)
</head>
<body>
@RenderBody()
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %><script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script><% } %> //inject script 位置
@RenderSection("Scripts", required: false)
</body>
</html>
接着是home template
@section Css{
<% for (var css in htmlWebpackPlugin.files.css) { %><link href="<%=htmlWebpackPlugin.files.css[css] %>" rel="stylesheet"><% } %>
}
@section Scripts{
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %><script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script><% } %>
}
<h1>home</h1>
這是文檔結構
通過npm start就可以得到wwwroot里content的結果,
那么webpack是怎么處理整個過程的呢?
通過entry找到要打包的位置,找到index就能找到對應的index.js
index.js 中,通過import和其他css 和 script 連接在一起(webpack是import 概念,被import的script 需要有comand js的規范,大概是這樣)
通過plugin的設置,會通過模版把css和script放在對應的位置,然后轉換去正真的html