構建就是把源代碼轉換成發佈到線上的可執行JavaScrip、CSS、HTML代碼,包括以下內容:css
首先確保電腦已經安裝了nodejs,推薦採用nvm的形式進行安裝,這樣就不用配置環境變量或者建立軟連接。html
mkdir webpack-learn //經過命令行建立文件夾
cd webpack-learn //打開建立的文件夾
npm init -y //初始化一個項目
npm install webpack webpack-cli -D //本地安裝webpack和webpack-cli
mkdir src //建立src目錄來存放源代碼
mkdir dist //建立dist目錄來存放打包後的代碼
複製代碼
在src目錄下建立index.js前端
let str = require('./a');
console.log(str);
複製代碼
在src目錄下建立a.jsnode
module.exports='webpack-learn'
複製代碼
在dist目錄下建立index.html文件react
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
複製代碼
利用webpack進行打包,關於commonjs不清楚的,請參考require()源碼解讀jquery
npx webpack -- mode development //以默認以開發模式進行打包
複製代碼
從上面的代碼中能夠看到文件打包到了dist/main.js中,因此須要進行相應的配置webpack.config.js來自定義結果文件名。webpack
const path=require('path');
module.exports={
entry: './src/index.js', //入口
output: {
path: path.resolve(__dirname,'dist'), //出口,絕對路徑
filename:'bundle.js'
},
module: {}, //配置loader
plugins: [], //配置插件
devServer: {} //配置本地服務
resolve:{}, //配置解析文件路徑等
}
複製代碼
//index.js
console.log('hello');
複製代碼
//a.js
console.log('world')
複製代碼
const path=require('path');
module.exports={
//index和a之間沒有依賴關係,只是單純的合併
entry: ['./src/index.js','./src/a.js'],
output: {
path: path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module: {},
plugins: [],
devServer: {}
resolve:{},
}
複製代碼
//a.js
let str =require('./c')
console.log(str);
複製代碼
//b.js
let str =require('./d')
console.log(str);
複製代碼
//c.js
module.export = 'hello'
複製代碼
//d.js
module.export = 'world'
複製代碼
const path=require('path');
module.exports={
//多入口拆分功能,能夠兩個頁面分別引用一個,也能夠一個頁面引用多個
//配合後面的html-webpack-plugin使用
entry: {
pageA:'./src/a',
pageB:'./src/b'
},
output: {
path: path.resolve(__dirname,'dist'),
//帶有哈希值的文件名exp:pageA.fa112c6二、pageB.fa112c62
filename:'[name].[hash:8].js'
},
module: {},
plugins: [],
devServer: {}
resolve:{},
}
複製代碼
如今頁面是手動建立到dist目錄下的,一個頁面還好,若是存在多個頁面,手動創造html的代價是很大的,能夠利用html-webpack-plugin來自動建立頁面:web
npm install html-webpack-plugin -D
複製代碼
//src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
</body>
</html>
複製代碼
const path = require('path');
const webpack =require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry:{
pageA:'./src/a',
pageB:'./src/b'
},
output: {
path: path.resolve(__dirname,'dist'),
filename:'[name].[hash:8].js'
},
module: {},
plugins: [
//在實際項目中,經過讀取須要建立的頁面信息,遍歷建立實例
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'pageA.html',
chunks:['pageA,pageB'], //數組,能夠放多個chunk
//頁面資源攜帶哈希值exp:pageA.fa112c62?r2452567&4124
//中間哈希一直都有,這個後面的哈希只在頁面引用添加在頁面中
hash:true,
minify:{
collapseWhitespace:true, //壓縮代碼,去除空格和換行
removeAttributeQuotes:true//壓縮代碼,去除屬性雙引號
}
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'pageB.html',
chunks:['pageB'],
hash:true,
minify:{
collapseWhitespace:true,
removeAttributeQuotes:true
}
})
],
devServer: {},
resolve:{},
}
複製代碼
因爲每次打包都須要執行npx webpack --mode development,因此能夠在package.json中進行配置:express
"scripts": {
//等價於webpack --config webpack.config.js --mode development
//默認是執行webpack.config.js,能夠根據env來配置執行不一樣的文件
"start": "webpack --mode development"
},
複製代碼
首先必須的安裝插件webpack-dev-derver:npm
npm install webpack-dev-server -D
複製代碼
修改script:
"scripts": {
"dev":"webpack-dev-server --mode development"
"build": "webpack --mode development"
},
複製代碼
修改配置文件:
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id='app'></div>
</body>
</html>
複製代碼
//a.js
module.exports = 'hello'
複製代碼
//index.js
let str = require('./a');
document.getElementById('app').innerHTML = str;
複製代碼
const path=require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports={
entry: './src/index.js',
output: {
path: path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module: {},
plugins: [
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
hash:true,
minify:{
collapseWhitespace:true,
removeAttributeQuotes:true
}
})
],
devServer: {
//devServer會在打包的時候把生成的文件放在內存中,
//而且是以根目錄爲參照目錄而不是dist目錄,因此須要修改
contentBase:'./dist',
port:'3000',
}
resolve:{},
}
複製代碼
經過瀏覽器,輸入localhost:3000就能夠看到
const path = require('path');
const webpack =require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports={
entry:'./src/index.js',
output: {
filename:'bundle.js',
path: path.resolve(__dirname,'dist')
},
module: {},
plugins: [
//使用熱更新插件
new webpack.HotModuleReplacementPlugin();
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
hash:true,
minify:{
collapseWhitespace:true,
removeAttributeQuotes:true
}
})
],
devServer: {
contentBase:'./dist',
port:'3000',
hot:true //熱更新開關,使用websocket來通知頁面更新
},
resolve:{},
}
複製代碼
//index.js
let str = require('./a');
document.getElementById('app').innerHTML = str;
//這裏必須加這段,否則的話,仍是沒有辦法使用熱更新
if(module.hot){
module.hot.accept();
}
複製代碼
配置proxy
devServer: {
contentBase:'./dist',
port:'3000',
hot:true,
proxy:{
target:'http://xxxxx' //代理的服務器
pathRewirte:{
'/xxx':'/yyy'
}
}
},
複製代碼
// 把webpack-dev-server的配置引入到本身的本地服務
const express = require('express');
const webpackDevMiddleware = require('webpack-dev-middleware');
// 引入webpack配置文件
const config = require('./webpack.config');
let app = express();
cosnt webpack = require('webpack');
let compiler = webpack(config); //用webpack進行編譯
app.use(webpackDevMiddleware(compiler));
app.listen(3000);
複製代碼
webpack每找到一個Module,就會根據配置的Loader去找出對應的轉換規則,讓js能過編譯css、ejs、jsx和圖片的各類格式。
//index.css
body{
background:red;
border-radio:4px;
}
複製代碼
//通常前端代碼使用import引入模塊,node服務使用require引入模塊
import str from './a'
import './index.css'
document.getElementById('app').innerHTML=str
if(module.hot){
module.hot.accept();
}
複製代碼
執行npm run build以後發現出現如下報錯,說明須要配置loader:
npm install css-loader style-loader -D
複製代碼
const path = require('path');
const webpack =require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry:{
index:'./src/index'
},
output: {
filename:'[name].[hash:8].js',
path: path.resolve(__dirname,'dist')
},
module: {
rules:[
{
test:/\.css$/,
//多個loaders用數組,loader的形式有字符串和對象兩種
//字符串形式:'xxx?option1!yyyy'
//對象形式{loader:'xxx',options:{option1:yyyy}}
//less-laoder將less轉化爲css,css-loader解析css,style-loader插入到style標籤中
use:['style-oader','css-loader']
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['index']
})
],
devServer: {
contentBase:'./dist',
port:'3000',
hot:true
},
resolve:{},
}
複製代碼
用npm run dev啓動服務能夠看到效果,可是這樣有一個問題,css樣式採用的內嵌式,最好能抽離出來使用外鏈式引入,能夠使用插件mini-css-extract-plugin:
npm install mini-css-extract-plugin -D
複製代碼
const path = require('path');
const webpack =require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry:{
index:'./src/index'
},
output: {
filename:'[name].[hash:8].js',
path: path.resolve(__dirname,'dist')
},
module: {
rules:[
{
test:/\.css$/,
use:[{
loader:MiniCssExtractPlugin.loader,
options:{
//將css中的路經前面添加,background:url('xxxx')
//http://ssss/xxxxx
publicPath:'http://sssss'
}
},
'css-loader'
]
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename:index.css,
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['index']
})
],
devServer: {
contentBase:'./dist',
port:'3000',
hot:true
},
resolve:{},
}
複製代碼
因爲前端寫的代碼要兼容各類瀏覽器,css屬性爲了兼容各大瀏覽器,每每須要添加各類前綴,可是同一個屬性寫多份,這個工做量仍是比較大的,有一個postcss-loader能夠配合autoprefixer插件使用
//index.css
body{
background:red;
transform: rotate(0,0,100deg);
}
複製代碼
npm install postcss-loader autoprefixer -D
複製代碼
//建立postcss.config.js
module.exports ={
plugins:[
require('autoprefixer')
]
}
複製代碼
const path = require('path');
const webpack =require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry:{
index:'./src/index'
},
output: {
filename:'[name].[hash:8].js',
path: path.resolve(__dirname,'dist')
},
module: {
rules:[
{
test:/\.css$/,
use:[
{loader:MiniCssExtractPlugin.loader},
'css-loader',
'postcss-loader' //添加css前綴處理laoder
]
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename:index.css,
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['index']
})
],
devServer: {
contentBase:'./dist',
port:'3000',
hot:true
},
resolve:{},
}
複製代碼
項目中引入圖片的方式有三種:
//index.js
import './index.css'
import jpg from './1.jpg'
let img = new Image();
img.src=jpg;
document.body.appendChild(img);
if(module.hot){
module.hot.accept();
}
複製代碼
//index.css
body{
background: url('./1.jpg') no-repeat right;
}
複製代碼
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<img src="./1.jpg" alt="">
</body>
</html>
複製代碼
處理前兩種引入圖片的方式須要使用file-loader和url-loader,其中url-laoder內部會引用file-loader,它們的做用就是解析js和css中的圖片連接而後將圖片變成base64。後一種引入圖片的方式須要使用html-withimg-loader。
npm install file-loader url-loader html-withimg-loader -D
複製代碼
const path = require('path');
const webpack =require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry:{
index:'./src/index'
},
output: {
filename:'[name].[hash:8].js',
path: path.resolve(__dirname,'dist')
},
module: {
rules:[
{
test:/\.css$/,
use:[{
loader:MiniCssExtractPlugin.loader,
},'css-loader']
},
{
test:/\.jpg|png/,
use:{
loader:'url-loader',
options:{
//大於8k的圖片會打包到dist目錄下,小於8k的圖片會生成base64插入到引用的地方
//base64會使資源變大1/4,可是base64無需發送請求,資源比較小時使用base64最佳
limit:8*1024
}
}
},
{
test:/\.html$/,
use:'html-withimg-loader'
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename:index.css,
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['index']
})
],
devServer: {
contentBase:'./dist',
port:'3000',
hot:true
},
resolve:{},
}
複製代碼
因爲ES6的簡潔和API擴展,有不少開發者使用ES6進行開發,可是因爲瀏覽器的品牌和版本的不一樣,就出現了開發時使用ES6而後贊成轉化成ES5的狀況。這時候就須要使用babel對ES6+的語法進行轉譯,關於babel的各類配置能夠參考對babel-transform-runtime,babel-polyfill的一些理解。
npm install babel-core babel-loader babel-preset-env babel-preset-stage-0 babel-plugin-tranform-runtime -D
複製代碼
//建立.babelrc文件
//preset中包含了一組用來轉換ES6+的語法的插件,可是還不轉換新的API
//如需使用新的API,例如set(),還須要使用對應的轉換插件或者polyfill(填充庫)
{
presets:{
'env', //環境變量,根據不一樣瀏覽器環境而對應的轉碼
'stage-0' //轉譯ES6+(0 > 1 > 2 > 3 > 4)
}
plugins:{
'tranform-runtime'
}
}
複製代碼
const path = require('path');
const webpack =require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry:{
index:'./src/index'
},
output: {
filename:'[name].[hash:8].js',
path: path.resolve(__dirname,'dist')
},
module: {
rules:[
{
test:/\.css$/,
use:[{
loader:MiniCssExtractPlugin.loader,
},'css-loader']
},
{
test:/\.jpg|png/,
use:{
loader:'url-loader',
options:{
limit:8*1024
}
}
},
{
test:/\.html$/,
use:'html-withimg-loader'
},
{ //使用babel-loader
test:/\.js$/,
use:'babel-loader',
exclude:/node_modules/ //排除編譯ndoe——modules
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename:index.css,
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['index']
})
],
devServer: {
contentBase:'./dist',
port:'3000',
hot:true
},
resolve:{},
}
複製代碼
plugin和loader的區別在於loader只在編譯module時執行,而plugin可能在webapck工做流程的各個階段執行。
清除dist目錄
module.exports = {
mode:'production', 生產環境會自動壓縮
entry:{
index:'./src/index'
},
output: {
filename:'[name].[hash:8].js',
path: path.resolve(__dirname,'dist')
},
module: {
rules:[
{
test:/\.css$/,
use:[{
loader:MiniCssExtractPlugin.loader,
},'css-loader']
},
{
test:/\.jpg|png/,
use:{
loader:'url-loader',
options:{
limit:8*1024
}
}
},
{
test:/\.html$/,
use:'html-withimg-loader'
},
{
test:/\.js$/,
use:'babel-loader',
exclude:'/node_modules/'
}
]
},
plugins: [
new CleanWebpackPlugin(['dist/*.*']), //清空dist目錄
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename:index.css,
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['index']
})
],
externals:{
'jquery':'$'
}
devServer: {
contentBase:'./dist',
port:'3000',
hot:true
},
resolve:{},
}
複製代碼
module.exports = {
mode:'production', 生產環境會自動壓縮
entry:{
index:'./src/index'
},
output: {
filename:'[name].[hash:8].js',
path: path.resolve(__dirname,'dist')
},
optimization:{
minimizer:{
new UglifyJSPlugin({ //壓縮js
cache:true,
parallel:ture, //並行壓縮
sourthMap:true, //啓動sourthMap
}) ,
new OptimizeCssAssetsPlugin() //壓縮css
}
},
module: {
rules:[
{
test:/\.css$/,
use:[{
loader:MiniCssExtractPlugin.loader,
},'css-loader']
},
{
test:/\.jpg|png/,
use:{
loader:'url-loader',
options:{
limit:8*1024
}
}
},
{
test:/\.html$/,
use:'html-withimg-loader'
},
{
test:/\.js$/,
use:'babel-loader',
exclude:'/node_modules/'
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new MiniCssExtractPlugin({
filename:index.css,
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html',
chunks:['index']
})
],
externals:{
'jquery':'$'
}
devServer: {
contentBase:'./dist',
port:'3000',
hot:true
},
resolve:{},
}
複製代碼
學習webpack的過程是從官方文檔開始學習的,照着敲了一遍,而後搜索相關的內容。