diff --git a/README.en-US.md b/README.en-US.md index 36033479..f963c950 100644 --- a/README.en-US.md +++ b/README.en-US.md @@ -66,6 +66,7 @@ It mainly has the following functions: | [@fesjs/plugin-monaco-editor](http://fesjs.mumblefe.cn/reference/plugin/plugins/editor.html#%E4%BB%8B%E7%BB%8D) | Provide code editor capability, based on `monaco-editor` (code editor used by VS Code) | | [@fesjs/plugin-pinia](http://fesjs.mumblefe.cn/reference/plugin/plugins/pinia.html) | state manager | | [@fesjs/plugin-watermark](http://fesjs.mumblefe.cn/reference/plugin/plugins/watermark.html) | watermark | +| [@fesjs/plugin-swc](http://fesjs.mumblefe.cn/reference/plugin/plugins/swc.html) | use swc-loader | ## As easy as counting 1, 2, 3 use `yarn`: diff --git a/README.md b/README.md index dff37b69..b6b56174 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Fes.js 是一个好用的前端应用解决方案。提供覆盖编译构建到 | [@fesjs/plugin-windicss](http://fesjs.mumblefe.cn/reference/plugin/plugins/windicss.html) | 基于 `windicss`,提供原子化 CSS 能力 | | [@fesjs/plugin-pinia](http://fesjs.mumblefe.cn/reference/plugin/plugins/pinia.html) | pinia,状态处理 | | [@fesjs/plugin-watermark](http://fesjs.mumblefe.cn/reference/plugin/plugins/watermark.html) | 水印 | - +| [@fesjs/plugin-swc](http://fesjs.mumblefe.cn/reference/plugin/plugins/swc.html) | 使用swc-loader构建 | ## 像数 1, 2, 3 一样容易 使用 `yarn`: diff --git a/build.config.js b/build.config.js index 58b16ef4..d3952f64 100644 --- a/build.config.js +++ b/build.config.js @@ -23,6 +23,7 @@ module.exports = { 'fes-plugin-pinia', 'fes-plugin-windicss', 'fes-plugin-watermark', + 'fes-plugin-swc', ], copy: [], }; diff --git a/docs/.vuepress/configs/sidebar/zh.ts b/docs/.vuepress/configs/sidebar/zh.ts index 71d364a7..bafbc83b 100644 --- a/docs/.vuepress/configs/sidebar/zh.ts +++ b/docs/.vuepress/configs/sidebar/zh.ts @@ -65,6 +65,7 @@ export const zh: SidebarConfig = { '/reference/plugin/plugins/editor.md', '/reference/plugin/plugins/pinia.md', '/reference/plugin/plugins/watermark.md', + '/reference/plugin/plugins/swc.md', ], }, { diff --git a/docs/guide/builder.md b/docs/guide/builder.md index a0773538..67d5fb86 100644 --- a/docs/guide/builder.md +++ b/docs/guide/builder.md @@ -4,7 +4,6 @@ - 选用 Vite 构建,安装 `npm i @fesjs/builder-vite` 依赖即可。 - 选用 Webpack 构建,安装 `npm i @fesjs/builder-webpack` 依赖即可。 -- Webpack构建支持用babel+terser和swc两种编译方式,如选用swc,安装`npm i @swc/core` 同时配置额外传`swcLoader:{}`,具体可以查看[配置](../reference/config)。 ## 使用差异 diff --git a/docs/reference/config/README.md b/docs/reference/config/README.md index 3f169a65..ff71b4e7 100644 --- a/docs/reference/config/README.md +++ b/docs/reference/config/README.md @@ -459,13 +459,6 @@ export default { 配置额外的 `babel` 插件集。 -### swcLoader -- 类型: `object` -- 默认值: `undefined` -- 详情: - -传对象时使用swc进行编译和压缩,[swc配置](https://swc.rs/docs/configuration/swcrc) -默认usage模式 ### extraPostCSSPlugins - 类型: `array` diff --git a/docs/reference/plugin/README.md b/docs/reference/plugin/README.md index a9cccbfb..25be0d87 100644 --- a/docs/reference/plugin/README.md +++ b/docs/reference/plugin/README.md @@ -7,7 +7,7 @@ | [@fesjs/plugin-enums](./plugins/enums.md) | 提供统一的枚举存取及丰富的函数来处理枚举 | | [@fesjs/plugin-icon](./plugins/icon.md) | svg 文件自动注册为组件 | | [@fesjs/plugin-jest](./plugins/jest.md) | 基于 `Jest`,提供单元测试、覆盖测试能力 | -| [ @fesjs/plugin-layout](./plugins/layout.md) | 简单的配置即可拥有布局,包括导航以及侧边栏 | +| [@fesjs/plugin-layout](./plugins/layout.md) | 简单的配置即可拥有布局,包括导航以及侧边栏 | | [@fesjs/plugin-locale](./plugins/locale.md) | 基于 `Vue I18n`,提供国际化能力 | | [@fesjs/plugin-model](./plugins/model.md) | 简易的数据管理方案 | | [@fesjs/plugin-request](./plugins/request.md) | 基于 `Axios` 封装的 request,内置防止重复请求、请求节流、错误处理等功能 | @@ -18,6 +18,7 @@ | [@fesjs/plugin-windicss](./plugins/windicss.md) | 基于 `windicss`,提供原子化 CSS 能力 | | [@fesjs/plugin-pinia](./plugins/pinia.md) | 基于 `pinia`,提供状态管理 | | [@fesjs/plugin-watermark](./plugins/watermark.md) | 水印 | +| [@fesjs/plugin-swc](./plugins/swc.md) | swc | ## 架构 diff --git a/docs/reference/plugin/plugins/swc.md b/docs/reference/plugin/plugins/swc.md new file mode 100644 index 00000000..108191ec --- /dev/null +++ b/docs/reference/plugin/plugins/swc.md @@ -0,0 +1,30 @@ +# @fesjs/plugin-swc + +## 介绍 +webpack 启用 swc,构建速度更快! + + +## 启用方式 +在 `package.json` 中引入依赖: +```json +{ + "dependencies": { + "@fesjs/fes": "^3.0.0", + "@fesjs/plugin-swc": "^3.0.0" + }, +} +``` + +## 编译时配置 +传对象时使用swc进行编译和压缩,[loader配置](https://swc.rs/docs/configuration/swcrc),默认usage模式。 +```js +export default { + swc: { + loader: { + env: { + coreJs: '3.27', + }, + } + }, +} +``` diff --git a/packages/fes-builder-webpack/package.json b/packages/fes-builder-webpack/package.json index 146bf96d..bdb40c4c 100644 --- a/packages/fes-builder-webpack/package.json +++ b/packages/fes-builder-webpack/package.json @@ -35,7 +35,6 @@ "@babel/preset-env": "^7.16.4", "@babel/preset-typescript": "^7.15.0", "@fesjs/utils": "3.0.0-rc.2", - "@swc/css": "^0.0.18", "@vue/babel-plugin-jsx": "^1.1.1", "autoprefixer": "^10.2.4", "babel-loader": "^8.2.2", @@ -56,7 +55,6 @@ "postcss-loader": "^4.2.0", "postcss-safe-parser": "^6.0.0", "style-loader": "^2.0.0", - "swc-loader": "^0.2.3", "terser-webpack-plugin": "^5.3.6", "vue-loader": "^16.1.2", "webpack": "^5.69.0", diff --git a/packages/fes-builder-webpack/src/index.js b/packages/fes-builder-webpack/src/index.js index d4455dcc..e9e1b703 100644 --- a/packages/fes-builder-webpack/src/index.js +++ b/packages/fes-builder-webpack/src/index.js @@ -24,7 +24,6 @@ export default function () { require.resolve('./plugins/features/postcssLoader'), require.resolve('./plugins/features/nodeModulesTransform'), require.resolve('./plugins/features/vueLoader'), - require.resolve('./plugins/features/swcLoader'), // commands require.resolve('./plugins/commands/build'), diff --git a/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/css.js b/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/css.js index ca8ab814..5fad5ec9 100644 --- a/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/css.js +++ b/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/css.js @@ -10,7 +10,6 @@ // 根据 entry 将文件输出到不同的文件夹 import { deepmerge } from '@fesjs/utils'; -import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; function createRules({ isDev, webpackConfig, config, lang, test, loader, options, browserslist, styleLoaderOption }) { function applyLoaders(rule, cssLoaderOption = {}) { @@ -98,7 +97,7 @@ export default function createCssWebpackConfig({ isDev, config, webpackConfig, b chunkFilename: '[id].[contenthash:8].css', }, ]); - webpackConfig.optimization.minimizer('css').use(require.resolve('css-minimizer-webpack-plugin'), [{ minify: CssMinimizerPlugin.swcMinify }]); + webpackConfig.optimization.minimizer('css').use(require.resolve('css-minimizer-webpack-plugin'), [{}]); } return (options) => { diff --git a/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/index.js b/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/index.js index 429a8009..6aa22f4d 100644 --- a/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/index.js +++ b/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/index.js @@ -8,7 +8,6 @@ import createVueWebpackConfig from './vue'; import createDefineWebpackConfig from './define'; import createMinimizerWebpackConfig from './minimizer'; import createHtmlWebpackConfig from './html'; -import { buildSwcOptions } from './swcOptions'; const DEFAULT_EXCLUDE_NODE_MODULES = [ 'vue', @@ -53,7 +52,6 @@ function handleAlias({ api, webpackConfig }) { export default async function getConfig({ api, cwd, config, env, entry = {}, modifyBabelOpts, modifyBabelPresetOpts, chainWebpack, headScripts, publicPath }) { const isDev = env === 'development'; const isProd = env === 'production'; - const useSwc = !!config.swcLoader; const webpackConfig = new Config(); const absoluteOutput = join(cwd, config.outputPath || 'dist'); @@ -114,6 +112,13 @@ export default async function getConfig({ api, cwd, config, env, entry = {}, mod .type('asset/source'); const { targets, browserslist } = api.utils.getTargetsAndBrowsersList({ config }); + const babelOpts = await getBabelOpts({ + cwd, + config, + modifyBabelOpts, + modifyBabelPresetOpts, + targets, + }); // --------------- js ----------- // https://webpack.docschina.org/configuration/module/#resolve-fully-specified @@ -122,106 +127,43 @@ export default async function getConfig({ api, cwd, config, env, entry = {}, mod .test(/\.m?jsx?$/) .resolve.set('fullySpecified', false); - if (useSwc) { - webpackConfig.module - .rule('js') - .test(/\.(js|mjs)$/) + webpackConfig.module + .rule('js') + .test(/\.(js|mjs|jsx|ts|tsx)$/) + .exclude.add((filepath) => { + // always transpile js in vue files + if (/(\.vue|\.jsx)$/.test(filepath)) { + return false; + } // Don't transpile node_modules - .exclude.add(/node_modules/) - .end() - .use('swc-loader') - .loader(require.resolve('swc-loader')) - .options(buildSwcOptions(targets, config, false, false)); - webpackConfig.module - .rule('jsx') - .test(/\.jsx$/) - .exclude.add(/node_modules/) - .end() - .use('swc-loader') - .loader(require.resolve('swc-loader')) - .options(buildSwcOptions(targets, config, true, false)); + return /node_modules/.test(filepath); + }) + .end() + .use('babel-loader') + .loader(require.resolve('babel-loader')) + .options(babelOpts); + // 为了避免第三方依赖包编译不充分导致线上问题,默认对 node_modules 也进行全编译,只在生产构建的时候进行 + if (isProd) { + const transpileDepRegex = genTranspileDepRegex(config.nodeModulesTransform.exclude); webpackConfig.module - .rule('ts') - .test(/\.ts$/) - .exclude.add(/node_modules/) + .rule('js-in-node_modules') + .test(/\.(js|mjs)$/) + .include.add(/node_modules/) .end() - .use('swc-loader') - .loader(require.resolve('swc-loader')) - .options(buildSwcOptions(targets, config, false, true)); - webpackConfig.module - .rule('tsx') - .test(/\.tsx$/) - .exclude.add(/node_modules/) - .end() - .use('swc-loader') - .loader(require.resolve('swc-loader')) - .options(buildSwcOptions(targets, config, true, true)); - // 为了避免第三方依赖包编译不充分导致线上问题,默认对 node_modules 也进行全编译,只在生产构建的时候进行 - if (isProd) { - // const cjsReg = [/css-loader/, /vue-loader/].concat(config.swcLoader?.cjsPkg || []); - const transpileDepRegex = genTranspileDepRegex(config.nodeModulesTransform.exclude); - webpackConfig.module - .rule('node_modules') - .test(/\.(js|mjs)$/) - .include.add(/node_modules/) - .end() - .exclude.add((filepath) => { - if (transpileDepRegex && transpileDepRegex.test(filepath)) { - return true; - } - return false; - }) - .end() - .use('swc-loader') - .loader(require.resolve('swc-loader')) - .options(buildSwcOptions(targets, config, false, false)); - } - } else { - const babelOpts = await getBabelOpts({ - cwd, - config, - modifyBabelOpts, - modifyBabelPresetOpts, - targets, - }); - webpackConfig.module - .rule('js') - .test(/\.(js|mjs|jsx|ts|tsx)$/) .exclude.add((filepath) => { - // always transpile js in vue files - if (/(\.tsx|\.ts|\.jsx)$/.test(filepath)) { - return false; + if (transpileDepRegex && transpileDepRegex.test(filepath)) { + return true; } - // Don't transpile node_modules - return /node_modules/.test(filepath); + + return false; }) .end() .use('babel-loader') .loader(require.resolve('babel-loader')) .options(babelOpts); - - // 为了避免第三方依赖包编译不充分导致线上问题,默认对 node_modules 也进行全编译,只在生产构建的时候进行 - if (isProd) { - const transpileDepRegex = genTranspileDepRegex(config.nodeModulesTransform.exclude); - webpackConfig.module - .rule('js-in-node_modules') - .test(/\.(js|mjs)$/) - .include.add(/node_modules/) - .end() - .exclude.add((filepath) => { - if (transpileDepRegex && transpileDepRegex.test(filepath)) { - return true; - } - - return false; - }) - .end() - .use('babel-loader') - .loader(require.resolve('babel-loader')) - .options(babelOpts); - } } + // --------------- css ----------- const createCSSRule = createCssWebpackConfig({ isDev, @@ -319,13 +261,15 @@ export default async function getConfig({ api, cwd, config, env, entry = {}, mod isProd, config, webpackConfig, - swcOptions: useSwc ? buildSwcOptions(targets, config, false, false, true) : undefined, }); // --------------- chainwebpack ----------- if (chainWebpack) { await chainWebpack(webpackConfig, { createCSSRule, + env, + targets, + browserslist, webpack, }); } @@ -334,6 +278,8 @@ export default async function getConfig({ api, cwd, config, env, entry = {}, mod await config.chainWebpack(webpackConfig, { createCSSRule, env, + targets, + browserslist, webpack, }); } diff --git a/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/minimizer.js b/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/minimizer.js index bf9343ea..507b8c52 100644 --- a/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/minimizer.js +++ b/packages/fes-builder-webpack/src/plugins/commands/webpackConfig/minimizer.js @@ -1,5 +1,4 @@ import { deepmerge } from '@fesjs/utils'; -import TerserPlugin from 'terser-webpack-plugin'; const defaultTerserOptions = { compress: { @@ -38,22 +37,14 @@ const defaultTerserOptions = { }, }; -const terserOptions = (config, swcOptions) => { - if (swcOptions) { - return { - terserOptions: swcOptions.jsc?.minify, - minify: TerserPlugin.swcMinify, - }; - } - return { - terserOptions: deepmerge(defaultTerserOptions, config.terserOptions || {}), - extractComments: false, - }; -}; +const terserOptions = (config) => ({ + terserOptions: deepmerge(defaultTerserOptions, config.terserOptions || {}), + extractComments: false, +}); -export default function createMinimizerWebpackConfig({ isProd, config, webpackConfig, swcOptions }) { +export default function createMinimizerWebpackConfig({ isProd, config, webpackConfig }) { if (isProd) { - webpackConfig.optimization.minimizer('terser').use(require.resolve('terser-webpack-plugin'), [terserOptions(config, swcOptions)]); + webpackConfig.optimization.minimizer('terser').use(require.resolve('terser-webpack-plugin'), [terserOptions(config)]); } if (process.env.FES_ENV === 'test') { webpackConfig.optimization.minimize(false); diff --git a/packages/fes-builder-webpack/src/plugins/features/swcLoader.js b/packages/fes-builder-webpack/src/plugins/features/swcLoader.js deleted file mode 100644 index 99f57eca..00000000 --- a/packages/fes-builder-webpack/src/plugins/features/swcLoader.js +++ /dev/null @@ -1,10 +0,0 @@ -export default (api) => { - api.describe({ - key: 'swcLoader', - config: { - schema(joi) { - return joi.object().description('more swc options see https://github.com/swc-project/swc-loader'); - }, - }, - }); -}; diff --git a/packages/fes-plugin-swc/LICENSE b/packages/fes-plugin-swc/LICENSE new file mode 100644 index 00000000..0978fbf7 --- /dev/null +++ b/packages/fes-plugin-swc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-present webank + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/fes-plugin-swc/README.md b/packages/fes-plugin-swc/README.md new file mode 100644 index 00000000..b6b56174 --- /dev/null +++ b/packages/fes-plugin-swc/README.md @@ -0,0 +1,126 @@ +简体中文 | [English](./README.en-US.md) + +
+
+
+
+