问题
What I'm trying to do is override all AJAX requests, including AJAX proxies, so what I created was an override for Ext.data.Connection. In development mode, this works like a charm, but in a production build, things get a little weird.
The reason why things get weird is because we're doing something that "splits" the build (link here). Meaning, we put all of the framework code into its own file, then have "app.js," which is essentially what we use for booting our application, and "viewport.js," which is the actual application after the booting succeeds. We do this because in "app.js," we have an auth call which makes sure the user is valid, and if they are, then we load "viewport.js."
I think the problem with this is, because we're overriding such a core piece of functionality, it doesn't actually get overridden until app.js loads, which, at that point, Ext.Ajax--a singleton of the overridden class Ext.data.Connection--has already been created, and we lose out on overriding that. It looks like the override is included in app.js, so this assumption would make sense.
I think what needs to happen is that the build.xml needs to include this override in the framework.js file, but I really don't know how to do that... I've never dealt with Ant, so I'm not even sure where I would start. If someone could point me in the right direction, that'd be super helpful. This is what the build.xml looks like right now (see begin custom addition comment for where we added the split code):
<?xml version="1.0" encoding="utf-8"?>
<project name="NewApp" default=".help">
<!-- Find and load Sencha Cmd ant tasks -->
<script language="javascript">
<![CDATA[
var dir = project.getProperty("basedir"),
cmdDir = project.getProperty("cmd.dir"),
cmdLoaded = project.getReference("senchaloader");
if (!cmdLoaded) {
function echo(message, file) {
var e = project.createTask("echo");
e.setMessage(message);
if (file) {
e.setFile(file);
}
e.execute();
};
if (!cmdDir) {
function exec(args) {
var process = java.lang.Runtime.getRuntime().exec(args),
input = new java.io.BufferedReader(new java.io.InputStreamReader(process.getInputStream())),
headerFound = false,
line;
while (line = input.readLine()) {
line = line + '';
java.lang.System.out.println(line);
if (line.indexOf("Sencha Cmd") > -1) {
headerFound = true;
}
else if (headerFound && !cmdDir) {
cmdDir = line;
project.setProperty("cmd.dir", cmdDir);
}
}
process.waitFor();
return !!cmdDir;
}
if (!exec(["sencha", "which"])) {
var tmpFile = "tmp.sh";
echo("source ~/.bash_profile; sencha " + whichArgs.join(" "), tmpFile);
exec(["/bin/sh", tmpFile]);
new java.io.File(tmpFile)['delete']();
}
}
}
if (cmdDir && !project.getTargets().containsKey("init-cmd")) {
var importDir = project.getProperty("build-impl.dir") ||
(cmdDir + "/ant/build/app/build-impl.xml");
var importTask = project.createTask("import");
importTask.setOwningTarget(self.getOwningTarget());
importTask.setLocation(self.getLocation());
importTask.setFile(importDir);
importTask.execute();
}
]]>
</script>
<!--
The following targets can be provided to inject logic before and/or after key steps
of the build process:
The "init-local" target is used to initialize properties that may be personalized
for the local machine.
<target name="-before-init-local"/>
<target name="-after-init-local"/>
The "clean" target is used to clean build output from the build.dir.
<target name="-before-clean"/>
<target name="-after-clean"/>
The general "init" target is used to initialize all other properties, including
those provided by Sencha Cmd.
<target name="-before-init"/>
<target name="-after-init"/>
The "page" target performs the call to Sencha Cmd to build the 'all-classes.js' file.
<target name="-before-page"/>
<target name="-after-page"/>
The "build" target performs the call to Sencha Cmd to build the application.
<target name="-before-build"/>
<target name="-after-build"/>
-->
<!-- BEGIN CUSTOM ADDITION TO BUILD.XML -->
<target name="-after-js">
<!-- The following is derived from the compile-js target in
.sencha/app/js-impl.xml. Compile the viewport and all of its
dependencies into viewport.js. Include in the framework
dependencies in the framework file. -->
<x-compile refid="${compiler.ref.id}">
<![CDATA[
union
-r
-class=${app.name}.view.main.Main
and
save
viewport
and
intersect
-set=viewport,allframework
and
include
-set=frameworkdeps
and
save
frameworkdeps
and
include
-tag=Ext.cmd.derive
and
concat
-remove-text-references=${build.remove.references}
-optimize-string-references=${build.optimize.string.references}
-remove-requirement-nodes=${build.remove.requirement.nodes}
${build.compression}
-out=${build.framework.file}
${build.concat.options}
and
restore
viewport
and
exclude
-set=frameworkdeps
and
exclude
-set=page
and
exclude
-tag=Ext.cmd.derive,derive
and
concat
-remove-text-references=${build.remove.references}
-optimize-string-references=${build.optimize.string.references}
-remove-requirement-nodes=${build.remove.requirement.nodes}
${build.compression}
-out=${build.out.base.path}/${build.id}/viewport.js
${build.concat.options}
]]>
</x-compile>
<!-- Concatenate the file that sets the main view. -->
<concat destfile="${build.out.base.path}/${build.id}/viewport.js" append="true">
<fileset file="classic/viewport.js"/>
</concat>
</target>
<target name="-before-sass">
<!-- The viewport is not explicitly required by the application,
however, its SCSS dependencies need to be included. Unfortunately,
the property required to filter the output, sass.name.filter, is
declared as local and cannot be overridden. Use the development
configuration instead. -->
<property name="build.include.all.scss" value="true"/>
</target>
</project>
To recap, running sencha app watch and loading the page will show the listeners for the Ext.Ajax singleton, but running sencha app build production and loading the page will show no listeners. And no, I do not wish to create my own version of Ext.Ajax or my own data proxy... I realize that's probably the right approach, but there is a lot of code where I'd have to replace that, and that would be a whole lot of regression testing that I currently don't have time for.
回答1:
I think I may've figured it out, but it might be inefficient. What I did was update the Build.xml file to include the page, and changed the output write path for the framework.js file to where app.js is. Then I updated app.json to change the path of where the framework node gets written. Not sure why I'd have to change both places, and I almost feel like it writes framework.js into app.js, and then overwrites it later on... so that might be inefficient, but this does seem to work.
<x-compile refid="${compiler.ref.id}">
<![CDATA[
union
-r
-class=${app.name}.view.main.Main
and
save
viewport
and
intersect
-set=viewport,allframework
and
include
-set=frameworkdeps
and
save
frameworkdeps
and
include
-tag=Ext.cmd.derive
and
// added this
include
-set=page
and
concat
-remove-text-references=${build.remove.references}
-optimize-string-references=${build.optimize.string.references}
-remove-requirement-nodes=${build.remove.requirement.nodes}
${build.compression}
// changed this
-out=${build.classes.file}
${build.concat.options}
and
restore
viewport
and
exclude
-set=frameworkdeps
and
exclude
-set=page
and
exclude
-tag=Ext.cmd.derive,derive
and
concat
-remove-text-references=${build.remove.references}
-optimize-string-references=${build.optimize.string.references}
-remove-requirement-nodes=${build.remove.requirement.nodes}
${build.compression}
-out=${build.out.base.path}/${build.id}/viewport.js
${build.concat.options}
]]>
</x-compile>
Then in the output node in app.json:
"framework": {
// Added this path
"path": "${build.id}/app.js",
"enable": true
}
来源:https://stackoverflow.com/questions/48309545/extjs-override-all-ajax-calls-in-production-build