author:mucjgm
轉載請註明出處。
版本:cocos2dx 3.10
需求:由於默認的打包方式打出來的game.min.js文件比較大。服務器方面要求我分成幾個文件打包。
研究:
1.首先根據打包命令cocos compile -p web -m release找到打包入口。位於引擎目錄下
cocos2d-x-3.10/tools/cocos2d-console/plugins/plugin_compile/project_compile.py
2.在文件中找到web的打包函數。build_web。
3.發現他是用谷歌的closure-compiler打包的。於是去github查看源碼。https://github.com/google/closure-compiler
4.wiki顯示只支持單文件打包。於是想分成多次compiler。然後在index.html裏面多次加載。
5.找到web的關鍵函數gen_buildxml。位於
cocos2d-x-3.10/tools/cocos2d-console/plugins/plugin_compile/build_web/__init__.py
6.開始修改。我的修改方式是根據根據裏面現成的module生成多個js文件。修改後的gen_buildxml函數代碼如下。
def gen_buildxml(project_dir, project_json, output_dir, build_opts):
# get engine dir (not real)
engineDir = project_json["engineDir"]
# get real engine dir
engine_dir = os.path.normpath(os.path.join(project_dir, engineDir))
# get real publish dir
publish_dir = output_dir
# get tools dir
if getattr(sys, 'frozen', None):
tools_dir = os.path.realpath(os.path.dirname(sys.executable))
else:
tools_dir = os.path.realpath(os.path.dirname(__file__))
# download the binary files
compiler_1_6 = os.path.join(tools_dir, "bin", "compiler-1.6.jar")
compiler_1_7 = os.path.join(tools_dir, "bin", "compiler-1.7.jar")
if not os.path.exists(compiler_1_6) or not os.path.exists(compiler_1_7):
download_cmd_path = os.path.join(tools_dir, os.pardir, os.pardir, os.pardir)
subprocess.call("python %s -f" % (os.path.join(download_cmd_path, "download-bin.py")), shell=True, cwd=download_cmd_path)
try:
f = open(os.path.join(engine_dir, "moduleConfig.json"))
print os.path.join(engine_dir, "moduleConfig.json")
module_cfg = json.load(f)
finally:
f.close()
ccModuleMap = module_cfg["module"]
modules = project_json.get("modules", ["core"])
renderMode = project_json.get("renderMode", 0)
mainJs = project_json.get("main", "main.js")
ccJsList = [module_cfg["bootFile"]]
userJsList = project_json.get("jsList", [])
if renderMode != 1 and "base4webgl" not in modules:
modules[0:0] = ["base4webgl"]
userJsList.append(mainJs)
def inGen(loop, ifUser = False):
xmlname = "build.xml"
if ifUser:
xmlname = "buildUser.xml"
buildXmlTempFile = open(os.path.join(tools_dir, "template", xmlname))
try:
buildContent = buildXmlTempFile.read()
finally:
buildXmlTempFile.close()
jdk_version = check_jdk_version()
sourceMapOpened = build_opts.get("sourceMapOpened")
if jdk_version == JDK_1_6:
sourceMapOpened = False
sourceMapContent = 'sourceMapOutputFile="' + os.path.join(publish_dir, "sourcemap") + '" sourceMapFormat="V3"' if sourceMapOpened else ""
buildContent = buildContent.replace("%projectDir%", project_dir)
buildContent = buildContent.replace("%engineDir%", engine_dir)
buildContent = buildContent.replace("%publishDir%", publish_dir)
buildContent = buildContent.replace("%outputFileName%", build_opts["outputFileName"] % loop)
buildContent = buildContent.replace("%toolsDir%", tools_dir)
buildContent = buildContent.replace("%compiler%", "compiler-%s.jar" % jdk_version)
buildContent = buildContent.replace("%compilationLevel%", build_opts["compilationLevel"])
buildContent = buildContent.replace("%sourceMapCfg%", sourceMapContent)
if ifUser:
buildContent = buildContent.replace("%userJsList%", _getFileArrStr(userJsList))
else:
buildContent = buildContent.replace("%ccJsList%", _getFileArrStr(ccJsList))
buildContent = buildContent.replace("%debug%", build_opts["debug"])
buildXmlOutputFile = open(os.path.join(publish_dir, "build" + str(loop) + ".xml"), "w")
buildXmlOutputFile.write(buildContent)
buildXmlOutputFile.close()
inloop = 1
for item in modules:
print item
arr = _getJsListOfModule(ccModuleMap, item)
if arr != None:
if inloop == 1:
ccJsList += arr
else:
ccJsList = arr
inGen(inloop)
inloop = inloop + 1
inGen(inloop, True)
return inloop
最後返回文件的數量。提供給前面去操作。
7.同時要添加一個新的文件builduser.xml。和修改之前template裏面的build.xml
這是修改後的build.xml
<?xml version="1.0"?>
<project name="Javascript compress project" basedir="%projectDir%" default="compile">
<taskdef name="jscomp" classname="com.google.javascript.jscomp.ant.CompileTask"
classpath="%toolsDir%/bin/%compiler%"/>
<target name="compile">
<jscomp compilationLevel="%compilationLevel%"
warning="quiet"
debug="%debug%"
output="%publishDir%/%outputFileName%"
languagein="ECMASCRIPT5"
%sourceMapCfg%
>
<sources dir="%engineDir%">
%ccJsList%
</sources>
</jscomp>
</target>
</project>
這是後添加的builduser.xml
<?xml version="1.0"?>
<project name="Javascript compress project" basedir="%projectDir%" default="compile">
<taskdef name="jscomp" classname="com.google.javascript.jscomp.ant.CompileTask"
classpath="%toolsDir%/bin/%compiler%"/>
<target name="compile">
<jscomp compilationLevel="%compilationLevel%"
warning="quiet"
debug="%debug%"
output="%publishDir%/%outputFileName%"
languagein="ECMASCRIPT5"
%sourceMapCfg%
>
<sources dir="${basedir}">
%userJsList%
</sources>
</jscomp>
</target>
</project>
文件目錄都位於
cocos2d-x-3.10/tools/cocos2d-console/plugins/plugin_compile/build_web/template/
8.修改project_compile.py裏面的函數。
修改後的build_web函數如下。
def build_web(self):
if not self._platforms.is_web_active():
return
project_dir = self._platforms.project_path()
# store env for run
cfg_obj = self._platforms.get_current_config()
if cfg_obj.run_root_dir is not None:
self.run_root = cfg_obj.run_root_dir
else:
self.run_root = project_dir
if cfg_obj.sub_url is not None:
self.sub_url = cfg_obj.sub_url
else:
self.sub_url = '/'
output_dir = CCPluginCompile.OUTPUT_DIR_SCRIPT_RELEASE
if self._is_debug_mode():
output_dir = CCPluginCompile.OUTPUT_DIR_SCRIPT_DEBUG
if not self._web_advanced:
return
self.sub_url = '%s%s/%s/' % (self.sub_url, output_dir, CCPluginCompile.WEB_PLATFORM_FOLDER_NAME)
f = open(os.path.join(project_dir, "project.json"))
project_json = json.load(f)
f.close()
engine_dir = os.path.join(project_json["engineDir"])
realEngineDir = os.path.normpath(os.path.join(project_dir, engine_dir))
publish_dir = os.path.normpath(os.path.join(project_dir, output_dir, CCPluginCompile.WEB_PLATFORM_FOLDER_NAME))
# need to config in options of command
buildOpt = {
"outputFileName" : "game%d.js",
"debug": "true" if self._is_debug_mode() else "false",
"compilationLevel" : "advanced" if self._web_advanced else "simple",
"sourceMapOpened" : True if self._has_sourcemap else False
}
if os.path.exists(publish_dir):
shutil.rmtree(publish_dir)
os.makedirs(publish_dir)
# generate build.xml
counts = build_web.gen_buildxml(project_dir, project_json, publish_dir, buildOpt)
for x in xrange(1,counts + 1):
outputJsPath = os.path.join(publish_dir, buildOpt["outputFileName"] % x)
if os.path.exists(outputJsPath) == True:
os.remove(outputJsPath)
# call closure compiler
ant_root = cocos.check_environment_variable('ANT_ROOT')
ant_path = os.path.join(ant_root, 'ant')
for x in xrange(1,counts + 1):
self._run_cmd("%s -f %s" % (ant_path, os.path.join(publish_dir, "build%d.xml" % x)))
# handle sourceMap
sourceMapPath = os.path.join(publish_dir, "sourcemap")
if os.path.exists(sourceMapPath):
smFile = open(sourceMapPath)
try:
smContent = smFile.read()
finally:
smFile.close()
dir_to_replace = project_dir
if cocos.os_is_win32():
dir_to_replace = project_dir.replace('\\', '\\\\')
smContent = smContent.replace(dir_to_replace, os.path.relpath(project_dir, publish_dir))
smContent = smContent.replace(realEngineDir, os.path.relpath(realEngineDir, publish_dir))
smContent = smContent.replace('\\\\', '/')
smContent = smContent.replace('\\', '/')
smFile = open(sourceMapPath, "w")
smFile.write(smContent)
smFile.close()
# handle project.json
del project_json["engineDir"]
del project_json["modules"]
del project_json["jsList"]
project_json_output_file = open(os.path.join(publish_dir, "project.json"), "w")
project_json_output_file.write(json.dumps(project_json))
project_json_output_file.close()
# handle index.html
indexHtmlFile = open(os.path.join(project_dir, "index.html"))
try:
#indexContent = indexHtmlFile.read()
linesContent = indexHtmlFile.readlines()
finally:
indexHtmlFile.close()
#reg1 = re.compile(r'<script\s+src\s*=\s*("|\')[^"\']*CCBoot\.js("|\')\s*><\/script>')
#indexContent = reg1.sub("", indexContent)
indexHtmlOutputFile = open(os.path.join(publish_dir, "index.html"), "w")
mainJs = project_json.get("main") or "main.js"
for line in linesContent:
if re.search(r"CCBoot.js", line):
pass
elif re.search(mainJs, line):
for x in range(1, counts + 1):
inline = line.replace(mainJs, buildOpt["outputFileName"] % x)
indexHtmlOutputFile.write(inline)
else:
indexHtmlOutputFile.write(line)
#indexContent = indexContent.replace(mainJs, buildOpt["outputFileName"])
indexHtmlOutputFile.close()
# copy res dir
if cfg_obj.copy_res is None:
dst_dir = os.path.join(publish_dir, 'res')
src_dir = os.path.join(project_dir, 'res')
if os.path.exists(dst_dir):
shutil.rmtree(dst_dir)
shutil.copytree(src_dir, dst_dir)
else:
for cfg in cfg_obj.copy_res:
cocos.copy_files_with_config(cfg, project_dir, publish_dir)
# copy to the output directory if necessary
pub_dir = os.path.normcase(publish_dir)
out_dir = os.path.normcase(os.path.normpath(self._output_dir))
if pub_dir != out_dir:
cpy_cfg = {
"from" : pub_dir,
"to" : out_dir
}
cocos.copy_files_with_config(cpy_cfg, pub_dir, out_dir)
9.修改完畢。編譯。結果顯示正常。這是publish裏面生成的文件。index.html對應加載。
我對html不太瞭解。不知道這樣加載有沒有問題。不過我run了之後是暫時沒發現問題的。
end.