loader处理顺序
css文件经过loader的处理流程:
['style-loader', 'css-loader'],从右向左执行的
-
1.先读出源文件 index.css
-
2.把文件内容传递给css-loader,css-loader可以处理css中的@import和url语法,处理完之后会把内容传递给style-loader
-
3.style-loader的作用是把CSS转换成style标签插入页面中
基础配置
以较为友好的方式显示打包后的文件,设置mode、devtool两个参数
mode: 'development',//none production development
//指定项目打包的入口
entry: './src/index.js',
output: {
//指定输出的目录,默认是dist目录,目录的配置必须是一个绝对路径而非相对路径
path: path.resolve(__dirname, 'dist'),
//指定的是文件名,默认是main.js
filename: 'main.js'
},
devtool: false,
output的path必须是一个绝对路径
模式(mode)
- 日常的前端开发工作中,一般都会有两套构建环境
- 一套开发时使用,构建结果用于本地开发调试,不进行代码压缩,打印 debug 信息,包含 sourcemap 文件
- 一套构建后的结果是直接应用于线上的,即代码都是压缩后,运行时不打印 debug 信息,静态文件不包括 sourcemap
- webpack 4.x 版本引入了 mode 的概念
- 当你指定使用 production mode 时,默认会启用各种性能优化的功能,包括构建结果优化以及 webpack 运行性能优化
- 而如果是 development mode 的话,则会开启 debug 工具,运行时打印详细的错误信息,以及更加快速的增量编译构建
| 选项 | 描述 |
|---|---|
| development | 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin |
| production | 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin |
\
webpack指令在执行时可以添加若干参数:
--mode用来设置模块内的process.env.NODE_ENV
--env用来设置webpack配置文件的函数参数
\
package.json文件里,在很多的script命令中,会添加cross-env,它的作用是用来设置node环境的process.env.NODE_ENV,且可以自动识别当前环境(mac linux windows)
设置环境变量的方式在windows和mac里不一样:
windows set Key=Value:set NODE_ENV=development webpack
Mac Key=Value:NODE_ENV=development webpack
\
需要注意node环境中的process.env.NODE_ENV和我们平时写的js(在浏览器环境中运行的代码)里面的process.env.NODE_ENV完全不同,后者相当于是浏览器里面定义的一个字符串token,webpack等打包工具会识别出这个token并做替换
这个工作,通常是由DefinePlugin插件来做
如果命令行中增加了mode参数,webpack.config.js也添加了mode参数,其优先级为:
默认优先级(production) < 配置文件webpack.config.js里的mode < package.json中的--mode的配置
webpack的config在导出时,除了可以以一个json的形式导出之外,还可以导出一个function,返回config作为其结果:
console.log('process.env.NODE_ENV', process.env.NODE_ENV)
module.exports = (env) => {
return {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',//none production development
//指定项目打包的入口
entry: './src/index.js',
output: {
//指定输出的目录,默认是dist目录,目录的配置必须是一个绝对路径而非相对路径
path: path.resolve(__dirname, 'dist'),
//指定的是文件名,默认是main.js
filename: 'main.js'
},
devtool: 'source-map',
module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': process.env.NODE_ENV
})
]
}
}
上述代码中的process.env.NODE_ENV就是package.json中script里通过cross-env定义的环境变量,除此之外,plugins里面的DefinePlugin也可以使用process来获取其值,因此定义执行模式通常通过cross-env这种方式,而不是写死一个mode参数
开发环境配置
devServer: {
port: 8080,
open: true
}
再在package.json中添加一个脚本dev:
"scripts": {
"build": "webpack",
"dev": "webpack serve"
},
样式相关配置
less 用于把less编译成CSS
less-loader
node-sass 用于把sass编译成CSS
sass-loader
由于sass需要通过ruby来装,因此出错概率较高,目前会采用dart-sass取代node-sass
css-loader参数:
如果要给css-loader传参,需要在loaders中写成对象格式
{
loader: 'css-loader',
options: {
url: true,//启用/禁用url解析 url(./kf.jpg);
import: true, //是否允许或者说禁 用@import语法处理 @import "base.css";
modules: false,// 是否允许 CSS 模块化
sourceMap: false,//是否生成sourcemap
importLoaders: 0, //允许或者说启动几个数量的loaders应用在import 的文件
esModule: false //默认情况下,css-loader生成使用ES Module的模块对象,如果你赋false的话,不包装成ESMODULES
}
},
- url: Enable/disable url() resolving.
- import: Allows to enables/disables @import at-rules handling
- modules: Allows to enable/disable CSS Modules or ICSS and setup configuration
- sourceMap: By default generation of source maps depends on the devtool option
- importLoaders: Allows to enables/disables or setups number of loaders applied before CSS loader for @import at-rules
- esModule: By default, css-loader generates JS modules that use the ES modules syntax. There are some cases in which using ES modules is beneficial
node_modules下文件的引入
//为了引入node_modules下面的资源文件,比如说bootstrap,可以添加 ~前缀
background-image: url(~image/kf.jpg);
给css类增加浏览器前缀
首先要安装postcss-preset-env这个包,并添加postcss.config.js
let postcssPresetEnv = require('postcss-preset-env');
module.exports = {
plugins: [
postcssPresetEnv({
browsers: 'last 5 version'
})
]
}
然后在webpack.config.js的module.rules里面添加postcss相关的配置
{
test: /.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
url: true,//启用/禁用url解析 url(./kf.jpg);
import: true, //是否允许或者说禁 用@import语法处理 @import "base.css";
modules: false,// 是否允许 CSS 模块化
sourceMap: false,//是否生成sourcemap
importLoaders: 0, //允许或者说启动几个数量的loaders应用在import 的文件
esModule: false //默认情况下,css-loader生成使用ES Module的模块对象,如果你亩false的话,不包装成ESMODULES
}
},
'postcss-loader',
path.resolve(__dirname, 'loaders', 'loader1.js'),
path.resolve(__dirname, 'loaders', 'loader2.js'),
path.resolve(__dirname, 'loaders', 'loader3.js')
]
},
{
test: /.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1
}
},
'postcss-loader',
'less-loader'
]
}, {
test: /.scss$/,
use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader']
},
还要在package.json中配置开发、生产环境中分别需要兼容的浏览器版本:
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%"
]
},
webpack中图片的处理
// webpack4 关于图片需要 使用file-loader url-loader
// webpack5 不再需要,而改用asset/resource和asset/inline,分别替代file-loader url-loader
{
test: /.(jpg|png|bmp|gif)/,
type: 'asset/resource',
generator: {
filename: '[hash][ext]'
}
}
file-loader=>asset/resource 把图片拷贝到输出目录里去,返回一个输出后的路径,包括文件
url-loader=>asset/inline 不拷贝文件,直接把源文件变成base64字符串内嵌到输出结果
css-loader的参数:importLoaders
允许或者说启动几个数量的loaders应用在import 的文件
例如下面的代码,importLoaders设置为了2,那么会从设置importLoaders的这一项(即css-loader这个对象)开始,往下找两个loader(此处就是postcss-loader和loader1),来对文件中从外部import进来的css进行解析(注意只有import的文件会受此影响,直接被引入页面的css不受该参数影响)
这个功能的出现是为了import引入的文件有可能会引各种类型的文件,例如css文件中引了less或scss,就可以通过这个参数来控制,但实际使用场合用的较少
{
test: /.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
url: true,//启用/禁用url解析 url(./kf.jpg);
import: true, //是否允许或者说禁 用@import语法处理 @import "base.css";
modules: false,// 是否允许 CSS 模块化
sourceMap: false,//是否生成sourcemap
importLoaders: 2, //允许或者说启动几个数量的loaders应用在import 的文件
esModule: false //默认情况下,css-loader生成使用ES Module的模块对象,如果你亩false的话,不包装成ESMODULES
}
},
'postcss-loader',
path.resolve(__dirname, 'loaders', 'loader1.js'),
path.resolve(__dirname, 'loaders', 'loader2.js'),
path.resolve(__dirname, 'loaders', 'loader3.js')
]
},
vscode插件:rm-js-comment,删除代码中所有注释
对于比较常见的组件,很多页面都需要import,为了避免这些频繁的import,可以通过ProvidePlugin进行简化:
new webpack.ProvidePlugin({
isarray: 'isarray'
})
相当于自动添加了import isarray from 'isarray'
但需要注意,ProvidePlugin里面自动import的东西并不是全局变量,所以在非模块环境下是不可以拿到isarray的
通过expose-loader添加全局变量
如果想要在window上挂载全局变量,需要用expose-loader
{
test: /isarray/,
use: [
{
loader: 'expose-loader',
options: {
exposes: {
globalName: 'isarray',
// 如果window上已经有了isarray这个变量,则直接覆盖
override: true
}
}
}
]
},
// require('isarray')引用一次以后就把isarray变量挂到了全局对象window上
let isarray = require('isarray');
let title = require('./title');
// title文件里可以直接用window.isarray
externals
externals: {
lodash: '_'
},
lodash将不会参与打包,而且我们需要手动在HTML中添加lodash的引入(可以以cdn方式引入),但在项目中依然可以通过import或require引用,原理是webpack会生成一个模块,这个模块会在window上添加变量_,这个_变量将指向lodash:
(function () {
var modules = ({
"lodash":
(function (module) {
module.exports = window._;
})
});
var cache = {};
function require(moduleId) {
var cachedModule = cache[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
var module = cache[moduleId] = {
exports: {}
};
modules[moduleId](module, module.exports, require);
return module.exports;
}
var exports = {};
!function () {
let lodash = require("lodash");
console.log(lodash);
}();
})()
开发服务器
devServer: {
port: 8080,//配置开发预览服务器的端口号8080
open: true,//打包后会自动打开浏览器
/* proxy: {
//把访问路径是以/api开头的请求都转发到http://localhost:3000
'/api': {
target: 'http://localhost:3000',//重定向的域名
pathRewrite: { //重写的路径
"^/api": ""
}
}
} */
//在 webpack-dev-server静态资源中间件处理之前,可以用于拦截部分请求返回特定内容,以实现简单的mock
// webpack5中使用
onBeforeSetupMiddleware({ app }) {
app.get('/api/users', (req, res) => {
res.json([{ id: 1, name: "张三" }, { id: 2, name: "李四" }]);
});
}
},
开发服务器原理简要介绍
let express = require('express');
//得到app应用对象
const app = express();
app.get('/api/users', (req, res) => {
res.json([{ id: 1, name: "张三" }, { id: 2, name: "李四" }]);
});
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('./webpack.config');
//compiler就是编译大管家
const compiler = webpack(config);
//webpackDevMiddleware会返回一个中间件
//中间件负责根据配置文件打包当前的项目并且返回打包后的结果
//中间件有两件工作
//1.负责打包
//2.返回打包后的静态文件 index.html main.js
app.use(webpackDevMiddleware(compiler));
app.listen(3000);
\