由于webpack更新了4.0以上版本,这里描述的是v3版本
自己使用webpack有一段时间了,现在也在学习中,接触webpack之前所使用的工具只有grunt,之后遇到上了webpack,学习过程中也遇到了很多坑,网上也有不少教程,这里也就整理一下,当作学习笔记,不少地方借鉴了vue(特别是目录搭建+样式处理)
webpack+jquery+ejs
entry
入口文件output
输出文件loaders
解析各种文件的loaderplugins
插件配置webpack
目前还是不要用v4版本npm install -D [email protected]
babel-loader
js
文件的loader
babel-core
同上html-webpack-plugin
个人理解为将打包的js
和html
进行绑定style-loader
样式loader
css-loader
同上url-loader
资源(img资源、media资源等)loader
build/
文件下面加入创建webpack.js
src/script/
文件下创建index.js
src/page/
文件下创建index.html
编写代码
/* webpack.js */
// 路径解析
const path = require('path');
module.exports = {
// js文件入口
entry: path.join(__dirname, '../src/script/index.js'),
// 输出到dist目录
output: {
path: path.join(__dirname, '../dist'),
filename: 'js/[name].js'
},
module: {
loaders: [
{
// 对js文件使用loader
test: /\.js$/,
use: 'babel-loader'
}
]
}
};
打开终端运行一下
webpack --config build/webpack.js
继续前进,加入html,引入html-webpack-plugin
插件
// 路径解析
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// js文件入口
entry: path.join(__dirname, '../src/script/main.js'),
// 输出到dist目录
output: {
path: path.join(__dirname, '../dist'),
filename: 'js/[name].js'
},
module: {
loaders: [
{
// 对js文件使用loader
test: /\.js$/,
use: 'babel-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
// 生成的html文件名,该文件将被放置在输出目录
filename: 'index.html',
// 源html文件路径
template: path.join(__dirname, '../src/page/index.html')
})
]
};
运行一下,html已被生成,并且加入了script
标签
加入样式文件,在src/style/
文件下创建index.css
,随便写点样式,并由index.js
引入
/* index.css */
body {
background: red;
}
/* index.js */
import '../style/index.css';
console.log('webpack第一步');
由于没有加css
的loader
,此时运行必定报错,需要加入对相应的loader
...
module: {
loaders: [
{
// 对js文件使用loader
test: /\.js$/,
use: 'babel-loader'
},
{
// 对css文件使用loader
test: /\.css$/,
// 从右到左执行loader
use: ['style-loader', 'css-loader']
}
]
},
...
运行一下,css
已被打包进main.js
内
浏览器打开index.html
,可看到样式被插入到head
里面style
标签内
extract-text-webpack-plugin
)npm install -D extract-text-webpack-plugin
借助extract-text-webpack-plugin
插件可以将css
从js
内分离
/* webpack.js */
// 引入插件
const ExtractTextPlugin = require('extract-text-webpack-plugin');
// loaders修改css
...
{
// 对css文件使用loader
test: /\.css$/,
// 使用插件提取样式
use: ExtractTextPlugin.extract({
// 样式loader运行顺序,后续可加入less/sass等处理
use: 'css-loader',
// 若上述处理进行顺利,执行style-loader并导出文件
fallback: 'style-loader'
})
}
...
// plugins里面加入
plugins: [
new ExtractTextPlugin('css/[name].css'),
new HtmlWebpackPlugin({
// 生成的html文件名,该文件将被放置在输出目录
filename: 'index.html',
// 源html文件路径
template: path.join(__dirname, '../src/page/index.html')
})
]
运行一下,css
被生成了,这里解释一下为什么我们引入的是index.css
却生成了main.css
,由于目前属于单页面且没有指定[name]
,默认为main
,之前的js
也是如此
为了不那么麻烦运行,使用npm start
替换webpack --config build/webpack.js
,修改packgae.json
文件
{
"name": "demo1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack --config build/webpack.js"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"html-webpack-plugin": "^3.1.0",
"webpack": "^3.10.0"
}
}
继续前进,css
引入资源,webpack.js
加入url-loader
file-loader
/* index.css */
body {
background: url('../assets/bg.jpg');
}
div {
background: url('../assets/header.jpg') no-repeat;
}
// module.loaders加入
{
// 对下列资源文件使用loader
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
loader: 'url-loader',
options: {
// 小于10kb将会转换成base64
limit: 10240,
// 大于10kb的资源输出地[name]是名字[ext]后缀
name: 'img/[name].[ext]'
}
}
运行一下,小于10k的已被转换成了base64,大于的执行路径引用
细看引用路径,就会发现这个路径是错误的,我们需要的是background: url(../img/bg.jpg);
这样的路径,更改这里我们需要修改.css
文件的处理规则
/* webpack.js */
...
{
// 对css文件使用loader
test: /\.css$/,
// 使用插件提取样式
use: ExtractTextPlugin.extract({
// 样式loader运行顺序,后续可加入less/sass等处理
use: 'css-loader',
// 若上述处理进行顺利,执行style-loader并导出文件
fallback: 'style-loader',
// 样式覆盖路径 处理背景图之类
publicPath: '../'
})
}
...
运行结果
为了便于开发,解决缓存问题,为打包生成的文件加入[hash]
,若嫌弃生成的hash
的长度,可使用[hash:n]
自定义长度
对于img
audio
video
标签这些资源来说,虽然我们可以通过html-loader
来引入,但如果没有对应的loader
来处理这些文件,也会出错,之前已经有图片处理的url-loader
,这个loader
也同样适用于处理媒体资源
npm install -D html-loader
...
/* webpack.js */
{
test: /\.html$/,
loader: 'html-loader',
options: {
// 标签+属性 貌似link:href会出错,引入脚本也会出现问题,img,audio,video是OK的
attrs: ['img:src', 'audio:src', 'video:src'],
interpolate: true
}
},
// 相应的loader解析
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10240,
name: 'media/[name].[hash:8].[ext]'
}
}
...
由于.js
和.css
已经有相应的处理,html-loader
并不适用于这两个文件的引用,运行结果如下
可以看到对应的资源都已经被打包,且被输出到指定文件夹,多次引用也不会重复打包,但如果有第三方库,且不支持webpack的模块引入,这样也就没有loader
来处理了0.0,不过我们可以在外部建立一个static
文件夹来存放这些第三方资源,通过copy-webpack-plugin
来复制资源到指定位置,这里顺便使用一下rimraf
包来清理dist
目录(虽然clean-webpack-plugin
也能清理,但还是觉得直接删除暴力,直接些)
static
文件目录下载包
npm install -D copy-webpack-plugin rimraf
/* webpack.js */
const CopyWebpackPlugin = require('copy-webpack-plugin');
const rm = require('rimraf');
// 删除
rm(path.join(__dirname, '../dist'), (err) => {
if (err) throw err;
});
// plugins增加copy插件
new CopyWebpackPlugin([{
// 源文件目录
from: path.join(__dirname, '../static'),
// 目标目录 dist目录下
to: 'static',
// 筛选过滤,这里复制所有文件,连同文件夹
ignore: ['.*']
}])
运行结果如下
bootstrap库已经被复制过来了,同样之前生成的乱目录文件也被清理干净了,这里提一下,由于没有相应的loader
处理,源html
文件中引入资源的时候就不能使用本地相对路径了,直接static/***
基本的一些处理做完了,但个人有强迫症,目录很乱,src/assets/
下面图片和媒体资源混乱(虽然打包之后分开了),打包生成的目录也乱(这里打包生成的目录借鉴vue),来整理目录吧,就想收拾房间那样~
首先处理src/assets/
,手动分离并修改相应文件的引用路径,如果嫌麻烦可以不修改,直接进入打包之后的文件修改
dist
目录结构我们只需要在webpack.js
里面相应的位置加入staic/
即可,附上目前完整的webpack.js
代码
/* webpack.js */
// 路径解析
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const rm = require('rimraf');
// 删除
rm(path.join(__dirname, '../dist'), (err) => {
if (err) throw err;
});
module.exports = {
// js文件入口
entry: path.join(__dirname, '../src/script/main.js'),
// 输出到dist目录
output: {
path: path.join(__dirname, '../dist'),
filename: 'static/js/[name].[hash].js'
},
module: {
loaders: [
{
// 对js文件使用loader
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.html$/,
loader: 'html-loader',
options: {
// 标签+属性
attrs: ['img:src', 'audio:src', 'video:src']
}
},
{
// 对css文件使用loader
test: /\.css$/,
// 使用插件提取样式
use: ExtractTextPlugin.extract({
// 样式loader运行顺序,后续可加入less/sass等处理
use: 'css-loader',
// 若上述处理进行顺利,执行style-loader并导出文件
fallback: 'style-loader',
// 样式覆盖路径 处理背景图之类
publicPath: '../../'
})
},
{
// 对下列资源文件使用loader
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
loader: 'url-loader',
options: {
// 小于10kb将会转换成base64
limit: 10240,
// 大于10kb的资源输出地[name]是名字[ext]后缀
name: 'static/img/[name].[hash:8].[ext]'
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10240,
name: 'static/media/[name].[hash:8].[ext]'
}
}
]
},
plugins: [
new ExtractTextPlugin('static/css/[name].[hash].css'),
new HtmlWebpackPlugin({
// 生成的html文件名,该文件将被放置在输出目录
filename: 'index.html',
// 源html文件路径
template: path.join(__dirname, '../src/page/index.html')
}),
new CopyWebpackPlugin([{
// 源文件目录
from: path.join(__dirname, '../static'),
// 目标目录 dist目录下
to: 'static',
// 筛选过滤,这里复制所有文件,连同文件夹
ignore: ['.*']
}])
]
};
由于多了一层目录,所以ExtractTextPlugin.extract
里面也就对应的多一层../
至此,基础配置就算是完成了,接下来,使用webpack-dev-server
构建服务
npm install -D [email protected]
v3以上版本是需要webpack-cli
这里还是使用3.0以下的吧
通过webpack-dev-server --config buidl/webpack.js
运行即可,修改一下packge.json
"scripts": {
"start": "webpack-dev-server --config build/webpack.js",
"build": "webpack --config build/webpack.js"
}
npm start
开启本地服务器,npm run build
可以打包,先npm start
运行一下(我已经删除了dist目录)
这里可以看到服务器已经搭建完毕,可以通过localhost:8080
访问,另外并没有生成dist
目录,因为其生成的文件都放置内存中,我们没法看见,如果运行npm run build
就会看到打包生成的文件了,浏览器访问一下吧~
另外我们也可以自定义端口号和加入局域网IP来搭建服务器
/* webpack.js */
module.exports = {
entry: ....
output: ...
// 加入端口和IP配置
devServer: {
host: '192.168.0.101',
port: '2018'
},
module: ...
}
由于es6的普及,开发过程中es6的特性也被大量使用,let,const,箭头函数啊等等,webpack只是打包,并没有将es6转换为es5
可见webpack
只是执行,并未处理语法,所以这时候我们就需要用到babel
,通过.babelrc
文件以及相应的配置可以来帮我们转换es6,babel具体说明见官网
npm install -D babel-preset-latest babel-preset-stage-0
创建.babelrc
文件并写入相关配置代码,这里的配置都是极为基础,打包运行如下,可见const
、() => {}
、...
都被转换了
好了第一步就算是走完了,下一章的笔记是环境分离,多页面开发,压缩文件也放入下一章里面~
希望对大家有所帮助,如有错误,欢迎指出……附上本章GitHub源码
PS:当我写第二篇笔记的时候发现这篇里面有关sourceMap的配置遗漏了需要加入devtool
属性,这里忘记说了
module.exports = {
devtool: 'source-map' // 值有很多种这里我使用它
}