webpack4 开发环境搭建
1. 概念
本质上,webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler)。当webpack处理应用程序时,会递归地创建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。
2. 初始化项目
本次环境将使用webpack4来构建配置。
mkdir webpack-demo && cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev
3. 目录改造
项目初始化完成,目录结构如下
根目录下建立dist文件夹、src文件夹、webpack.config.js文件和.gitignore文件。
src文件夹下建立scss、images、js子文件夹和index.html文件。
js文件夹和scss文件夹下分别建立index.js和index.scss文件。
images文件夹下放入一个名称为info的图片
webpack4中,现在已经可以无须任何配置,然而大多数项目会需要很复杂的配置,所以webpack仍然要支持配置文件,本次配置也将使用配置文件的方式。
Sass是一款成熟、稳定、强大的专业级css扩展语言,本次项目将使用Sass来编写样式文件。
.gitignore文件是git上传的忽略文件。
改造完目录如下
4. 配置webpack.config.js
配置js文件的入口和打包后的文件名称及输出目录。
entry是文件的入口,当前配置使用单页面的方式,可以配置多个入口文件。
output是打包后的输出目录,当前配置是根路径下的dist/js目录。
const path = require('path');
module.exports = {
mode: 'development',
entry: {
index: path.resolve(__dirname, 'src/js/index.js')
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].js'
}
}
5. 配置package.json文件
在根目录下直接运行cmd命令 webpack --config webpack.config.js 就可以使用webpack-cli编译项目。考虑到使用CLI方式运行本地的webpack不方便,我们可以编写一个NPM脚本。
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack --config webpack.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
}
}
执行 npm run webpack 命令后,查看dist目录,如果发现dist目录下已经生成js/index.js文件。说明第一步配置已经完成。
6. 编译ES6语法
编译ES6语法需要使用 babel-loader、babel-core、babel-preset-latest和uglifyjs-webpack-plugin。
babel-core:封装babel编译时需要使用的API;
babel-loader:负责ES6语法转化,webpack打包时使用babel-loader处理js文件;
babel-preset-latest:特殊的presets,包括es2015、es2016、… es2017;
uglifyjs-webpack-plugin:用来缩小(压缩优化)js文件;
babel-loader和babel-core需要版本对应,负责会编译报错。
babel-loader 8.x 对应 babel-core 7.x
babel-loader 7.x 对应 babel-core 6.x
依赖安装
npm install babel-core@6.26.3 babel-loader@7.1.5 --save-dev
npm install babel-preset-latest uglifyjs-webpack-plugin --save-dev
依赖配置
webpack.config.js 中增加以下配置
const path = require('path'),
uglify = require('uglifyjs-webpack-plugin');
module 配置
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: path.resolve(__dirname, 'node_modules'),
query: {
'presets': ['latest']
}
}
]
}
plugins 配置
plugins: [
new uglify()
]
运行测试
index.js
const arr = ['张三', '李四', '王五', '赵六'],
iterator = arr.keys();
for (const key of iterator) {
document.write(arr[key]);
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpack4</title>
</head>
<body>
<script type="text/javascript" src="../dist/js/index.js"></script>
</body>
</html>
index.js中编写测试程序,使用打包命令 npm run webpack打包,并在index.html中引入打包好的js文件。浏览器运行如果打印出循环的arr名称,说明babel配置已经完成。
7. 编译.scss文件
编译Sass语法需要使用到 css-loader、style-loader、sass-loader、node-sass、postcss-loader、autoprefixer、extract-text-webpack-plugin@next。
css-loader:通过require的方式引入css,使用css-loader先将css代码编译,然后再使用style-loader插入到网页中;
style-loader:配置css-loader使用,可以以内联样式的形式在html页面中插入css代码;
sass-loader、node-sass:用来解析解析.scss文件,编译sass语法;
postcss-loader:一个用JavaScript工具和插件转换css代码的工具;
autoprefixer:配合postcss-loader为css的属性添加浏览器特定的前缀;
extract-text-webpack-plugin(可选):可以抽离css文件,并以外链的方式引入css文件。
相对于mini-css-extract-plugin,webpack4推荐使用extract-text-webpack-plugin来提取css样式。
依赖安装
npm install css-loader style-loader sass-loader node-sass --save-dev
npm install postcss-loader autoprefixer extract-text-webpack-plugin@next
依赖配置
webpack.config.js 中增加以下配置(二选一)。
const path = require('path'),
autoprefix = require('autoprefixer'),
uglify = require('uglifyjs-webpack-plugin'),
extractTextPlugin = require('extract-text-webpack-plugin');
1. 不提取css文件,内联样式
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: function () {
return [autoprefix('last 5 versions')]
}
}
},
'sass-loader'
]
}
2. 提取css文件,外链样式
module 配置
{
test: /\.scss$/,
use: extractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: function () {
return [autoprefix('last 5 versions')]
}
}
},
'sass-loader'
]
})
}
plugins 配置
plugins: [
new extractTextPlugin("css/styles.css"),
new uglify()
]
运行测试
inde.scss
#app {
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 200px;
margin: 20px auto;
border: 1px solid transparent;
background-color: orange;
box-shadow: 2px 3px 5px #ddd;
box-sizing: border-box;
&:hover {
border-color: #ddd;
}
}
index.js
import '../css/index.scss'
const App = (doc) => {
const app = doc.createElement('div');
app.id = 'app';
document.body.appendChild(app);
}
App(document);
编写index.scss,并在index.js文件中引入,编译后运行index.html进行测试。
出现以下效果,说明配置完成。
8. 服务器及热更新配置
服务器热更新配置需要使用 webpack-dev-server、html-webpack-plugin。
webpack-dev-server:一个小型的Node.js Express服务器;
html-webpack-plugin:可以根据模板文件动态生成HTML文件;
依赖安装
npm install webpack-dev-server html-webpack-plugin --save-dev
依赖配置
webpack.config.js 中增加以下配置。
const path = require('path'),
autoprefix = require('autoprefixer'),
uglify = require('uglifyjs-webpack-plugin'),
htmlWebpackPlugin = require('html-webpack-plugin'),
extractTextPlugin = require('extract-text-webpack-plugin');
plugins 配置
plugins: [
// new extractTextPlugin("css/styles.css"),
new uglify(),
new htmlWebpackPlugin({
removeComments: true,
collapseWhitespace: true,
filename: 'index.html',
template: path.resolve(__dirname, 'src/index.html'),
title: 'webpack-demo',
chunksSortMode: 'manual',
chunks: ['index'],
excludeChunks: ['node_modules'],
hash: true
})
]
dev-server 配置
devServer: {
watchOptions: {
ignored: /node_modules/
},
host: 'localhost',
port: 3000
}
pageage.json 配置NPM服务器启动脚本
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack --config webpack.config.js",
"dev": "webpack-dev-server --host localhost --content-base dist/ --hot --config webpack.config.js --progress --display-modules --colors --display-reasons"
}
inedex.html 模板配置
配置动态渲染标题及移除之前引入的index.js文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>
运行测试
执行脚本 npm run dev,服务器启动后,监听3000端口。
访问http://localhost:3000/连接,出现以下页面,代表服务器配置成功。
9. 编译图片资源
编译图片资源需要用到 file-loader、url-loader、image-webpack-loader。
file-loader:可以用来解析图片文件;
url-loader:增强版的file-loader,可以根据需求选择性把小图片编码成base64格式;
image-webpack-loader:用于图片压缩;
依赖安装
npm i file-loader url-loader image-webpack-loader --save-dev
依赖配置
webpack.config.js 中增加以下配置。
module 配置
{
test: /\.(png|jpg|jpeg|gif|ico)$/i,
loader: [
'url-loader?limit=1024&name=img/[name]-[hash:16].[ext]',
'image-webpack-loader'
]
}
index.scss 文件样式修改
#app {
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 200px;
margin: 20px auto;
border: 1px solid transparent;
box-shadow: 2px 3px 5px #ddd;
box-sizing: border-box;
&:hover {
border-color: #ddd;
}
.img {
width: 100px;
}
}
index.js 引入图片并添加到页面
import '../scss/index.scss'
import icon from '../images/icon.jpg';
const App = (doc) => {
const app = doc.createElement('div'),
img = doc.createElement('img');
app.id = 'app';
img.src = icon;
img.className = 'img';
app.appendChild(img);
document.body.appendChild(app);
}
App(document);
运行测试
运行 npm run dev 命令,启动服务器,出现以下页面效果,说明配置已经完成。
10. 总结
通过这篇文章,记录如何用webpack4搭建一个开发环境,用于ES6模块化项目的开发。
当然在实际场景中,还需要复杂的业务,对配置进行进一步的调整与优化。
完整配置如下:
webpack.config.js 配置
const path = require('path'),
autoprefix = require('autoprefixer'),
uglify = require('uglifyjs-webpack-plugin'),
htmlWebpackPlugin = require('html-webpack-plugin'),
extractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
mode: 'development',
entry: {
index: path.resolve(__dirname, 'src/js/index.js')
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].js'
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: path.resolve(__dirname, 'node_modules'),
query: {
'presets': ['latest']
}
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: function () {
return [autoprefix('last 5 versions')]
}
}
},
'sass-loader'
]
},
// {
// test: /\.scss$/,
// use: extractTextPlugin.extract({
// fallback: 'style-loader',
// use: [
// 'css-loader',
// {
// loader: 'postcss-loader',
// options: {
// plugins: function () {
// return [autoprefix('last 5 versions')]
// }
// }
// },
// 'sass-loader'
// ]
// })
// },
{
test: /\.(png|jpg|jpeg|gif|ico)$/i,
loader: [
'url-loader?limit=1024&name=img/[name]-[hash:16].[ext]',
'image-webpack-loader'
]
}
]
},
plugins: [
// new extractTextPlugin("css/styles.css"),
new uglify(),
new htmlWebpackPlugin({
removeComments: true,
collapseWhitespace: true,
filename: 'index.html',
template: path.resolve(__dirname, 'src/index.html'),
title: 'webpack-demo',
chunksSortMode: 'manual',
chunks: ['index'],
excludeChunks: ['node_modules'],
hash: true
})
],
devServer: {
watchOptions: {
ignored: /node_modules/
},
host: 'localhost',
port: 3000
}
}