构建就是把源代码转换成发布到线上的可执行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的过程是从官方文档开始学习的,照着敲了一遍,而后搜索相关的内容。