var babelOptsReact = { plugins: [ devExpressionWithCodes, // this pass has to run before `rewrite-modules` [babelPluginModules, { map: moduleMapReact }] ] };
var evalToString = require("./evalToString"); var existingErrorMap = require("./codes.json"); var invertObject = require("./invertObject"); var errorMap = invertObject(existingErrorMap); module.exports = function(babel) { var t = babel.types; var SEEN_SYMBOL = Symbol("dev-expression-with-codes.seen"); // Generate a hygienic identifier functiongetProdInvariantIdentifier(path, localState) { if (!localState.prodInvariantIdentifier) { localState.prodInvariantIdentifier = path.scope.generateUidIdentifier( "prodInvariant" ); path.scope.getProgramParent().push({ id: localState.prodInvariantIdentifier, init: t.callExpression(t.identifier("require"), [ t.stringLiteral("reactProdInvariant") ]) }); } return localState.prodInvariantIdentifier; } var DEV_EXPRESSION = t.binaryExpression( "!==", t.memberExpression( t.memberExpression(t.identifier("process"), t.identifier("env"), false), t.identifier("NODE_ENV"), false ), t.stringLiteral("production") ); return { pre: function() { this.prodInvariantIdentifier = null; }, visitor: { Identifier: { enter: function(path) { // Do nothing when testing if (process.env.NODE_ENV === "test") { return; } // Replace __DEV__ with process.env.NODE_ENV !== 'production' if (path.isIdentifier({ name: "__DEV__" })) { path.replaceWith(DEV_EXPRESSION); } } }, CallExpression: { exit: function(path) { var node = path.node; // Ignore if it's already been processed if (node[SEEN_SYMBOL]) { return; } // Insert `var PROD_INVARIANT = require('reactProdInvariant');` // before all `require('invariant')`s. // NOTE it doesn't support ES6 imports yet. if ( path.get("callee").isIdentifier({ name: "require" }) && path.get("arguments")[0] && path.get("arguments")[0].isStringLiteral({ value: "invariant" }) ) { node[SEEN_SYMBOL] = true; getProdInvariantIdentifier(path, this); } elseif (path.get("callee").isIdentifier({ name: "invariant" })) { // Turns this code: // // invariant(condition, argument, 'foo', 'bar'); // // into this: // // if (!condition) { // if ("production" !== process.env.NODE_ENV) { // invariant(false, argument, 'foo', 'bar'); // } else { // PROD_INVARIANT('XYZ', 'foo', 'bar'); // } // } // // where // - `XYZ` is an error code: a unique identifier (a number string) // that references a verbose error message. // The mapping is stored in `scripts/error-codes/codes.json`. // - `PROD_INVARIANT` is the `reactProdInvariant` function that always throws with an error URL like // [http://facebook.github.io/react/docs/error-decoder.html?invariant=XYZ&args[\]=foo&args[]=bar](http://facebook.github.io/react/docs/error-decoder.html?invariant=XYZ&args%5B%5D=foo&args%5B%5D=bar) // // Specifically this does 3 things: // 1. Checks the condition first, preventing an extra function call. // 2. Adds an environment check so that verbose error messages aren't // shipped to production. // 3. Rewrites the call to `invariant` in production to `reactProdInvariant` // - `reactProdInvariant` is always renamed to avoid shadowing // The generated code is longer than the original code but will dead // code removal in a minifier will strip that out. var condition = node.arguments[0]; var errorMsgLiteral = evalToString(node.arguments[1]); var prodErrorId = errorMap[errorMsgLiteral]; if (prodErrorId === undefined) { // The error cannot be found in the map. node[SEEN_SYMBOL] = true; if (process.env.NODE_ENV !== "test") { console.warn( 'Error message "' + errorMsgLiteral + '" cannot be found. The current React version ' + "and the error map are probably out of sync. " + "Please run `gulp react:extract-errors` before building React." ); } return; } var devInvariant = t.callExpression( node.callee, [ t.booleanLiteral(false), t.stringLiteral(errorMsgLiteral) ].concat(node.arguments.slice(2)) ); devInvariant[SEEN_SYMBOL] = true; var localInvariantId = getProdInvariantIdentifier(path, this); var prodInvariant = t.callExpression( localInvariantId, [t.stringLiteral(prodErrorId)].concat(node.arguments.slice(2)) ); prodInvariant[SEEN_SYMBOL] = true; path.replaceWith( t.ifStatement( t.unaryExpression("!", condition), t.blockStatement([ t.ifStatement( DEV_EXPRESSION, t.blockStatement([t.expressionStatement(devInvariant)]), t.blockStatement([t.expressionStatement(prodInvariant)]) ) ]) ) ); } elseif (path.get("callee").isIdentifier({ name: "warning" })) { // Turns this code: // // warning(condition, argument, argument); // // into this: // // if ("production" !== process.env.NODE_ENV) { // warning(condition, argument, argument); // } // // The goal is to strip out warning calls entirely in production. We // don't need the same optimizations for conditions that we use for // invariant because we don't care about an extra call in __DEV__ node[SEEN_SYMBOL] = true; path.replaceWith( t.ifStatement( DEV_EXPRESSION, t.blockStatement([t.expressionStatement(node)]) ) ); } } } } }; };
var gutil = require("gulp-util"); var through = require("through2"); var PM_REGEXP = require("./shared/provides-module").regexp; module.exports = function(opts) { functiontransform(file, enc, cb) { if (file.isNull()) { cb(null, file); return; } if (file.isStream()) { cb(new gutil.PluginError("module-map", "Streaming not supported")); return; } // Get the @providesModule piece out of the file and save that. var contents = file.contents.toString().replace(PM_REGEXP, ""); file.contents = new Buffer(contents); this.push(file); cb(); } return through.obj(transform); };
var basic = { entries: [ './build/node_modules/react/lib/ReactUMDEntry.js', ], outfile: './build/react.js', debug: false, standalone: 'React’, // 全局导出时候的库名称 // Apply as global transform so that we also envify fbjs and any other deps globalTransforms: [envifyDev], plugins: [collapser], after: [derequire, simpleBannerify], // 其他还有一些 after // [wrapperify, minify, bannerify, simpleBannerify] };