项目初始化
$ NPM init
安装 webpack
本次创建是基于 webpack4
$ NPM install --save-dev
新建 webpack 配置文件
在根目录创建 build 文件夹, 添加一个 JS 文件, 命名为 webpack.base.conf.JS
- // webpack.base.conf.JS 文件
- const path = require('path');
- const DIST_PATH = path.resolve(__dirname, '../dist');
- module.exports = {
- entry: {
- App: './app/index.js'
- },
- output: {
- filename: "js/bundle.js",
- path: DIST_PATH
- }
- };
使用 merge 的方式来组织 webpack 基础配置和不同环境的配置
先安装 webpack-merge:
$ NPM install --save-dev webpack-merge
在 build 文件夹中再添加一个 JS 文件, 命名为 webpack.prod.conf.JS
- // webpack.prod.conf.JS 文件
- const merge = require('webpack-merge');
- const baseWebpackConfig = require('./webpack.base.conf');
- module.exports = merge(baseWebpackConfig, {
- mode: 'production'
- });
在根目录下创建 App 目录, 然后创建 index.JS 文件
- var element =document.getElementById('root');
- element.innerhtml = 'hello, world!';
在根目录创建一个 public 文件夹, 然后新建一个 index.HTML 文件
// index.HTML
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- 从零开始搭建 react 工程
- </title>
- </head>
- <body>
- <div id="root">
- </div>
- <script src="../dist/js/bundle.js">
- </script>
- </body>
- </HTML>
当前项目目录树
- |- /App
- |- index.JS
- |- /node_modules
- |- /public
- |- index.HTML
- |- /build
- |- webpack.base.conf.JS
- |- webpack.prod.conf.JS
- |- package.JSON
- |- package-lock.JSON
安装 webpack-cli
webpack 4.0 版本之后的 webpack, 已经将 webpack 命令工具迁移到 webpack-cli 模块了, 需要安装 webpack-cli
$ NPM install --save-dev webpack-cli
package.JSON 文件 scripts 属性配置一个 build 命令
其值为: webpack --config build/webpack.prod.conf.JS, 以下是 scripts 的相关代码
- // package.JSON
- "scripts": {
- "build": "webpack --config build/webpack.prod.conf.js",
- "test": "echo \"Error: no test specified\"&& exit 1"
- },
安装 React
$ NPM install --save react react-dom
修改 App 目录下的 index.JS 的代码
- import React from "react";
- import ReactDom from "react-dom";
- ReactDom.render(
- <h1>hello, world!</h1>,
- document.getElementById("root")
- );
注意 import 属于 ES6 规范, 因此需要转译 ES2015 + 的语法, 安装并配置 babel 以及相关依赖
$ NPM install --save-dev babel-loader babel-core babel-preset-env babel-preset-react
根目录创建. babelrc 文件, 配置 presets.
- {
- "presets": [
- [
- "env",
- {
- "targets": {
- "browsers": [
- "> 1%",
- "last 5 versions",
- "ie>= 8"
- ]
- }
- }
- ],
- "react"
- ]
- }
修改 webpack.base.conf.JS 文件
- // webpack.base.conf.JS
- const path = require('path');
- const APP_PATH = path.resolve(__dirname, '../app');
- const DIST_PATH = path.resolve(__dirname, '../dist');
- module.exports = {
- entry: {
- App: './app/index.js'
- },
- output: {
- filename: 'js/bundle.js',
- path: DIST_PATH
- },
- module: {
- rules: [
- {
- test: /\.JS?$/,
- use: "babel-loader",
- include: APP_PATH
- }
- ]
- }
- };
运行 NPM run build
添加插件
public 下的 index.HTML 本该自动添加到 dist 目录, 并且引用资源自动加载到该文件, 通过 HTML-webpack-plugin 实现这一步
$ NPM install HTML-webpack-plugin --save-dev
webpack.prod.conf.JS 中配置 plugins 属性
- const merge = require('webpack-merge');
- const baseWebpackConfig = require('./webpack.base.conf.js');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- module.exports = merge(baseWebpackConfig, {
- mode: 'production',
- plugins: [
- new HtmlWebpackPlugin({
- template: 'public/index.html',
- inject: 'body',
- minify: {
- removeComments: true,
- collapseWhitespace: true,
- removeAttributeQuotes: true
- },
- })
- ]
- });
删除 index.HTML 中手动引入的 script 标签
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <title>
- 从零开始搭建 react 工程
- </title>
- </head>
- <body>
- <div id="root">
- </div>
- </body>
- </HTML>
重新编译查看 NPM run build 浏览器打开查看目录 dist 下的 index.HTML
以上步骤都成功的前提下继续走下一步
生成的文件名添加 Hash 值, 目的是解决缓存问题
修改 webpack.prod.conf.JS,mode: 'production', 增加以下代码
- // webpack.prod.conf.JS
- output: {
- filename: "js/[name].[chunkhash:16].js",
- },
生成前需要清理之前项目生成的文件, 因为由于文件名的改变如果不删除会一直增加
安装插件 clean-webpack-plugin
$ NPM install --save-dev clean-webpack-plugin
修改 webpack.prod.conf.JS
- // webpack.prod.conf.JS
- const merge = require('webpack-merge');
- const baseWebpackConfig = require('./webpack.base.conf.js');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- const CleanWebpackPlugin = require('clean-webpack-plugin');
- module.exports = merge(baseWebpackConfig, {
- mode: 'production',
- output: {
- filename: "js/[name].[chunkhash:16].js",
- },
- plugins: [
- new HtmlWebpackPlugin({
- template: 'public/index.html',
- inject: 'body',
- minify: {
- removeComments: true,
- collapseWhitespace: true,
- removeAttributeQuotes: true
- },
- }),
- new CleanWebpackPlugin(['../dist'], { allowExternal: true })
- ]
- });
公共代码与业务代码分离
修改 webpack.base.conf.JS 的 entry 入口属性, 抽出框架代码
- entry: {
- App: './app/index.js',
- framework: ['react','react-dom'],
- },
修改 webpack.prod.conf.JS, 增加以下代码, 目的是分离框架代码和业务代码
虽然上面步骤抽出框架代码生成两个文件, 但是 App.JS 还是包含框架代码
- optimization: {
- splitChunks: {
- chunks: "all",
- minChunks: 1,
- minSize: 0,
- cacheGroups: {
- framework: {
- test: "framework",
- name: "framework",
- enforce: true
- }
- }
- }
- }
cacheGroups 对象, 定义了需要被抽离的模块
其中 test 属性是比较关键的一个值, 他可以是一个字符串, 也可以是正则表达式, 还可以是函数. 如果定义的是字符串, 会匹配入口模块名称, 会从其他模块中把包含这个模块的抽离出来
name 是抽离后生成的名字, 和入口文件模块名称相同, 这样抽离出来的新生成的 framework 模块会覆盖被抽离的 framework 模块
整合 webpack-dev-server
开发环境开启服务监听文件改动实时更新最新内容
$ NPM install --save-dev webpack-dev-server
在 build 中添加 webpack.dev.conf.JS 文件
- const path = require('path');
- const merge = require('webpack-merge');
- const baseWebpackConfig = require('./webpack.base.conf.js');
- const HtmlWebpackPlugin = require('html-webpack-plugin');
- const webpack = require('webpack');
- module.exports = merge(baseWebpackConfig, {
- mode: 'development',
- output: {
- filename: "js/[name].[hash:16].js",
- },
- plugins: [
- new HtmlWebpackPlugin({
- template: 'public/index.html',
- inject: 'body',
- minify: {
- html5: true
- },
- hash: false
- }),
- new webpack.HotModuleReplacementPlugin()
- ],
- devServer: {
- port: '8080',
- contentBase: path.join(__dirname, '../public'),
- compress: true,
- historyApiFallback: true,
- hot: true,
- https: false,
- noInfo: true,
- open: true,
- proxy: {}
- }
- });
在 package.JSON scripts 属性添加内容
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
NPM run dev
自动打开浏览器打开入口页面实时更新
独立导出 CSS 文件
安装 CSS 相关依赖
Sass Less 预处理
- $ NPM install extract-text-webpack-plugin
- $ NPM install style-loader CSS-loader postcss-loader autoprefixer --save-dev
- $ NPM install Less Sass Less-loader Sass-loader stylus-loader node-Sass --save-dev
webpack.base.conf.JS 文件修改
- // webpack.base.conf.JS
- {
- test: /\.CSS$/,
- use: [
- {
- loader: "style-loader" // 在 HTML 中插入 < style > 标签
- },
- {
- loader: "css-loader",// 获取引用资源, 如 @import,url()
- },
- {
- loader: "postcss-loader",
- options: {
- plugins:[
- require('autoprefixer')({
- browsers:['last 5 version']
- })
- ]
- }
- }
- ]
- },
- {
- test:/\.Less$/,
- use: [
- { loader: "style-loader" },
- { loader: "css-loader" },
- {
- loader: "postcss-loader",// 自动加前缀
- options: {
- plugins:[
- require('autoprefixer')({
- browsers:['last 5 version']
- })
- ]
- }
- },
- { loader: "less-loader" }
- ]
- },
- {
- test:/\.SCSS$/,
- use:[
- { loader: "style-loader" },
- {
- loader: "css-loader",
- },
- { loader: "sass-loader" },
- {
- loader: "postcss-loader",
- options: {
- plugins:[
- require('autoprefixer')({
- browsers:['last 5 version']
- })
- ]
- }
- }
- ]
- },
图片和路径处理
$ NPM i file-loader url-loader --save-dev
webpack.base.conf.JS 文件修改
- // webpack.base.conf.JS
- {
- test: /\.(PNG|jpg|gif|woff|svg|eot|woff2|tff)$/,
- use: 'url-loader?limit=8129',
- // 注意后面那个 limit 的参数, 当你图片大小小于这个限制的时候, 会自动启用 base64 编码图片
- exclude: /node_modules/
- }
build 时报错
- Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead
- at Chunk.get (F:\react\createApp\node_modules\webpack\lib\Chunk.JS:824:9)
webpack4.0 中使用 "extract-text-webpack-plugin" 报错
解决办法
$ NPM install extract-text-webpack-plugin@next
背景图片路径问题
由于 CSS 文件分离出来的原因, 会导致在 CSS 文件夹下找 images 文件夹下的图片
解决办法 publicPath 属性改为 '/', 以绝对路径的方式寻找资源
- {
- test:/\.(PNG|jpg|gif)$/,
- use:[{
- loader:'url-loader',
- options: {
- // outputPath:'../',// 输出 ** 文件夹
- publicPath: '/',
- name: "images/[name].[ext]",
- limit:500 // 是把小于 500B 的文件打成 Base64 的格式, 写入 JS
- }
- }]
- },
https://xiaozhuanlan.com/topic/7106389254
来源: https://juejin.im/post/5c1de44ff265da61715e523b