1️⃣. 引入 | Demo
当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要(依赖)的每个模块(modules),然后将所有这些模块打包成一个或多个 assets。
npm init -y 初始化一个package.json文件
然后将webpack安装在本地 npm i -D webpack
注意:
npm install --save-dev webpack
完成安装之后如下如所示:
npm i lodash -P
lodash 参考:https://www.lodashjs.com/
然后在````index.js```文件中写如下代码:
import _ from 'lodash';
let createDomElement = ()=>{
let dom = document.createElement('div');
dom.innerHTML = _.join(['https://','blog','.csdn','.net','/imaginecode'],'');
return dom;
}
document.body.appendChild(createDomElement());
接着,在index.html文件中写入:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack App</title>
<body>
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
webpack.config.js
,编写webpack.config.js
文件webpack.config.js遵循Nodejs
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname,'./dist')
}
}
npx webpack
进行构建你可以在package.json 的scripts
下加入"build":"npx webpack"
以后就只需要执行 npm run build
执行成功后,然后我们在浏览器中打开index.htm
前面我们用一个小Case让大家了解了一下Webpack。下面,我们在开始进一步完善我们的Case前,需要先知道一些webpack的先验知识/概念。这些概念也可以在Case的进行中在https://www.webpackjs.com/
中文文档中进行查阅。
配置大都是在导出的模块(module.exports
)对象体中完成的:
module.exports = {
}
module.exports = {
mode: 'production', //设置开发模式为生产模式
}
module.exports = {
mode: 'production',
entry: { //入口文件
app:'./src/index.js',
},
}
入口配置,告诉webpack应该从哪个模块开始(上面从src/index.js这个模块),作为构建内部依赖图
的开始。可以配置多个。
module.exports = {
mode: 'production',
entry: {
app:'./src/index.js',
print:'./src/print.js'
},
output: { //输出文件
filename: '[name].bundle.js', //如何命名
path:path.resolve(__dirname,'./dist') //在哪里输出bundles
},
output属性,则是告诉webpack在哪里(path
)输出它所创建的assets(或者说bundles),并告诉Webpack要怎样命名这些文件(filename
)。
module 模块中的选项决定了如何处理项目中不同类型的模块。
这项能防止webpack解析与给定的正则表达式相匹配的文件。需要注意的是,不进行解析的文件中不能含有import,require,define
等其他导入机制。通常,我们可以选择不对大文件库进行解析,如jquery。
rules,顾名思义,是一种规则数组。即,当创建模块时,根据规则数组进行匹配。同时,这些规则能够对模块应用loader
等。
同时还有其他条件,如:
{include:Condition}
:匹配特定条件,一般是提供一个字符串或者字符串数组。
{exclude:Condition}
:排除特定条件。一般是提供一个字符串或字符串数组。
{and: [Condition]}
:必须匹配数组中的所有条件。
{ or: [Condition] }
: 匹配数组中任何一个条件。
{ not: [Condition] }
: 必须排除这个条件。
module: {
rules: [
{
test: /\.css$/,
include: [
path.resolve(__dirname, "app/styles"),
path.resolve(__dirname, "src/styles")
],
use: ['style-loader', 'css-loader']
}
]
}
告诉模块要使用哪个loader。若有多个loader的话,从右向左(从下到上)进行应用。
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
}
];
原本,webpack是只能处理javascript文件的,但这样的话,岂不是很不爽?! 所以,loader来了,它能让webpack去处理非javascript文件
。
简单理解,loader将所有类型的文件(如css、scss、png、jpg、…等类型)进行转换,转换为webpack能处理的模块。
如css-loader
转换css文件 :
使用前先安装 npm i -D css-loader
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
sourceMap: true
}
}
]
}
如果将loader理解为转换某些类型的模块,那么plugins能处理的任务可不止这些。如打包、压缩,定义环境变量…插件能用来处理各种各样的任务。
npm i -D style-loader css-loader
const path = require('path');
module.exports = {
entry: {
app:'./src/index.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] //从右向左应用到模块
}
]
}
};
.c-red {color:red;}
import _ from 'lodash';
import './style.css'
let createDomElement = ()=>{
let dom = document.createElement('div');
dom.innerHTML = _.join(['https://','blog','.csdn','.net','/imaginecode'],'');
dom.className = 'c-red';
return dom;
}
document.body.appendChild(createDomElement());
npm i -D sass-loader node-sass webpack
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
sourceMap: true //利于开发调式,定位文件
}
}, {
loader: "sass-loader",
options: {
sourceMap: true
}
}]
}]
}
postcss 可以利用为CSS3属性添加前缀的方式实现CSS的模块化,防止样式冲突。这也是常用的方式。 参考文档:
https://postcss.org/
npm i -D postcss-loader autoprefixer
...
const autoprefixer = require('autoprefixer');
...
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: loader => [
require('autoprefixer')({ browsers: ['> 0.15% in CN'] }) // 添加前缀
]
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
}
]
}
注意:抽取样式后,就不会使用style-loader注入css到HTML了。
npm i -D mini-css-extract-plugin
...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
...
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader, //抽取样式
'css-loader',
'postcss-loader',
'sass-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash].css', // 设置最终输出的文件名
chunkFilename: '[id].[hash].css'
})
]
此时,可以运行npm run build 或 npx webpack
看结果
npm i -D optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin
...
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
...
plugins:[
...
],
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
],
minimizer: [new OptimizeCSSAssetsPlugin({})]
}
npm i -D html-webpack-plugin
...
const HtmlWebpackPlugin = require('html-webpack-plugin');
...
plugins: [
...
new HtmlWebpackPlugin({
minify: { //压缩html配置,在development模式下先不进行压缩,到production下再进行
collapseWhitespace: false,
removeComments: false,
removeAttributeQuotes: false // 移除属性的引号
}
})
],
optimization: {
...
}
npm i -D clean-webpack-plugin
...
const CleanWebpackPlugin = require('clean-webpack-plugin');
...
let pathsToClean = [
'dist/*.js',
'dist/*.css',
'dist/*jpg',
]
let cleanOptions = {
root: '',
exclude: ['index.html'],
verbose: true,
dry: false
}
plugins: [
new CleanWebpackPlugin(pathsToClean,cleanOptions), //构建前清除dist文件夹
...
],
npm i -D file-loader image-webpack-loader url-loader
module: {
rules: [
...
{
test: /\.(png|svg|jpg|gif|jpeg|ico|woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'url-loader', // 根据图片大小,把图片优化成base64
options: {
limit: 10000
}
},
{
loader: 'image-webpack-loader',// 先进行图片优化
options: {
name: 'dist/[name].[ext]',
mozjepg:{
progressive: true,
quality: 65
},
optipng: {
enabled: false,
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false,
},
webp: {
quality: 75
}
}
}
]
}
]
}
inline-source-map
module.exports = {
...
devtool: 'inline-source-map',
...
}
监控变化,执行命令:npx watch
热更新
npm i -D webpack-dev-server
module.exports = {
...
devServer: {
contentBase: './dist', //文件变化后,自动打包更新到dist目录
hot: true //启用热更新
}
...
}
webpack-dev-server --open
devServer: {
clientLogLevel: 'warning', // 可能的值有 none, error, warning 或者 info(默认值)
hot: true, // 启用 webpack 的模块热替换特性, 这个需要配合: webpack.HotModuleReplacementPlugin插件
contentBase: path.join(__dirname, "dist"), // 告诉服务器从哪里提供内容, 默认情况下,将使用当前工作目录作为提供内容的目录
compress: true, // 一切服务都启用gzip 压缩
host: '0.0.0.0', // 指定使用一个 host。默认是 localhost。如果你希望服务器外部可访问 0.0.0.0
port: 8080, // 端口
open: true, // 是否打开浏览器
overlay: { // 出现错误或者警告的时候,是否覆盖页面线上错误消息。
warnings: true,
errors: true
},
publicPath: '/', // 此路径下的打包文件可在浏览器中访问。
proxy: { // 设置代理
"/api": { // 访问api开头的请求,会跳转到 下面的target配置
target: "http://192.168.0.102:8080",
pathRewrite: {"^/api" : "/mockjsdata/5/api"}
}
},
quiet: true, // necessary for FriendlyErrorsPlugin. 启用 quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。
watchOptions: { // 监视文件相关的控制选项
poll: true, // webpack 使用文件系统(file system)获取文件改动的通知。在某些情况下,不会正常工作。例如,当使用 Network File System (NFS) 时。Vagrant 也有很多问题。在这些情况下,请使用轮询. poll: true。当然 poll也可以设置成毫秒数,比如: poll: 1000
ignored: /node_modules/, // 忽略监控的文件夹,正则
aggregateTimeout: 300 // 默认值,当第一个文件更改,会在重新构建前增加延迟
}
}
npm i -D babel-loader babel-core babel-preset-env babel-plugin-transform-runtime babel-runtime
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/, // 加快编译速度,不包含node_modules文件夹内容
use: {
loader: 'babel-loader'
}
}
]
{
"presets": ["env"]
}
最后,你可以在index.js文件中写一些ES6语法运行试试。
raw-loader
加载文件原始内容(utf-8)val-loader
将代码作为模块执行,并将 exports 转为 JS 代码url-loader
像 file loader 一样工作,但如果文件小于限制,可以返回 data URLfile-loader
将文件发送到输出文件夹,并返回(相对)URLhtml-loader
导出 HTML 为字符串,需要引用静态资源pug-loader
加载 Pug 模板并返回一个函数jade-loader
加载 Jade 模板并返回一个函数markdown-loader
将 Markdown 转译为 HTMLreact-markdown-loader
使用 markdown-parse parser(解析器) 将 Markdown 编译为 React 组件posthtml-loader
使用 PostHTML 加载并转换 HTML 文件handlebars-loader
将 Handlebars 转移为 HTMLmarkup-inline-loader
将内联的 SVG/MathML 文件转换为 HTML。在应用于图标字体,或将 CSS 动画应用于 SVG 时非常有用。style-loader
将模块的导出作为样式添加到 DOM 中css-loader
解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码less-loader
加载和转译 LESS 文件sass-loader
加载和转译 SASS/SCSS 文件postcss-loader
使用 PostCSS 加载和转译 CSS/SSS 文件stylus-loader
加载和转译 Stylus 文件mocha-loader
使用 mocha 测试(浏览器/NodeJS)eslint-loader PreLoader
,使用 ESLint 清理代码jshint-loader PreLoader
,使用 JSHint 清理代码jscs-loader PreLoader
,使用 JSCS 检查代码样式coverjs-loader PreLoader
,使用 CoverJS 确定测试覆盖率vue-loader
加载和转译 Vue 组件polymer-loader
使用选择预处理器(preprocessor)处理,并且 require()
类似一等模块(first-class)的 Web 组件angular2-template-loader
加载和转译 Angular 组件Awesome
更多第三方 loader,查看 awesome-webpack 列表。const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');
const autoprefixer = require('autoprefixer');
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
devtool: 'inline-source-map',
devServer: {
clientLogLevel: 'warning', // 可能的值有 none, error, warning 或者 info(默认值)
hot: true, // 启用 webpack 的模块热替换特性, 这个需要配合: webpack.HotModuleReplacementPlugin插件
contentBase: path.join(__dirname, "dist"), // 告诉服务器从哪里提供内容, 默认情况下,将使用当前工作目录作为提供内容的目录
compress: true, // 一切服务都启用gzip 压缩
host: '0.0.0.0', // 指定使用一个 host。默认是 localhost。如果你希望服务器外部可访问 0.0.0.0
port: 8085, // 端口
open: true, // 是否打开浏览器
overlay: { // 出现错误或者警告的时候,是否覆盖页面线上错误消息。
warnings: true,
errors: true
},
publicPath: '/', // 此路径下的打包文件可在浏览器中访问。
proxy: { // 设置代理
"/api": { // 访问api开头的请求,会跳转到 下面的target配置
target: "http://192.168.0.102:8080",
pathRewrite: {
"^/api": "/mockjsdata/5/api"
}
}
},
quiet: true, // necessary for FriendlyErrorsPlugin. 启用 quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。
watchOptions: { // 监视文件相关的控制选项
poll: true, // webpack 使用文件系统(file system)获取文件改动的通知。在某些情况下,不会正常工作。例如,当使用 Network File System (NFS) 时。Vagrant 也有很多问题。在这些情况下,请使用轮询. poll: true。当然 poll也可以设置成毫秒数,比如: poll: 1000
ignored: /node_modules/, // 忽略监控的文件夹,正则
aggregateTimeout: 300 // 默认值,当第一个文件更改,会在重新构建前增加延迟
}
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/, // 加快编译速度,不包含node_modules文件夹内容
use: [{
loader: 'babel-loader'
},{
loader: 'eslint-loader',
options: {
fix: true
}
}]
},
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader', {
loader: 'css-loader',
options: {
sourceMap: true
}
}, {
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: (loader) => [autoprefixer({browsers: ['> 0.15% in CN']})]
}
}, {
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
}, {
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000
}
}
]
}, {
test: /\.(png|svg|jpg|gif|jpeg|ico)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000
}
}, {
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false
},
webp: {
quality: 75
}
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({filename: '[name].css', chunkFilename: '[id].css'}),
new CleanWebpackPlugin(['dist']),
new webpack.NamedModulesPlugin(), // 更容易查看(patch)的依赖
new webpack.HotModuleReplacementPlugin(), // 替换插件
new HtmlWebpackPlugin({
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true, // 移除属性的引号
},
template: path.resolve(__dirname, 'src/index.html')
})
],
optimization: {}
};
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/, // 加快编译速度,不包含node_modules文件夹内容
use: [{
loader: 'babel-loader'
},{
loader: 'eslint-loader',
options: {
fix: true
}
}]
},
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader, {
loader: 'css-loader'
}, {
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: (loader) => [autoprefixer({browsers: ['> 0.15% in CN']})]
}
}, {
loader: 'sass-loader'
}
]
}, {
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000
}
}
]
}, {
test: /\.(png|svg|jpg|gif|jpeg|ico)$/,
use: [
'file-loader', {
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false
},
webp: {
quality: 75
}
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({filename: '[name][hash].css', chunkFilename: '[id][hash].css'}),
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src/index.html'),
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true, // 移除属性的引号
}
})
],
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true, parallel: true, sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
}
};
你可以通过npx webpack --config webpack.dev.js
或npx webpack --config webpack.prodjs
在构建时执行不同环境下的配置文件。当然,你最好是在package.json文件中添加脚本来便捷执行:
"scripts":{
"dev":"npx webpack --config webpack.dev.js",
"prod":"npm webpack --config webpack.prod.js"
}
以后只需执行:npm run dev
或npm run prod