From 32453c8fee36ab327b54d09980dc95bb380f4294 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Fri, 27 May 2022 00:06:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0source-ref-loader?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E6=98=BE=E7=A4=BA=E5=85=83=E7=B4=A0=E6=89=80?= =?UTF-8?q?=E5=9C=A8=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../source-ref-webpack-loader/package.json | 36 +++++++ .../source-ref-webpack-loader/src/index.ts | 63 ++++++++++++ .../test/fixtures.ts | 18 ++++ .../source-ref-webpack-loader/test/index.ts | 16 ++++ .../source-ref-webpack-loader/test/utils.ts | 14 +++ .../source-ref-webpack-loader/tsconfig.json | 17 ++++ pnpm-lock.yaml | 96 +++++++++++++++++++ web/build/webpack.config.ts | 29 ++++-- 8 files changed, 283 insertions(+), 6 deletions(-) create mode 100644 packages/source-ref-webpack-loader/package.json create mode 100644 packages/source-ref-webpack-loader/src/index.ts create mode 100644 packages/source-ref-webpack-loader/test/fixtures.ts create mode 100644 packages/source-ref-webpack-loader/test/index.ts create mode 100644 packages/source-ref-webpack-loader/test/utils.ts create mode 100644 packages/source-ref-webpack-loader/tsconfig.json diff --git a/packages/source-ref-webpack-loader/package.json b/packages/source-ref-webpack-loader/package.json new file mode 100644 index 00000000..00e1e546 --- /dev/null +++ b/packages/source-ref-webpack-loader/package.json @@ -0,0 +1,36 @@ +{ + "name": "source-ref-webpack-loader", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "files": [ + "dist" + ], + "scripts": { + "build": "tsc", + "prepare": "tsc", + "test": "ts-node ./test/index.ts" + }, + "keywords": [ + "sourcecode", + "pointer", + "webpack" + ], + "author": "moonrailgun", + "license": "MIT", + "devDependencies": { + "@types/babel__generator": "^7.6.4", + "@types/babel__traverse": "^7.17.1", + "@types/webpack": "^5.28.0", + "ts-node": "^10.0.0", + "typescript": "^4.5.2", + "webpack": "^5.72.0", + "webpack-test-utils": "^1.1.0" + }, + "dependencies": { + "@babel/generator": "^7.17.7", + "@babel/parser": "^7.17.7", + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.10" + } +} diff --git a/packages/source-ref-webpack-loader/src/index.ts b/packages/source-ref-webpack-loader/src/index.ts new file mode 100644 index 00000000..8f8f3310 --- /dev/null +++ b/packages/source-ref-webpack-loader/src/index.ts @@ -0,0 +1,63 @@ +import type { LoaderContext } from 'webpack'; +import { parse } from '@babel/parser'; +import traverse from '@babel/traverse'; +import generate from '@babel/generator'; +import { jsxAttribute, jsxIdentifier, stringLiteral } from '@babel/types'; + +const TRACE_ID = 'data-source'; + +async function loader(this: LoaderContext, source: string): Promise { + const done = this.async(); + + const { available } = this.getOptions(); + if (!available) { + // skip if not + done(null, source); + return; + } + + const ast = parse(source, { + sourceType: 'module', + plugins: ['jsx', 'typescript'], + }); + const filepath = this.resourcePath; + if (filepath.includes('node_modules')) { + done(null, source); + return; + } + + traverse(ast, { + JSXOpeningElement(path) { + const location = path.node.loc; + if (!location) { + return; + } + + if (Array.isArray(location)) { + return; + } + + const line = location.start.line; + const col = location.start.column; + + const attrs = path.node.attributes; + for (let i = 0; i < attrs.length; i++) { + const attr = attrs[i]; + if (attr.type === 'JSXAttribute' && attr.name.name === TRACE_ID) { + // existed + return; + } + } + + const traceId = `${filepath}:${line}:${col}`; + + attrs.push(jsxAttribute(jsxIdentifier(TRACE_ID), stringLiteral(traceId))); + }, + }); + + const code = generate(ast).code; + + done(null, code); +} + +export default loader; diff --git a/packages/source-ref-webpack-loader/test/fixtures.ts b/packages/source-ref-webpack-loader/test/fixtures.ts new file mode 100644 index 00000000..4874516c --- /dev/null +++ b/packages/source-ref-webpack-loader/test/fixtures.ts @@ -0,0 +1,18 @@ +export const tsx = { + '/src/index.js': ` + import Foo, { HelloWorld } from './foo.tsx' + export default [ + HelloWorld, + (new Foo()).render(), + ]; + `, + + '/src/foo.tsx': ` + export const HelloWorld = <>
hello world
; + export default class Foo { + render() { + return
content
+ } + } + `, +}; diff --git a/packages/source-ref-webpack-loader/test/index.ts b/packages/source-ref-webpack-loader/test/index.ts new file mode 100644 index 00000000..a10c26ff --- /dev/null +++ b/packages/source-ref-webpack-loader/test/index.ts @@ -0,0 +1,16 @@ +import { build } from 'webpack-test-utils'; +import * as fixtures from './fixtures'; +import { configureLoader } from './utils'; + +async function test() { + const built = await build(fixtures.tsx, (config) => { + configureLoader(config); + }); + + console.log(built.stats.endTime - built.stats.startTime); + + console.log(built.stats.compilation.errors.length); + console.log(built.stats.compilation.errors); +} + +test(); diff --git a/packages/source-ref-webpack-loader/test/utils.ts b/packages/source-ref-webpack-loader/test/utils.ts new file mode 100644 index 00000000..0b881178 --- /dev/null +++ b/packages/source-ref-webpack-loader/test/utils.ts @@ -0,0 +1,14 @@ +import type { Configuration } from 'webpack'; + +const loaderPath = require.resolve('../src/index.ts'); + +export function configureLoader(config: Configuration) { + config.resolveLoader.alias = { + 'source-pointer-loader': loaderPath, + }; + + config.module.rules.push({ + test: /\.tsx$/, + loader: 'source-pointer-loader', + }); +} diff --git a/packages/source-ref-webpack-loader/tsconfig.json b/packages/source-ref-webpack-loader/tsconfig.json new file mode 100644 index 00000000..1e84caf7 --- /dev/null +++ b/packages/source-ref-webpack-loader/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "outDir": "dist", + "module": "commonjs", + + // Node 10 + "target": "ES2018", + "lib": ["ES2018"], + + "declaration": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 378c041a..2203225b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -156,6 +156,33 @@ importers: '@types/node': 15.14.9 ts-node: 10.7.0_ixcth6kbstn6no7hiktnzckliq + packages/source-pointer-webpack-loader: + specifiers: + '@babel/generator': ^7.17.7 + '@babel/parser': ^7.17.7 + '@babel/traverse': ^7.17.3 + '@babel/types': ^7.17.10 + '@types/babel__generator': ^7.6.4 + '@types/babel__traverse': ^7.17.1 + '@types/webpack': ^5.28.0 + ts-node: ^10.0.0 + typescript: ^4.5.2 + webpack: ^5.72.0 + webpack-test-utils: ^1.1.0 + dependencies: + '@babel/generator': 7.17.10 + '@babel/parser': 7.17.10 + '@babel/traverse': 7.17.10 + '@babel/types': 7.17.10 + devDependencies: + '@types/babel__generator': 7.6.4 + '@types/babel__traverse': 7.17.1 + '@types/webpack': 5.28.0 + ts-node: 10.7.0_typescript@4.6.4 + typescript: 4.6.4 + webpack: 5.72.1 + webpack-test-utils: 1.1.0_webpack@5.72.1 + shared: specifiers: '@reduxjs/toolkit': ^1.7.1 @@ -861,6 +888,8 @@ packages: resolution: {integrity: sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==} engines: {node: '>=6.0.0'} hasBin: true + dependencies: + '@babel/types': 7.17.10 /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.16.7_@babel+core@7.17.10: resolution: {integrity: sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==} @@ -4931,6 +4960,19 @@ packages: source-map: 0.6.1 dev: true + /@types/webpack/5.28.0: + resolution: {integrity: sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w==} + dependencies: + '@types/node': 17.0.4 + tapable: 2.2.1 + webpack: 5.72.1 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + - webpack-cli + dev: true + /@types/webpack/5.28.0_webpack-cli@4.9.2: resolution: {integrity: sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w==} dependencies: @@ -5414,6 +5456,9 @@ packages: resolution: {integrity: sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==} peerDependencies: acorn: ^8 + peerDependenciesMeta: + acorn: + optional: true dependencies: acorn: 8.7.1 dev: true @@ -9471,6 +9516,10 @@ packages: resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} dev: true + /fs-require/1.4.0: + resolution: {integrity: sha512-ZytCzc6QAE0lprblNErZJuDVNoT0JPRSBCUXIMrIB0mLlwcAppbE5fqUyqC8zhgrrR3+whvpKLxOqtk8EnSbeA==} + dev: true + /fs-write-stream-atomic/1.0.10: resolution: {integrity: sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==} dependencies: @@ -17201,6 +17250,36 @@ packages: yn: 3.1.1 dev: true + /ts-node/10.7.0_typescript@4.6.4: + resolution: {integrity: sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.7.0 + '@tsconfig/node10': 1.0.8 + '@tsconfig/node12': 1.0.9 + '@tsconfig/node14': 1.0.1 + '@tsconfig/node16': 1.0.2 + acorn: 8.7.1 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.6.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + /ts-pnp/1.2.0_typescript@4.6.4: resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==} engines: {node: '>=6'} @@ -17412,6 +17491,12 @@ packages: set-value: 2.0.1 dev: true + /unionfs/4.4.0: + resolution: {integrity: sha512-N+TuJHJ3PjmzIRCE1d2N3VN4qg/P78eh/nxzwHnzpg3W2Mvf8Wvi7J1mvv6eNkb8neUeSdFSQsKna0eXVyF4+w==} + dependencies: + fs-monkey: 1.0.3 + dev: true + /uniq/1.0.1: resolution: {integrity: sha512-Gw+zz50YNKPDKXs+9d+aKAjVwpjNwqzvNpLigIruT4HA9lMZNdMqs9x07kKHB/L9WRzqp4+DlTU5s4wG2esdoA==} dev: false @@ -18074,6 +18159,17 @@ packages: engines: {node: '>=10.13.0'} dev: true + /webpack-test-utils/1.1.0_webpack@5.72.1: + resolution: {integrity: sha512-zJaJZsa3v8jFx41uiVSF6V/8wd4zuX/DtDZkm7t8f8WlxP0W3Iwj3BikZx4C45EX7+yTUBWmKbkknoSsaIhFmw==} + peerDependencies: + webpack: ^4.40.0 || ^5.0.0 + dependencies: + fs-require: 1.4.0 + memfs: 3.4.1 + unionfs: 4.4.0 + webpack: 5.72.1 + dev: true + /webpack-virtual-modules/0.2.2: resolution: {integrity: sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==} dependencies: diff --git a/web/build/webpack.config.ts b/web/build/webpack.config.ts index d1fcb3bf..635f4092 100644 --- a/web/build/webpack.config.ts +++ b/web/build/webpack.config.ts @@ -225,17 +225,34 @@ const config: Configuration = { overlay: false, }, }, + // resolveLoader: { + // alias: { + // 'source-ref-loader': require.resolve( + // '../../packages/source-ref-webpack-loader/src' + // ), + // }, + // }, module: { rules: [ { test: /\.tsx?$/, exclude: /node_modules/, - loader: 'esbuild-loader', - options: { - loader: 'tsx', - target: 'es2015', - tsconfigRaw: require('../tsconfig.json'), - }, + use: [ + { + loader: 'esbuild-loader', + options: { + loader: 'tsx', + target: 'es2015', + tsconfigRaw: require('../tsconfig.json'), + }, + }, + // { + // loader: 'source-ref-loader', + // options: { + // available: false, + // }, + // }, + ], }, { test: /\.(less|css)$/,