feat: 增加source-ref-loader用于显示元素所在位置

pull/81/head
moonrailgun 3 years ago
parent 9983bfb6cf
commit 32453c8fee

@ -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"
}
}

@ -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<any>, source: string): Promise<void> {
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;

@ -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 = <><div>hello world</div></>;
export default class Foo {
render() {
return <div className="class-name">content</div>
}
}
`,
};

@ -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();

@ -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',
});
}

@ -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"]
}

@ -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:

@ -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)$/,

Loading…
Cancel
Save