webpack是当前最流行的模块化,为了更好地理解和学习webpack,本文从零搭建基于webpack开发环境。
项目初始化
进入项目目录,生成package.json
文件。因为我们并不是要做一个工具库,所以可以将main
字段删除。main
字段的主要作用是,通过import
引入我们的程序,默认引入的具体文件。
npm init -y
// package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
配置package.json
执行文件
运行npm run start
之后,启动开发服务器,文件数据放在内存中,不会生成打包之后的dist文件。
运行npm run build
之后,执行打包命令,生成打包后的dist文件。
// package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC"
}
运行命令之前,需要先配置webpack。
安装webpack的依赖
npm i webpack webpack-cli webpack-dev-server -D
- 根目录下新建
webpack.config.js
文件, 该文件最终需要导出关于webpack的配置。可以是对象、函数或者Promise
。
配置入口(entry)
因为我们构建的是单页面应用,所以entry
的值可以是字符串,直接写入入口文件的相对路径。
// webpack.config.js
module.exports = {
entry: './src/main.js'
}
新建入口文件 /src/main.js
目录结构entry
的值也可以是对象,用来支持多页面应用的打包。我们在这里打包的是单页面应用,使用字符串的形式就足够了。
// webpack.config.js
module.exports = {
entry: {
home: "./home.js",
about: "./about.js",
contact: "./contact.js"
}
}
配置出口(output)
出口(ouput)决定了在什么位置输出、如何输出以及如何命名打包后的文件。
filename
中的[name]
是入口文件名称的占位符,是entry
是对象情况下的key,在entry
是字符串的时候,[name]
的值为main
。
类似的展位符还有[id]
内部chunk的id,[hash]
唯一hash值以及[chunkhash]
每个chunk内容生成的hash。
output
的参数还有很多,对于打包库文件比较有用的library
、libraryTarget
,具体使用可以查阅文档
// webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].bundle.js',
path: path.resolve('dist')
}
}
配置mode
mode
告知webpack的打包环境是开发环境(development)还是生产环境(production)。可以根据不同的mode
,运行不同的webpack配置。
在这里我们用npm
运行脚本的时候,通过NODE_ENV可以来设置环境变量。在webpack.config.js
获取之后,进行设置。
可以通过下面的形式对NODE_ENV进行设置。
// mac & linux
export NODE_ENV=production
// window
set NODE_ENV=production
为了解决平台兼容性的问题,可以使用cross-env
。
cnpm i cross-env -D
并更改package.json
。
// package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "cross-env NODE_ENV=development && webpack-dev-server",
"build": "cross-env NODE_ENV=production && webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {...}
}
并在webpack.config.js
中获取,并设置。
// webpack.config.js
...
const mode = process.env.NODE_ENV;
module.exports = {
entry: './src/main.js',
...
mode
}
配置sourceMap
sourceMap是一个源文件和打包之后文件的对应关系表。配置之前,所有的log信息的位置、行号都是对应打包之后的文件。只有配置之后,才能让log的信息显示正确的位置(源文件位置)。
sourceMap有很多种类型,为了构建效率,开发环境下推荐使用cheap-module-eval-source-map
,生产环境下可关闭。
// webpack.config.js
...
module.exports = {
entry: './src/main.js',
...
devtool: mode === 'development'
? 'cheap-module-eval-source-map'
: 'none'
}
下面是从webpack官网截取的不同种类source map的分类图。
source map配置loader
- 配置babe-loader
开发过程中,需要使用ES6的新特性提高开发效率。为了兼容低版本浏览器,需要引入babel将将ES6代码转换为低版本浏览器也能够识别的ES5代码。
npm i babel-loader @babel/core core-js@3 regenerator-runtime @babel/preset-env -D
// webpack.config.js
...
module.exports = {
entry: './src/main.js',
...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}
]
}
}
根目录下新建.babelrc
文件,并添加babel相关配置。
// .babelrc
{
"presets": [
[
"@babel/preset-env", {
"corejs": 3,
"useBuiltIns": "usage"
}
]
]
}
babel
的编译功能是依赖于babel
中的plugin
,preset
是plugin
的集合。
我们在这里配置了preset
,babel-preset-env
用于ES6转ES5, preset
的运行顺序是从下至上。如果我们要配置其他的preset
一定要注意配置顺序。
babel-preset-env
中,useBuiltIns
参数决定了babel
如何处理pollyfill
。值可以是usage
、entry
、false
,默认是false
。当设置useBuiltIns
参数时(不为false
),我们还需要引入core-js
。
当使用useBuiltIns: "entry"
时,在入口文件中一次性手动引入时,不推荐使用。
当使用useBuiltIns:“usage”
提取文件中所需的polyfill
在每个文件引入,每种polyfill
只会引入一次。
在package.json
中配置browserslist
,让babel编译成响应的版本。该配置对后面的postcss
同样有效。
// package.json
{
"name": "webpack-demo",
...
"browserslist": [
"iOS >= 7",
"Android > 4.1"
]
}
后续的loader
同样配置在module.rules
中,和babel-loader
同级。
- 配置eslint
eslint
一个用来识别 ECMAScript 并且按照规则给出报告的代码检测工具。
命令行输入npx eslint --init
,按照提示进行安装。
这样我们的eslint
就安装好了,添加package.json
的eslint代码检查命令。
// package.json
{
"name": "webpack-demo",
...
"scripts": {
"start": "cross-env NODE_ENV=development webpack-dev-server",
"build": "cross-env NODE_ENV=production webpack",
"lint": "eslint src"
},
...
}
在命令行中输入 npm run lint
,就可以运行eslint
检查代码了。为了更多的在webpack
中使用eslint
,需要安装eslint-loader
。
npm i eslint-loader -D
同时还要更改webpack.config.js
。
// webpack.config.js
...
module.exports = {
entry: './src/main.js',
...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [ 'babel-loader', 'eslint-loader' ]
}
]
}
}
- 配置css相关的loader
webpack
如果要引入非js文件,需要引入相应的loader才能识别。
除了必须的style-loader
和css-loader
之外,还引入了scss-loader
来解析scss
文件,以及postcss-loader
帮助我们更好的管理css。
npm i style-loader css-loader sass-loader node-sass postcss-loader autoprefixer -D
根目录下新建postcss.config.js
配置postcss,自动添加浏览器前缀,解决低版本浏览器的css兼容性问题。
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
// webpack.config.js
...
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
},
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
}
},
'postcss-loader'
]
}
...
- 配置图片相关的
url-loader
url-loader
可以让小于指定大小的图片转换为Base64直接在页面中引入,大于指定大小的图片拷贝到目标文件夹。
npm i url-loader -D
// webpack.config.js
...
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'url-loader',
options: {
name: '[name]_[hash].[ext]',
outputPath: 'images/',
limit: 10240
}
}
}
...
配置Plugin
- clean-webpack-plugin
每次打包之前,清楚原先的打包后的文件。
cnpm i clean-webpack-plugin -D
// webpack.config.js
...
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: './src/main.js',
...
plugins: [
new CleanWebpackPlugin()
]
}
- html-webpack-plugin
文件打包好之后,需要通过html引入,才能够在浏览器中渲染。
html-webpack-plugin
的template
参数指定了html模版位置。
cnpm i html-webpack-plugin -D
// webpack.config.js
...
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/main.js',
...
plugins: [
...
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
- 启用 HMR
启用 HMR之后,我们在更改代码时,只更改需要更改的组件,不会刷新页面,保留页面状态。
webpack
内置HMR
相关插件,所以我们要引入webpack
,并将HotModuleReplacementPlugin
插件加入配置,完成对js的 HMR
配置。
不需要担心css文件,因为style-loader
已经自动完成了。
// webpack.config.js
...
const webpack = require('webpack');
module.exports = {
entry: './src/main.js',
...
plugins: [
...
new webpack.HotModuleReplacementPlugin()
]
}
配置开发服务器
// webpack.config.js
...
module.exports = {
entry: './src/main.js',
...
devServer: {
hot: true, // 热更新
open: true, // 自动开启浏览器打开页面
port: 8080 // 端口号
}
}
配置解析(resolve)
配置默认拓展名 resolve.extensions,不加后缀也可以通过impot
引入到相应文件。
配置目录别名resolve.alias,方便找到常用目录。
// webpack.confgi.js
...
module.exports = {
entry: './src/main.js',
...
resolve: {
extensions: [ '.js', '.json' ],
alias: {
src: path.resolve(__dirname, 'src/')
}
}
}
配置优化(optimization)
代码分割
// webpack.config.js
...
module.exports = {
entry: './src/main.js',
...
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
网友评论