webpack 中loader
的作用是把不是 js 编译成 js 文件。比如,在开发 vue 项目的时候,写的全部是.vue结尾的文件,这种文件是无法运行在浏览器中的,因此需要vue-loader
转换成 js 文件。下面我们来演示如果通过 css-loader 打包 css 文件的。
创建项目
- npm init 初始化项目
- 创建 src/index.js
- 创建 public/index.html
- 创建 webpack.config.js,并写入配置
- 执行 npm install -D webpack webpack-cli
- 配置 build 命令为 webpack
- 执行 npm run build
主要代码如下:
webpack.config.js
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'bundle.js'
}
}
index.html 和 index.js
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>webpack</title>
<script src="../dist/bundle.js"></script>
</head>
<body></body>
</html>
// index.js
console.log('hello webpack')
packge.json
"scripts": {
"build": "webpack"
},
执行npm run build
,生成 bundle.js 文件,代码精简后如下:
;(() => {
// 所有的模块都放在__webpack_modules__对象中
var __webpack_modules__ = {
'./src/index.js': () => {
console.log('hello webpack')
)
}
}
// 定义了一个输出,现在入口文件是没有输出的
var __webpack_exports__ = {}
// 执行index.js,打印 hello webpack
__webpack_modules__['./src/index.js']()
})()
利用 css-loader 解析 css 文件
当在入口文件引入css之后,代码如下:
// index.css
.test {
width: 100px;
height: 100px;
background-color: rebeccapurple;
}
// index.js
import './index.css'
console.log('hello webpack')
// index.html
<body>
<div class="test"></div>
</body>
如果这个时候直接执行打包操作,会报错。
这是因为 webpack 不能识别 css 文件,所以需要安装css-loader,配置文件如下:
module.exports = {
mode: 'development',
entry: './src/index.js',
devtool: 'source-map',
output: {
path: path.resolve(__dirname, './dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['css-loader']
}
]
}
}
执行npm run build
,打包后运行发现浏览器没有显示div的样式,这是什么原因呢?接下来,分析下打包后的文件 bundle.js。
通过对 bundle.js 代码精简后如下:
;(() => {
'use strict'
var __webpack_modules__ = {
'./src/index.css': (module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.d(__webpack_exports__, {
default: () => __WEBPACK_DEFAULT_EXPORT__
})
var ___CSS_LOADER_EXPORT___ = []
// Module
___CSS_LOADER_EXPORT___.push([
module.id,
'.test {\n width: 100px;\n height: 100px;\n background-color: rebeccapurple;\n}\n'
])
const __WEBPACK_DEFAULT_EXPORT__ =
___CSS_LOADER_EXPORT___
}
}
var __webpack_module_cache__ = {}
function __webpack_require__(moduleId) {
// Check if module is in cache
var cachedModule = __webpack_module_cache__[moduleId]
if (cachedModule !== undefined) {
return cachedModule.exports
}
// Create a new module (and put it into the cache)
var module = (__webpack_module_cache__[moduleId] = {
id: moduleId,
// no module.loaded needed
exports: {}
})
// Execute the module function
__webpack_modules__[moduleId](module, module.exports, __webpack_require__)
// Return the exports of the module
return module.exports
}
var __webpack_exports__ = {}
;(() => {
// 入口文件
var _index_css__WEBPACK_IMPORTED_MODULE_0__ =
__webpack_require__('./src/index.css')
console.log('hello webpack')
})()
})()
入口文件 index.js 经过 webpack 编译后变成了如下代码:
__webpack_require__.r(__webpack_exports__)
var _index_css__WEBPACK_IMPORTED_MODULE_0__ =
__webpack_require__('./src/index.css')
console.log('hello webpack')
可以发现 import './index.css'
变成了 var _index_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__('./src/index.css')
,其中 __webpack_require__
就类似于nodejs 中的 require
方法,在这里 webpack 实现了一个require
方法。
function __webpack_require__(moduleId) {
// moduleId就是文件路径,也就是 './src/index.css'
// 首先查找缓存
var cachedModule = __webpack_module_cache__[moduleId]
if (cachedModule !== undefined) {
return cachedModule.exports
}
// 如果没有缓存,那么生成一个module对象,这个对象包含一个id和exports对象
var module = (__webpack_module_cache__[moduleId] = {
id: moduleId,
exports: {}
})
// 执行 __webpack_modules__对象里面 key 为 './src/index.css'的值,即一个函数,在这个函数里面,把module和__webpack_require__传入
__webpack_modules__[moduleId](module, module.exports, __webpack_require__)
// 最后返回module
return module.exports
}
那现在看看 index.css 编译后的代码:
(module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.d(__webpack_exports__, {
default: () => __WEBPACK_DEFAULT_EXPORT__
})
var ___CSS_LOADER_EXPORT___ = []
// 把css文件放到___CSS_LOADER_EXPORT___数组中,如果引入了多个css文件,就都放里面
___CSS_LOADER_EXPORT___.push([
module.id, // id为文件路径
// css代码变为字符串
'.test {\n width: 100px;\n height: 100px;\n background-color: rebeccapurple;\n}\n'
])
const __WEBPACK_DEFAULT_EXPORT__ =
___CSS_LOADER_EXPORT___
}
我们可以把___CSS_LOADER_EXPORT___
打印出来:
经过上面的分析,index.css
文件最终转化字符串,然后放到_index_css__WEBPACK_IMPORTED_MODULE_0__
数组中,但是在index.js
中并没有使用这个数组,所以我们就看不到css样式效果,那怎么办呢?
那我们需要就需要安装style-loader
,这个loader的作用是把上面生成的_index_css__WEBPACK_IMPORTED_MODULE_0__
,转化为<style>标签插入到<head>中,这样样式就生效了。
下一节,我们将介绍style-loader
如何生成<style>标签并插入到<head>中的。