# create-webpack-next **Repository Path**: janpoem/create-webpack-next ## Basic Information - **Project Name**: create-webpack-next - **Description**: Create webpack application within next-generation libraries. - **Primary Language**: TypeScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-03-18 - **Last Updated**: 2023-08-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # create-webpack-next [![Fork me on Gitee](https://gitee.com/janpoem/create-webpack-next/widgets/widget_6.svg)](https://gitee.com/janpoem/create-webpack-next) [![version](https://img.shields.io/npm/v/create-webpack-next?style=for-the-badge)](https://www.npmjs.com/package/create-webpack-next) [![dt](https://img.shields.io/npm/dt/create-webpack-next?style=for-the-badge)](https://www.npmjs.com/package/create-webpack-next) 创建次世代的 webpack 应用程序开发环境。 该指令将自动创建一个初始化的 webpack 项目环境,并添加所需必要的库。 开发环境主要集成: - `webpack`,`webpack-cli`, `webpack-dev-server` - loaders: `css-loader`, `style-loader`, `url-loader`, `file-loader`, `@svgr/webpack`, `postcss-loader` , `swc-loader` (JS/TS 转译加载器,替换 babel-loader / ts-loader) - plugins: `terser-webpack-plugin`, `css-minimizer-webpack-plugin`, `mini-css-extract-plugin`, `html-webpack-plugin` , `react-dev-utils`, `@pmmmwh/react-refresh-webpack-plugin`, `dotenv-webpack`, `react-refresh` (保留,有兴趣可以试试), `webpack-manifest-plugin` - `react`, `react-dom` - `windicss` - postcss 插件:`postcss-preset-env`, `autoprefixer`, `postcss-flexbugs-fixes` - `ts-node` 可直接执行 ts - `eslint` - `@typescript-eslint/parser`, `@typescript-eslint/eslint-plugin` - `eslint-plugin-react`, `eslint-plugin-react-hooks` 具体版本,请参考 [dependencies.ts](src/dependencies.ts) 文件。 ![img.png](img/screenshot-startup.png) dev server 启动界面截图 ## 版本特性说明 ### 1.0.x 最后版本到 `1.0.9`,旧版本。 ### 1.1.x - 调整创建的项目结构(根据实际项目结构调整) - 调整部分文件命名 - 分离出 app 目录(分离 App 组件和 AppService 类) - 添加 components/hooks 目录 - webpack 部分 - webpack `dotenv-webpack` 导入环境变量统一在 `import.meta.env.` 下,和 Vite 对齐 - `webpack.plugins.js` 增加第二个参数,以传递更多的插件 - 增加 Vite 支持 - Vite 插件、功能,与 webpack 对齐 ## 命令行参数 ```shell npx create-webpack-next # 使用帮助和查看版本号 npx create-webpack-next --help npx create-webpack-next --version # 更新新版本 # 如果之前通过 npx 指令使用过 npx create-webpack-next@latest --help npx create-webpack-next -p yarn npx create-webpack-next -p pnpm -r 17 ``` ### --react|-r 指定 React 版本号,默认为 `18`。 ### --package-manager|-p 默认为 `npm`,可选 `npm` `yarn` `pnpm`,选择本地 node 包管理器。 ### --install|-i 默认为 `true` 是否自动安装依赖包,根据指定的 `--package-manager|-p` 安装依赖库。 ### --vite 默认为 `false` 是否同时启用 Vite (推荐开发环境使用)。 ## 针对 swc-loader 和 CSS in JS 的说明 目前市面主流的 CSS in JS 库,大体依赖于 babel 进行处理。 基于 swc-loader 环境,项目中仍旧需要添加以下的 babel 库: ```shell yarn add @babel/core @babel/preset-env @babel/preset-react @compiled/babel-plugin -D ``` 我针对 linaria , @compiled, vanilla-extract, astroturf 这四个能提供静态 CSS 分离的库,做了本地测试,都能在 swc-loader 环境下跑通(还包括 emotion, goober, stitches 等)。 如 @compiled: **webpack.config.js** 文件 ``` { test : /\.(ts|tsx)$/, exclude: /(node_modules|bower_components)/, use : [ { loader: 'swc-loader' }, { loader: '@compiled/webpack-loader', options: { extract: false, importReact: false, extensions: ['.js', '.jsx', '.ts', '.tsx'] }, }, ] } ``` **.babelrc** 文件 ``` { "presets": [ "@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript" ], "plugins": [ [ "@compiled/babel-plugin", { "importReact": true, "cache": true } ] ] } ``` 目前 [Next.js](https://github.com/vercel/next.js) 也是基于 webpack + swc-loader 进行转译的,如果配置 CSS in JS 的环境有问题,可以去翻翻 Next.js 的 [examples](https://github.com/vercel/next.js/tree/canary/examples) 库。 ## 不要 Windi CSS ? 直接在入口文件 `src/index.tsx` 把 `import 'windi.css';` 删除掉即可。 ## 路径 resolve 说明 目前默认已经添加了 `tsconfig-paths-webpack-plugin` ,只要在 tsconfig.json 中添加了 paths ,webpack 环境下自动加载,无需额外配置。 如果要在脱离了 webpack 环境也能生效,则仍需再安装 `tsconfig-paths` 。 其次,也可以使用 pnpm 以 [workspace](https://pnpm.io/zh/workspaces) 方式来管理项目: package.json ```json { "dependencies": { "your-lib": "workspace:*" } } ``` 然后记得 `pnpm update` or `pnpm update -r` or `pnpm install` 也可。 或者在子项目下: ```shell pnpm add your-lib@workspace:* ``` 语法和 remote add 一样。 ## 单元测试例子 本来想加上单元测试的依赖的代码的,但想想其实也没必要。现在 React 周边都很成熟了,没必要非要 jest 了,mocha 更好(跑的更快)。断言库也可以自己选,比如我喜欢用 chai。 ### 组件测试 ```shell pnpm add react-test-renderer @types/react-test-renderer -D ``` ```tsx import * as React from 'react'; import { create } from 'react-test-renderer'; import { expect } from 'chai'; import { Flex } from './Flex'; let root: HTMLElement; describe('Flex test in react-test-runner', function () { it('should align items center', () => { const { props } = create(
).toTree(); expect(props).to.have.property('className'); expect(props.className).to.contain('ok'); }); }); ``` ### Hooks 测试 ```shell pnpm add @testing-library/react-hooks -D ``` ```tsx import { expect } from 'chai'; import * as React from 'react'; import { useState, useCallback } from 'react'; import { renderHook, act } from '@testing-library/react-hooks'; function useCounter() { const [count, setCount] = useState(0); const increment = useCallback(() => setCount((x) => x + 1), []); return { count, increment }; } describe('hook test in @testing-library/react-hooks', function () { it('should increment counter', () => { const { result } = renderHook(() => useCounter()); act(() => result.current.increment()); expect(result.current.count).to.eql(1); }); }); ``` ## 为何重复造轮子(vs create-react-app) 首先必须承认,本项目的 webpack.config.js 有参考自 create-react-app。 其次,和 create-react-app 比较: - 立场差异: - create-react-app 是 react 官方(facebook)出品,他创建的项目,立足于突出 react 的特点。故而将 webpack/postcss 等配置进行隐藏,集中突显立刻上手体验 react 的明确性。 - create-webpack-next 立足于创建可定制的 webpack 环境,不局限于 react,具体而言: 1. 工程配置化,可随着项目发展对 webpack 及相关部分进行更深入的定制。 2. 学习与研究,基于 webpack 环境,对各种插件和 loader 的尝试与定制,以及打包策略的调整等。 - 项目建立的时间点不同,导致依赖工具链环境差异。 - create-react-app 建立时间早,遵循其基础立场,而且存在诸多不合理的地方,并且很难在短期做更大的改进: 1. 使用 babel-loader 对 js/ts 进行转译; 2. 运行时加入了诸如 `eslint-webpack-plugin` `react-dev-utils/ForkTsCheckerWarningWebpackPlugin` 等语法检查工具,这种做法本身就很值得商榷,并不是一个大中型项目工程值得参考的做法。个人更推荐在 per-commit 阶段进行语法检查(诸如 husky 或如 JetBrains IDE 等)。 3. 官方还整合一些其他的插件,并不见得其必要性,更不体现其能突出 react 的何种特性。 - create-webpack-next 1. 使用 swc-loader,官方号称:**SWC is 20x faster than Babel on a single thread and 70x faster on four cores.** 2. eslint 只作为项目环境配置,而非运行时使用。 3. 所加入的配置和插件,立足于 `next generation` ,故而连 less/sass/stylus 这种 css 预处理器也不考虑。 > 次世代的 CSS > > 藉由 JS 运行时的动态 Statement 构建出 CSS(或由编译器预处理,或实时动态 generate,也即 CSS in JS) > > - 预处理型:`linaria` , `@compiled`, `vanilla-extract`, `astroturf` 等,支持静态 CSS 提取,生成 css var,支持拆分原子 CSS(或可)。 > - 实时生成型:`emotion`, `styled-components`, `goober`, `stitches` 等 > - 工具辅助型(可以在任意 CSS in JS 种使用):`polished`, `styled-system` 等 > - 异形:`react-native` 直接生成所需的 styles,看似怪异,但却会上瘾。 再次,无论 create-react-app 或 create-webpack-next 都旨在为用户提供开箱即用、可立刻体验式的 react/webpack 项目创建脚手架,都为 JS/TS/CSS/CSS Modules 等最基础的 web 前端开发环境提供处理支持。 ## 更新记录 ### 1.1.1 - 增加 `prettier` ### 1.1.0 - 调整创建的项目结构(根据实际项目结构调整) - 调整部分文件命名 - 分离出 app 目录(分离 App 组件和 AppService 类) - 添加 components/hooks 目录 - webpack 部分 - webpack `dotenv-webpack` 导入环境变量统一在 `import.meta.env.` 下,和 Vite 对齐 - `webpack.plugins.js` 增加第二个参数,以传递更多的插件 - 增加 Vite 支持 - Vite 插件、功能,与 webpack 对齐 ### 1.0.8 / 1.0.9 - 修正默认 react 18 未生效的问题 摆乌龙,状态不好,忘记 build 了 ### 1.0.7 - align 依赖库的最新版本 - react `-r` 未指定时,默认为 `18` - 去除 `chokidar` - fix React 18 的 hot-reload 机制,修改模板 `.swcrc` 内容。 ### 1.0.6 - 增加 `--react|-r` 参数,默认为 `17` ### 1.0.5 - 拆分 webpack.config.js 文件内容到 `config/webpack.*.js` 中 - 创建真实世界的应用程序环境 - 创建 AppService 类,管理全局应用程序环境; - `styles/index.css` 全局样式 - `pages` 对应页面入口 - `pages/Home.tsx` `pages/Home.module.css` 首页示例 - 样式从标签上转移到 css 中,使用 `@apply` 的 windi-css 语法 ### 1.0.4 - 针对 swc-loader 优化 `@pmmmwh/react-refresh-webpack-plugin` 配置,[参考](); - 增加 `tsconfig-paths-webpack-plugin` 插件,tsconfig paths 可自动加入 webpack resolve alias (无需手动配置); - 移除 `react-dev-utils/ModuleScopePlugin` 限制,去掉 tsconfig rootDir 配置; - 调整生成的文件名,图片使用 [contenthash:8],js 和 css 的 chunk 文件使用 [fullhash:8] ,主文件不带 hash。 - 使用 [windi css](https://windicss.org/guide/migration.html) 替换 tailwind css - 增加 webpack-manifest-plugin 插件 ### 1.0.3 - 调整 svgr 的配置,改为导入 svg 文件自动生成组件(React.memo)。 - `webpack.config.js.ejs` 增加 image-webpack-loader 的配置,但默认不开启(被注释掉),也不会添加 image-webpack-loader 包,如果需要,请自行安装。