Tôi quyết định thực hiện ljfranklin's advice và hoàn toàn không cần dùng đến RequireJS. Cá nhân tôi nghĩ rằng AMD đang làm tất cả sai, và CommonJS (với hành vi đồng bộ của nó) là con đường để đi; nhưng đó là một cuộc thảo luận khác.
Một điều tôi xem là di chuyển đến Browserify, nhưng trong việc phát triển mỗi biên dịch (vì nó quét tất cả các tệp của bạn và truy tìm các cuộc gọi require()
) mất quá lâu để tôi cho là chấp nhận được.
Cuối cùng, tôi đã triển khai giải pháp riêng biệt của riêng mình. Đó là về cơ bản Trình duyệt, nhưng thay vào đó, nó yêu cầu bạn chỉ định tất cả các phụ thuộc của bạn, thay vì để Browserify tự tìm ra. Nó có nghĩa là biên dịch chỉ là một vài giây thay vì 30 giây.
Đó là TL; DR. Dưới đây, tôi đi vào chi tiết như thế nào tôi đã làm nó. Xin lỗi cho chiều dài. Hy vọng điều này sẽ giúp một ai đó ... hoặc ít nhất là cung cấp cho ai đó một số cảm hứng!
Thứ nhất, tôi có tệp JavaScript của mình. Chúng được viết chung là CommonJS, với giới hạn là exports
không có sẵn dưới dạng biến "chung" (bạn phải sử dụng module.exports
thay thế). ví dụ:
var anotherModule = require('./another-module');
module.exports.foo = function() {
console.log(anotherModule.saySomething());
};
Sau đó, tôi xác định trong trật tự danh sách phụ thuộc trong một tập tin cấu hình (lưu ý js/support.js
, nó tiết kiệm ngày sau):
{
"js": [
"js/support.js",
"js/jquery.js",
"js/jquery-ui.js",
"js/handlebars.js",
// ...
"js/editor/manager.js",
"js/editor.js"
]
}
Sau đó, trong quá trình biên soạn, tôi ánh xạ tất cả các tệp JavaScript của tôi (trong thư mục js/
) vào biểu mẫu;
define('/path/to/js_file.js', function (require, module) {
// The contents of the JavaScript file
});
Đây là hoàn toàn hoàn toàn trong tệp JavaScript gốc; bên dưới, chúng tôi cung cấp tất cả hỗ trợ cho define
, require
và module
v.v., chẳng hạn như, đối với tệp JavaScript ban đầu nó chỉ hoạt động.
Tôi thực hiện ánh xạ bằng cách sử dụng grunt; đầu tiên để sao chép các tập tin vào một thư mục build
(vì vậy tôi không gây rối với bản gốc) và sau đó để viết lại tập tin.
// files were previous in public/js/*, move to build/js/*
grunt.initConfig({
copy: {
dist: {
files: [{
expand: true,
cwd: 'public',
src: '**/*',
dest: 'build/'
}]
}
}
});
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask('buildjs', function() {
var path = require('path');
grunt.file.expand('build/**/*.js').forEach(function (file) {
grunt.file.copy(file, file, {
process: function (contents, folder) {
return 'define(\'' + folder + '\', function (require, module) {\n' + contents + '\n});'
},
noProcess: 'build/js/support.js'
});
});
});
Tôi có một tệp /js/support.js
, xác định hàm define()
tôi bao gồm từng tệp; đây là nơi ma thuật xảy ra, vì nó thêm hỗ trợ cho module.exports
và require()
trong ít hơn 40 dòng!
(function() {
var cache = {};
this.define = function (path, func) {
func(function (module) {
var other = module.split('/');
var curr = path.split('/');
var target;
other.push(other.pop() + '.js');
curr.pop();
while (other.length) {
var next = other.shift();
switch (next) {
case '.':
break;
case '..':
curr.pop();
break;
default:
curr.push(next);
}
}
target = curr.join('/');
if (!cache[target]) {
throw new Error(target + ' required by ' + path + ' before it is defined.');
} else {
return cache[target].exports;
}
}, cache[path] = {
exports: {}
});
};
}.call(this));
Sau đó, trong phát triển, tôi theo nghĩa đen lặp qua mỗi tập tin trong tập tin cấu hình và đầu ra nó như là một <script />
thẻ riêng biệt; mọi thứ đồng bộ, không có gì được rút gọn, mọi thứ nhanh chóng.
{{#iter scripts}}<script src="{{this}}"></script>
{{/iter}}
Điều này mang lại cho tôi;
<script src="js/support.js"></script>
<script src="js/jquery.js"></script>
<script src="js/jquery-ui.js"></script>
<script src="js/handlebars.js"></script>
<!-- ... -->
<script src="js/editor/manager.js"></script>
<script src="js/editor.js"></script>
Trong sản xuất, tôi rút gọn và kết hợp các tệp JS bằng cách sử dụng UglifyJs. Vâng, về mặt kỹ thuật tôi sử dụng một wrapper xung quanh UglifyJs; mini-fier.
grunt.registerTask('compilejs', function() {
var minifier = require('mini-fier').create();
if (config.production) {
var async = this.async();
var files = bundles.js || [];
minifier.js({
srcPath: __dirname + '/build/',
filesIn: files,
destination: __dirname + '/build/js/all.js'
}).on('error', function() {
console.log(arguments);
async(false);
}).on('complete', function() {
async();
});
}
});
... sau đó trong mã ứng dụng, tôi thay đổi scripts
(biến tôi sử dụng để chứa các kịch bản để sản lượng trong giao diện), để chỉ có ['/build/js/all.js']
, chứ không phải là mảng các tập tin thực tế. Điều đó mang lại cho tôi một kết quả
<script src="/js/all.js"></script>
... đầu tiên. Đồng bộ, rút gọn, hợp lý nhanh chóng.
Bạn có thể xem xét việc thêm giọng nói của mình vào chủ đề này mà tôi đã bắt đầu trong danh sách gửi thư. https://groups.google.com/forum/?fromgroups#!topic/requirejs/nT8bPgHf9Vg –