初始化项目
mkdir new-webpack-react
cd new-webpack-react
npm init
安装webpack
npm install --save-dev webpack webpack-cli
备注: npm 的各种简写的意义:
- -i 相当于 install -s
- -S就是--save的简写,将包的名称及版本号放在dependencies里面,dependencies 是需要发布到生产环境的
- -D就是--save-dev 这样安装的包的名称及版本号就会存在package.json的devDependencies这个里面。 devDependencies 里面的插件只用于开发环境,不用于生产环境
配置文件webpack.config.js的配置
1.首先明确 webpack的配置文件需要的几个配置:
- 配置入口(entry)
- 配置出口(output)
- 配置各种资源加载的loader
- 插件(plugins ),解决 loader 无法实现的其他事
- 解析器(resolve),
- 使用HtmlWebpackPlugin将打包后的js入口文件的脚本注入到html模板中
const path = require('path'),
htmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
/* entry的值有三种类型 : 1.字符串,2.数组, 3.对象 ,
数组 多个入口文件时,使用数组的方式,比如依赖第三方库 bootstrap ,最终 bootstrap 会被追加到打包好的 index.js 中,数组中的最后一个会被 export
对象 设置多个打包目标。每一对键值对都对应着一个入口文件。常用语多页面入口文件配置
*/
entry: path.resolve(__dirname, '../src/index.js'), // 打包的入口文件
output: {
filename: '[name].index.js', // 输出文件名称,自己设置的js路径
chunkFilename: 'chunk/[name].[hash].js', // chunkFilename 按需加载,生成块状文件
path: path.resolve(__dirname, '../dist'), // 输出文件位置
publicPath: '' // 静态资源的路径前缀
},
plugins: [
/* HtmlWebpackPlugin这个插件的作用是依据一个简单的index.html模板,生成一个自动引用你打包后的JS文件的新index.html */
new htmlWebpackPlugin({
template: path.resolve(__dirname, '../template/index.html')
// 设置favicon的路径
// favicon: './src/assets/favicon-32x32-next.png'
})
]
}
packagejson文件配置命令并执行,可以看到dist文件夹下生成了main.923dea72093bed3467ee文件
"scripts": {
"start": "webpack --config build/webpack.config.js"
// "start": "webpack"
},
备注: 如果webpack.config.js存在在根目录里, 则webpack命令将默认选择使用它.
也可以使用 webpack --config webpack.config.js 命令来指定配置文件
- 配置一些常用的loader,css,js等
安装 npm install --save-dev style-loader css-loader less-loader sass-loader less file-loader
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader', // creates style nodes from JS strings
'css-loader', // translates CSS into CommonJS
'sass-loader' // compiles Sass to CSS, using Node Sass by default
]
},
{
test: /\.less$/,
use: [
{loader: 'style-loader'},
{loader: 'css-loader'},
{loader: 'less-loader',
options: { javascriptEnabled: true, modifyVars: themeVariables } // modifyVars 全局覆盖的样式,例:antd的定制全局覆盖样式
}
]
},
{
test: /\.css$/,
use: [devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)(\?\S*)?$/,
use: [
{
loader: 'file-loader',
options: {
// name: '[name].[ext]' // name也可以为一个函数
name(file) {
if (devMode) {
return '[name].[hash].[ext]'
}
return '[name].[ext]'
}
},
exclude: /node_modules/
}
]
}
]
}
js 编译, 使用babel编译javascript: cnpm install --save-dev babel-core babel-loader babel-plugin-import babel-plugin-transform-class-properties babel-plugin-transform-decorators-legacy babel-plugin-transform-runtime babel-polyfill babel-preset-env babel-preset-es2015 babel-preset-stage-0 babel-preset-stage-1
编译react代码可以安装 babel-preset-react react-hot-loader
根目下新建 .babelrc文件
{
"presets": ["es2015", "react", "stage-1"],
"plugins": [
"transform-runtime",
"transform-decorators-legacy",
"transform-class-properties",
"react-hot-loader/babel",
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "es",
"style": true
}
]
]
/* transform-runtime: 解决编译中产生的重复的工具函数,减小代码体积
* transform-remove-console: 编译后的代码都会移除console.,可在webpack中配置
* transform-decorators-legacy: 装饰器配置 @
* transform-class-properties: class属性转换
* react-hot-loader:热更新
* 执行顺序: 先编译plugins里边的配置
*/
在webpack.config.js的rules 增加js、jsx的编译器
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
接下来做一些插件的优化(plugins)
一、HtmlWebpackPlugin配置优化
HtmlWebpackPlugin各属性配置详解:
title:生成html文件的标题
filename:输出的html的文件名称
template:html模板所在的文件路径
inject:注入选项。有四个选项值 true, body, head, false.
- true:默认值,script标签位于html文件的 body 底部
- body:script标签位于html文件的 body 底部(同 true)
- head:script 标签位于 head 标签内
- false:不插入生成的 js 文件,只是单纯的生成一个 html 文件
minify: 对 html 文件进行压缩,minify 的属性值是一个压缩选项或者 false 。默认值为false, 不对生成的 html 文件进行压缩。
new HtmlWebpackPlugin({
// 打包输出HTML
title: 'Hello World app',
minify: {
// 压缩HTML文件
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true // 压缩内联css
},
filename: 'index.html',
template: path.resolve(__dirname, '../template/index.html')
})
二、clean-webpack-plugin
cnpm install --save-dev clean-webpack-plugin 如果安装3.0 以上版本,引入方法和之前不一样 3.0版本之前:
const CleanWebpackPlugin = require('clean-webpack-plugin')
plugins:[
new CleanWebpackPlugin(['dist'])
]
3.0版本之后:
const { CleanWebpackPlugin } = require('clean-webpack-plugin'),
plugins:[
new CleanWebpackPlugin(), // 备注:不用传需要clean的文件
]
三,happypack cnpm install happypack --save-dev
原因:运行在 Node.js 之上的 Webpack 是单线程模型的,所以Webpack 需要处理的事情需要一件一件的做,不能多件事一起做,我们需要Webpack 能同一时间处理多个任务,发挥多核 CPU 电脑的威力,HappyPack 就能让 Webpack 做到这点,它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
并且由于 JavaScript 是单线程模型,要想发挥多核CPU的能力,只能通过多进程去实现,而无法通过多线程实现。
由于HappyPack 对file-loader、url-loader支持的不友好,所以不建议对该loader使用。
修改webpack.config.js文件:
const HappyPack = require('happypack');
const os = require('os');
<!--线程数,改为电脑核数-->
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: 'happypack/loader?id=happyBabel', //把对.js 的文件处理交给id为happyBabel 的HappyPack 的实例执行
exclude: /node_modules/ //排除node_modules 目录下的文件
},
]
},
plugins: [
new HappyPack({
id: 'happyBabel', //用id来标识 happypack处理那里类文件
loaders: [{
loader: 'babel-loader', //如何处理 用法和loader 的配置一样
}],
threadPool: happyThreadPool, //共享进程池
verbose: true, //允许 HappyPack 输出日志
})
]
}
四、progress-bar-webpack-plugin 编译进度条插件
可在命令行里看到编译时的进度
const ProgressBarPlugin = require(progress-bar-webpack-plugin)
new ProgressBarPlugin({
format: ' build [:bar] ' + chalk.green.bold(':percent') + ' (:elapsed seconds)'
}),
五、mini-css-extract-plugin npm install --save-dev mini-css-extract-plugin
将CSS提取为独立的文件的插件,对每个包含css的js文件都会创建一个CSS文件,支持按需加载css和sourceMap
- 异步加载
- 不重复编译,性能更好
- 只针对css
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
{
test: /\.css$/,
use: [devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader']
},
new MiniCssExtractPlugin({
filename: devMode ? '[name].[hash:4].css' : '[name].[contenthash].css',
chunkFilename: devMode ? '[id].[hash:4].css' : '[id].[contenthash].css',
})
六、 webpack.DefinePlugin
创建一个在编译时可以配置的全局变量,主要针对在编译时,区分开发,测试,生产环境。
因为nodejs里的环境变量process.env.NODE_ENV 只能在node环境里拿到,而 webpack.DefinePlugin提供的变量可以在浏览器环境里拿到
new webpack.DefinePlugin({
'gropuPcApiType': {
ENV: JSON.stringify(process.env.ENV)
}
})
index.js:
console.log('gropuPcApiType', gropuPcApiType)
上边代码在浏览器环境里提供了一个名为“gropuPcApiType” 的变量,可通过js 获取到定义的该变量,获取到的值为启动环境时的值:即:development 或者development
七、case-sensitive-paths-webpack-plugin
强制执行所有必须模块的整个路径,匹配磁盘上实际路径的确切大小写。即可以忽略大小写的问题,避免大小写问题引起的麻烦。有时你会发现 Mac 上 webpack 编译没有问题,但是到 linux 机器上就不行了,这是因为 Mac 系统是大小写不敏感 的,避免的办法是使用 case-sensitive-paths-webpack-plugin 模块
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
new CaseSensitivePathsPlugin()
八、NamedModulesPlugin
在热加载时,直接返回更新文件的文件名 而不是id,一般用于生产环境:
new webpack.HotModuleReplacementPlugin(),