近来得闲,从新撸了一边webpack文档,将webpack的用法以及做用基本理清了脉络,虽然各大前端框架的生态系统愈来愈完善,每一个框架基本都搭配了一套标准的脚手架工具,可是那是搭配好的套餐,用起来虽然也还行,仍是总以为哪里不得劲儿,就像开车开了个自动档模式,不能根据本身的项目为所欲为的搭配功能。因此今天咱们就来好好啃一啃webpack,知其然也知其因此然。css
webpack的核心功能就是模块化打包,既然是打包就必定涉及到entry(入口)和output(出口),剩下的两个核心概念是loader(加载器)和plugin(插件)以及mode(模式)。html
entry和output就是字面意思上的入口和出口,就是打包过程中读取代码的入口以及编译输出文件。前端
mode有点相似于半自动挡模式:提供mode配置选项,webpack会使用相应模式的内置功能进行自动优化。就这么一句话就能够归纳了模式。至于在哪一种模式下,webpack会开启那些功能,能够看以下表:node
选项 | 描述 |
---|---|
development | 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。 |
production | 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin. |
loader是加载器,用于对模块的源代码进行转换。loader 能够将全部类型的文件转换为 webpack 可以处理的有效模块,而后你就能够利用 webpack 的打包能力,对它们进行处理。react
在 webpack 的配置中 loader 有两个目标:webpack
const config = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
};
复制代码
以上配置中,对一个单独的 module 对象定义了 rules 属性,里面包含两个必须属性:test 和 use。这告诉 webpack 编译器(compiler) 以下信息:git
“嘿,webpack 编译器,当你碰到「在 require()/import 语句中被解析为 '.txt' 的路径」时,在你对它打包以前,先使用 raw-loader 转换一下。”github
当你须要对各个文件转为webpack可以处理的有效模块时能够去loader列表选择一个合适的加载器web
插件则能够用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到从新定义环境中的变量。插件接口功能极其强大,能够用来处理各类各样的任务。 想要使用一个插件,你只须要 require() 它,而后把它添加到 plugins 数组中。多数插件能够经过选项(option)自定义。你也能够在一个配置文件中由于不一样目的而屡次使用同一个插件,这时须要经过使用 new 操做符来建立它的一个实例。 当你想用某些实现某些任务优化时能够去插件列表看没有现成的插件开箱即用,npm
这里有个例子能够说明loader以及plugin用法
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 经过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const config = {
...
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
复制代码
引入了HtmlWebpackPlugin插件自动生成一个HTML文件。
虽然webpack支持在命令行中手动敲下webpack-cli命中以构建文件,可是通常的项目要复杂的多, 因此webpack支持提供配置文件。这比在终端(terminal)中手动输入大量命令要高效的多。因此让咱们建立一个取代以上使用 CLI 选项方式的配置文件:
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
复制代码
这是一个最简单的配置文件,定义了输入文件与输出文件,读取并运行src下的index.js文件将生成的bundle.js输出到dist文件夹中。 有了这样的一个配置文件以后,有两中方式启动它
npx webpack --config webpack.config.js
这行命令表示以指定的webpack配置文件运行webpack命令若是 webpack.config.js 存在,则 webpack 命令将默认选择使用它。咱们在这里使用 --config 选项只是向你代表,能够传递任何名称的配置文件。这对于须要拆分红多个文件的复杂配置是很是有用。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
复制代码
如今,可使用 npm run build 命令,来替代咱们以前使用的 npx 命令。
谈谈我本身对webpack的理解,把webpack看做是要编织一条美丽的珍珠项链的话,那么配置文件则是项链的链子,而webpack中loader列表和插件列表则至关于原料库,咱们能够从原料库中挑出咱们所须要的珍珠,entry和output则是选择以及打磨这条项链的入口及出口。好了一切准备就绪了,咱们要学习的变成如何打造一条美丽的珍珠项链。首先是要学习如何打磨完美的入口和出口。而后咱们要学习应该在什么地方放上怎样的珠子,以及如何放上去。
如今咱们能够从简单到复杂一步一步来完成一个针对react的从0到1的配置文件:
1,初始化npm项目,生成package.json。
2,添加public/index.html。
3, 安装Babel,建立.babelrc进行配置。
4,安装react、react-dom、热更新react-hot-loader。
5,安装webpack,建立webpack.config.js进行配置。
6,添加src/index.js、src/App.js、src/App.css。
7,配置package.json,修改启动命令。
8,启动项目
建立一个新项目,并cd进入。
$ mkdir webpack-demo
$ cd webpack-demo
复制代码
建立package.json文件, 若是你想跳过初始化时的问题,加上 -y,以默认选项安装:
npm init -y
复制代码
mkdir public
cd public
touch index.html
复制代码
index.html
<!-- sourced from https://raw.githubusercontent.com/reactjs/reactjs.org/master/static/html/single-file-example.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>React Starter</title>
</head>
<body>
<div id="root"></div>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<script src="../dist/bundle.js"></script>
</body>
</html>
复制代码
这里引入的bundle.js后面会用到。
cd ../
npm install -D @babel/core@7.1.0 @babel/cli@7.1.0 @babel/preset-env@7.1.0 @babel/preset-react@7.0.0
touch .babelrc
复制代码
.babelrc
{
"presets": ["@babel/env", "@babel/preset-react"]
}
复制代码
npm i react react-dom -S
npm i react-hot-loader -D
复制代码
npm i webpack webpack-cli webpack-dev-server style-loader css-loader babel-loader --save-dev
touch webpack.config.js
复制代码
webpack.config.js
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: "./src/index.js",
mode: "development",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
options: { presets: ["@babel/env"] }
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
resolve: { extensions: ["*", ".js", ".jsx"] },
output: {
path: path.resolve(__dirname, "dist/"),
publicPath: "/dist/",
filename: "bundle.js"
},
devServer: {
contentBase: path.join(__dirname, "public/"),
port: 3000,
publicPath: "http://localhost:3000/dist/",
hotOnly: true
},
plugins: [new webpack.HotModuleReplacementPlugin()]
};
复制代码
mkdir src
cd src
touch index.js
touch App.js
touch App.css
复制代码
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App.js";
ReactDOM.render(<App />, document.getElementById("root"));
复制代码
App.js
import React, { Component} from "react";
import {hot} from 'react-hot-loader';
import "./App.css";
class App extends Component{
render(){
return(
<div className="App">
<h1> Hello</h1>
</div>
);
}
}
export default hot(module)(App);
复制代码
App.css
.App {
margin: 1rem;
font-family: Arial, Helvetica, sans-serif;
border: 1px solid red;
}
复制代码
在package.json里配置scripts字段。
"scripts": {
"start": "webpack-dev-server --mode development",
"test": "echo \"Error: no test specified\" && exit 1"
}
复制代码
npm start
复制代码
在浏览器键入http://localhost:3000以启动项目