本文主要写于 2021 - 02 - 09 。使用时候须要看 package.json 的版本,避免出错。
全文主要讲述的是,从 0 开始搭建一个属于本身能够彻底控制的 react 项目。主要涉及 webpack 逻辑,DLL 生成 等多个方面。后续会补充实际项目中使用等等。git 地址:https://gitee.com/sanyuelanv/...javascript
咱们先来简单的熟识一下整个项目的架构。在后续开发都依靠着这一个架构去拓展。css
├── app // 源码目录 │ ├── app.common.css // 全局的 CSS 代码,只须要一个! │ ├── app.html // 模版 HTML │ ├── app.tsx // 主要入口 │ ├── components // 组件 │ ├── config // 配置文件 │ ├── image // 图片素材 │ ├── router // 路由 │ ├── typings.d.ts // 全局 type │ └── utils // 工具函数使用 ├── build // 打包后目录 ├── dll // 打包后目录 ├── webpack.config.js // webpack 打包配置 └── webpack.dll.config.js // DLL 打包配置
devDependencies - 开发依赖包html
npm i --save-dev @babel/cli @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript @types/react @types/react-dom @typescript-eslint/eslint-plugin @typescript-eslint/parser autoprefixer babel-loader css-loader eslint eslint-plugin-react eslint-plugin-react-hooks file-loader html-webpack-plugin ip postcss postcss-loader style-loader typescript url-loader webpack webpack-cli webpack-dev-server clean-webpack-plugin terser-webpack-plugin optimize-css-assets-webpack-plugin mini-css-extract-plugin add-asset-html-webpack-plugin html-webpack-tags-plugin copy-webpack-plugin
按照完以上长长的开发依赖以后,咱们须要一个个去简单解析一下对应的做用java
dependencies - 普通依赖包node
npm i --save core-js react react-dom regenerator-runtime whatwg-fetch
普通依赖包和上面的 devDependencies 不同,它是须要打包进去咱们发布的 JS 文件中的。所以在后续增长和选择的时候须要对他们的内容,大小进行分析和了解才加入。避免打包出来的文件过大。react
首先在 package.json
文件中的 scripts
加上对应的命令。这些命令的对应着 开发环境 / 正式环境 / DLL 的打包。这一节是讲述 开发环境 / 正式环境 的打包。主要都是在 webpack.config.js
这个文件中操做。webpack
"scripts": { "dev": "webpack serve --env NODE_ENV=dev", "production": "webpack --env NODE_ENV=production --profile --json > stats.json", "dll": "webpack --config webpack.dll.config.js" },
不少讲 webpack 的文章都喜欢把 webpack.config.js 分开成两个文件,再使用一些合并函数来合并通用的,而我这里更加偏向在一个文件中操做,根据 dev / production 命令中设置的 NODE_ENV 的不一样去返回对应的 webpack 配置(webpack.config.js 的本质即便须要导出(module.exports)一个能 返回 webpack config json 的函数)。 ios
webpack.config.js 中的内容不少,可是首先把它分红两部分。module.exports 以前的 和 module.exports 以后的。git
module.exports 以后的web
module - 模块
在 webpack 眼中,项目内的全部文件都是 模块(module)。而在 webpack 的 module 字段中咱们须要作的就是制定规则(rules)。这个 rules 的主要做用是描述不一样文件该由谁去解析(不一样的loader)。
因此在整个 webpack.config.js 文件中你能看到不少的 xxLoader
和 xxxRule
对象。不一样的 Loader 在 Rule 的 use 中进行组装。而 rule 则在本身的内部使用 test 和 include 字段去决定本身在哪个目录下处理哪一类文件,全部的 rule 最终都在 config.module.rules 中拼接成一个数组。
const fileRule = { test: /\.(png|svg|jpg|gif|woff|woff2)$/, use: [{ loader: 'url-loader', options: isDev ? { limit: 2500 } : { limit: 2500, outputPath: assestPathName, publicPath: `/${assestPathName}` }, }], include: [appDir], exclude: [nodeModuleDir] } const baseConfig = { target: 'web', mode, entry: { 'app': [path.resolve(appDir, 'app.tsx')] }, resolve: { extensions: [".ts", ".tsx", '.js'] }, module: { rules: [ typeScriptRule, javaScriptRule, modulesStyleRule, commonStyleRule, fileRule ] } }
plugins - 插件
在 webpack 打包中,不一样时间段是在作着这个不一样的事情。而插件则能获取到这些不一样的时间点,方便你去作任何事情。没错,是任何事情。这就决定了 plugins 的功能是很是普遍的。
这里主要说明几个插件的做用
DefinePlugin:定义全局变量,但在 typescript 中使用须要在 typings.d.ts 中把这个变量定义好,否则的话会提出警告。
同时须要说明一下这里不是给 __DEV__
赋值,而是在编译的时候把 __DEV__
替换成 true / false。配合上 webpack 的 Tree Shaking
咱们就能很方便设置一些配置文件:在开发环境的配置不会带在正式环境打包后的代码中
// 须要在 typings.d.ts 中定义 // declare const __DEV__: boolean new webpack.DefinePlugin({ __DEV__: isDev }), // 使用 const config = __DEV__ ? 'dev' : 'production' // DEV 编译后 const config = true ? 'dev' : 'production' // Tree Shaking 后 const config = 'dev'
module.exports 以前的
在 module.exports 以前的大可能是配置,以及和环境(dev/dep)无关的的 rule / loader 配置。
// 开发代理服务器配置 const ip = require('ip') ... // html Plugin 配置 const baseHtmlWebpackPluginConfig = { filename: `index.html`, title: 'title', template: path.join(appDir, 'app.html'), inject: true }
在 webpack.config.js 的文件中其实能够看到在 production 环境下,使用到 webpack.DllReferencePlugin 。
const dllReferencePlugin = new webpack.DllReferencePlugin({ context: process.cwd(), manifest: require('./dll/dll.manifest.json') })
而这里使用到的 dll.manifest.json 文件则是咱们要见的 webpack.dll.config.js
配置下产生的。
webpack.dll.config.js
其实和 webpack.config.js
的正式环境差很少。只不过它只须要处理 ts
或者 js
文件(并且通常是依赖包下的 node_modules)。而它须要引入 webpack.DllPlugin 来导出一个清单文件(manifest.json)。这样在 webpack.config.js
中真正打包的时候就会跳过 manifest.json 上已经打包的模块。直接使用 dll.js
提供的模块。
new webpack.DllPlugin({ // 动态连接库的全局变量名称,须要和 output.library 中保持一致 name: '[name]', // 描述动态连接库的 manifest.json 文件输出时的文件名称 path: path.resolve(process.cwd(), 'dll', '[name].manifest.json') })
DLL 的优势在于咱们无需频繁打包这些不常常更新的依赖包文件,在正式环境下打包的时候, DLL 相关文件实际上是再也不参与的。确保每次更新后用户须要再次下载的内容不会变更很大。
详见 package.json 下的 eslintConfig 字段
详见 package.json 下的 browserslist 字段